Driver exposes a character device /dev/pico_rng. Updated driver to support the character device. Tested with dd and cat. I am getting better performance than with Python, no shocker there.

This commit is contained in:
Mickey Malone
2021-02-12 06:55:02 -06:00
parent 396455021a
commit ce9e5deb54

View File

@@ -11,6 +11,7 @@
#include <linux/semaphore.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mickey Malone");
MODULE_DESCRIPTION("Random number generator using a Raspberry Pi Pico");
@@ -21,7 +22,6 @@ MODULE_VERSION("1.0");
**/
#define VENDOR_ID 0x0
#define PRODUCT_ID 0x4
#define SC_MINOR_BASE 31
/**
* Helper macros
@@ -35,6 +35,21 @@ static int debug = 0;
module_param(debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(debug, "Set the log level to debug");
static int timeout = 500;
module_param(timeout, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(timeout, "Set the read timeout for the pico rng usb device");
/**
* The main data structure for this module
**/
struct pico_rng_data {
struct usb_device *dev;
struct usb_interface *interface;
struct usb_endpoint_descriptor *endpoint;
char *buffer;
int pipe;
} module_data;
/**
* Prototype Functions
**/
@@ -43,13 +58,8 @@ static void pico_rng_usb_disconnect(struct usb_interface *interface);
static int __init pico_rng_driver_init(void);
static void __exit pico_rng_driver_exit(void);
/**
static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset);
static int pico_rng_open(struct inode *inode, struct file *file);
static int pico_rng_release(struct inode *inode, struct file *file);
static ssize_t pico_rng_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos);
static ssize_t pico_rng_read(struct file *file, char __user *user, size_t count, loff_t *ppos);
**/
/**
* Data structure of the USB vid:pid device that we will support
@@ -73,13 +83,63 @@ static struct usb_driver pico_rng_usb_driver = {
* File operations data structure for the character device
* that will be implemented in this module
**/
/**static struct file_operations pico_rng_fops = {
static struct file_operations pico_rng_fops = {
.owner = THIS_MODULE,
.open = pico_rng_open,
.read = pico_rng_read,
.release = pico_rng_release,
.open = pico_rng_open,
};
**/
/**
* USB class data structure
**/
struct usb_class_driver pico_rng_usb_class = {
.name = "pico_rng",
.fops = &pico_rng_fops,
};
/**
* File ops:open
**/
static int pico_rng_open(struct inode *inode, struct file *file)
{
LOGGER_DEBUG("inside pico_rng_open with inode %p file %p\n", inode, file);
return 0;
}
/**
* File ops:read
**/
static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset)
{
int actual_length = 0;
int retval = 0;
LOGGER_DEBUG("inside pico_rng_read with file %p, user_buffer %p, size %ld, offset %lld\n", file, user_buffer, size, *offset);
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
LOGGER_DEBUG("Calling usb_bulk_msg dev %p, pipe %d, buffer %p, size %d, and timeout %d", \
module_data.dev, module_data.pipe, module_data.buffer, module_data.endpoint->wMaxPacketSize, timeout);
retval = usb_bulk_msg(module_data.dev,
module_data.pipe,
module_data.buffer,
module_data.endpoint->wMaxPacketSize,
&actual_length,
timeout);
if(retval)
{
return -EFAULT;
}
LOGGER_DEBUG("Copying %d bytest of random data to userspace with offset %lld\n", actual_length, *offset);
if(copy_to_user(user_buffer, module_data.buffer, module_data.endpoint->wMaxPacketSize))
{
return -EFAULT;
}
return module_data.endpoint->wMaxPacketSize;
}
/**
* USB: Probe
@@ -87,45 +147,50 @@ static struct usb_driver pico_rng_usb_driver = {
**/
static int pico_rng_usb_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(interface);
struct usb_endpoint_descriptor *endpoint = NULL;
int retval = -ENODEV;
char *buffer;
int actual_length;
int pipe = 0;
int retval = -ENODEV;
retval = usb_find_bulk_in_endpoint(interface->cur_altsetting, &endpoint);
module_data.dev = interface_to_usbdev(interface);
if(!module_data.dev)
{
LOGGER_ERR("Unable to locate usb device");
return retval;
}
module_data.interface = interface;
if(!module_data.interface)
{
LOGGER_ERR("Invalid interface");
return retval;
}
retval = usb_find_bulk_in_endpoint(module_data.interface->cur_altsetting, &(module_data.endpoint));
if(retval)
{
LOGGER_ERR("Unable to find bulk endpoint %d\n", retval);
return(retval);
}
pipe = usb_rcvbulkpipe(dev, endpoint->bEndpointAddress);
module_data.pipe = usb_rcvbulkpipe(module_data.dev, module_data.endpoint->bEndpointAddress);
LOGGER_DEBUG("endpoint found %p with pipe %d", endpoint, pipe);
LOGGER_DEBUG("endpoint found %p with pipe %d", module_data.endpoint, module_data.pipe);
buffer = kmalloc(endpoint->wMaxPacketSize, GFP_KERNEL);
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
retval = usb_bulk_msg (dev,
pipe,
buffer,
64,
&actual_length,
5000);
/* if the read was successful, copy the data to user space */
if (!retval)
module_data.buffer = NULL;
module_data.buffer = kmalloc(module_data.endpoint->wMaxPacketSize, GFP_KERNEL);
if(!module_data.buffer)
{
LOGGER_INFO("%s\n", buffer);
}
else
{
LOGGER_INFO("usb_bulk_msg raised an error %d\n", retval);
LOGGER_ERR("failed to allocate buffer");
return -1;
}
kfree(buffer);
retval = usb_register_dev(module_data.interface, &pico_rng_usb_class);
if(retval)
{
LOGGER_ERR("not able to get a minor for this device\n");
return -1;
}
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
//retval = usb_bulk_msg(dev, pipe, buffer, 64, &actual_length, 500);
return retval;
}
@@ -137,9 +202,14 @@ static int pico_rng_usb_probe(struct usb_interface *interface, const struct usb_
static void pico_rng_usb_disconnect(struct usb_interface *interface)
{
LOGGER_INFO("pico rng usb device disconnected\n");
usb_deregister_dev(module_data.interface, &pico_rng_usb_class);
module_data.dev = NULL;
module_data.interface = NULL;
module_data.pipe = 0;
kfree(module_data.buffer);
module_data.buffer = NULL;
}
static int __init pico_rng_driver_init(void)
{
int retval = 0;
@@ -156,12 +226,18 @@ static int __init pico_rng_driver_init(void)
LOGGER_INFO("pico rng driver registered successfully\n");
}
return retval;
return 0;
}
static void __exit pico_rng_driver_exit(void)
{
usb_deregister(&pico_rng_usb_driver);
if(module_data.buffer)
{
kfree(module_data.buffer);
}
return;
}