Hi,
Using the usb-skeleton driver, I can successfully read from my own USB
device in user mode. I have added a function with the name
'fpga_update_read_buffer' to the driver to read from the device in
kernel mode using the 'usb_bulk_msg' commad (the code is somehow the
same as skel_read). I can call the function and get the data from the
device when I call it in the module_init. But whenever I use the
function in a thread I receive a  Kernel Panic. Could  anyone solve the
problem? My code is attached to the email.




#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/config.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <pthread.h>
#include "fpga-usb.h"

/* Version Information */
#define DRIVER_VERSION "v0.4"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, [EMAIL PROTECTED]"
#define DRIVER_DESC "USB Skeleton Driver"

/* Define these values to match your device */
#define USB_SKEL_VENDOR_ID      0x045E//0xfff0
#define USB_SKEL_PRODUCT_ID     0x930A//0xfff0

/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
        { }                                     /* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, skel_table);



/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE     192     

/* we can have up to this number of device plugged in at once */
#define MAX_DEVICES             16

pthread_t thread;
static short fpga_count = 0;
struct usb_fpga_device *fpga_dev = NULL;
short *fpga_write_buffer;
short *fpga_read_buffer;
pthread_mutex_t fpga_write_buffer_mutex;


EXPORT_SYMBOL_NOVERS( fpga_write_buffer );
EXPORT_SYMBOL_NOVERS( fpga_read_buffer );
EXPORT_SYMBOL_NOVERS( fpga_dev );
EXPORT_SYMBOL_NOVERS( fpga_write_buffer_mutex );

/* the global usb devfs handle */
extern devfs_handle_t usb_devfs_handle;


/* local function prototypes */
static ssize_t skel_read        (struct file *file, char *buffer, size_t count, 
loff_t *ppos);
static ssize_t skel_write       (struct file *file, const char *buffer, size_t 
count, loff_t *ppos);
static int skel_open            (struct inode *inode, struct file *file);
static int skel_release         (struct inode *inode, struct file *file);

static void * skel_probe        (struct usb_device *dev, unsigned int ifnum, 
const struct usb_device_id *id);
static void skel_disconnect     (struct usb_device *dev, void *ptr);

static void skel_write_bulk_callback    (struct urb *urb);
static void skel_read_bulk_callback             (struct urb *urb);


/* array of pointers to our devices that are currently connected */
static struct usb_fpga_device *minor_table[MAX_DEVICES];

/* lock to protect the minor_table structure */
static DECLARE_MUTEX (minor_table_mutex);

static struct file_operations skel_fops = {
owner:          THIS_MODULE,

read:           skel_read,
write:          skel_write,
open:           skel_open,
release:        skel_release,
};      

static struct usb_driver skel_driver = {
name:           "FPGA Card",
probe:          skel_probe,
disconnect:     skel_disconnect,
fops:           &skel_fops,
minor:          USB_SKEL_MINOR_BASE,
id_table:       skel_table,
};

static inline void skel_delete ( struct usb_fpga_device *dev )
{
        minor_table[dev->minor] = NULL;
        if (dev->bulk_in_buffer != NULL)
                kfree (dev->bulk_in_buffer);
        if (dev->bulk_out_buffer != NULL)
                kfree (dev->bulk_out_buffer);
        if (dev->write_urb != NULL)
                usb_free_urb (dev->write_urb);
        kfree (dev);
}

static int skel_open (struct inode *inode, struct file *file)
{
        struct usb_fpga_device *dev = NULL;
        int subminor;
        int retval = 0;

        subminor = MINOR (inode->i_rdev) - USB_SKEL_MINOR_BASE;
        if ((subminor < 0) ||
                (subminor >= MAX_DEVICES)) {
                        return -ENODEV;
                }

                MOD_INC_USE_COUNT;

                down (&minor_table_mutex);
                dev = minor_table[subminor];
                if (dev == NULL) {
                        up (&minor_table_mutex);
                        MOD_DEC_USE_COUNT;
                        return -ENODEV;
                }

                down (&dev->sem);
                up (&minor_table_mutex);

                ++dev->open_count;

                file->private_data = dev;

                up (&dev->sem);

                return retval;
}


static int skel_release (struct inode *inode, struct file *file)
{
        struct usb_fpga_device *dev;
        int retval = 0;

        dev = (struct usb_fpga_device *) file->private_data;
        if (dev == NULL) {
                return -ENODEV;
        }

        down (&minor_table_mutex);
        down (&dev->sem);

        if (dev->open_count <= 0) {
                retval = -ENODEV;
                goto exit_not_opened;
        }

        if (dev->udev == NULL) {
                /* the device was unplugged before the file was released */
                up (&dev->sem);
                skel_delete (dev);
                up (&minor_table_mutex);
                MOD_DEC_USE_COUNT;
                return 0;
        }

        /* decrement our usage count for the device */
        --dev->open_count;
        if (dev->open_count <= 0) {
                /* shutdown any bulk writes that might be going on */
                usb_unlink_urb (dev->write_urb);
                dev->open_count = 0;
        }

        /* decrement our usage count for the module */
        MOD_DEC_USE_COUNT;

exit_not_opened:
        up (&dev->sem);
        up (&minor_table_mutex);

        return retval;
}


static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t 
*ppos)
{
        struct usb_fpga_device *dev;
        int retval = 0;

        dev = (struct usb_fpga_device *)file->private_data;

        down (&dev->sem);

        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                up (&dev->sem);
                return -ENODEV;
        }

        /* do an immediate bulk read to get data from the device */
        retval = usb_bulk_msg (dev->udev,
                usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
                dev->bulk_in_buffer, dev->bulk_in_size,
                &count, HZ*10);

        /* if the read was successful, copy the data to userspace */
        if (!retval) {
                if (copy_to_user (buffer, dev->bulk_in_buffer, count))
                        retval = -EFAULT;
                else
                        retval = count;
        }

        /* unlock the device */
        up (&dev->sem);

        return retval;
}


static ssize_t skel_write (struct file *file, const char *buffer, size_t count, 
loff_t *ppos)
{
        struct usb_fpga_device *dev;
        ssize_t bytes_written = 0;
        int retval = 0;

        printk( "USB device wrote.\n" );

        dev = (struct usb_fpga_device *)file->private_data;

        down (&dev->sem);

        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                retval = -ENODEV;
                goto exit;
        }

        /* verify that we actually have some data to write */
        if (count == 0) {
                goto exit;
        }

        /* see if we are already in the middle of a write */
        if (dev->write_urb->status == -EINPROGRESS) {
                goto exit;
        }

        /* we can only write as much as 1 urb will hold */
        bytes_written = (count > dev->bulk_out_size) ? 
                dev->bulk_out_size : count;

        /* copy the data from userspace into our urb */
        if (copy_from_user(dev->write_urb->transfer_buffer, buffer, 
                bytes_written)) {
                        retval = -EFAULT;
                        goto exit;
                }

                //      usb_skel_debug_data (__FUNCTION__, bytes_written, 
dev->write_urb->transfer_buffer);

                /* set up our urb */
                FILL_BULK_URB(dev->write_urb, dev->udev, 
                        usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
                        dev->write_urb->transfer_buffer, bytes_written,
                        skel_write_bulk_callback, dev);

                /* send the data out the bulk port */
                retval = usb_submit_urb(dev->write_urb);
                if (retval) {
                        err(__FUNCTION__ " - failed submitting write urb, error 
%d",
                                retval);
                } else {
                        retval = bytes_written;
                }

exit:
                /* unlock the device */
                up (&dev->sem);

                return retval;
}



static void skel_write_bulk_callback (struct urb *urb)
{
        return;
}

static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const 
struct usb_device_id *id)
{
        struct usb_fpga_device *dev = NULL;
        struct usb_interface *interface;
        struct usb_interface_descriptor *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
        int minor;
        int buffer_size;
        int i;
        char name[10];

        /* See if the device offered us matches what we can accept */
        if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
                (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
                        return NULL;
                }

                /* select a "subminor" number (part of a minor number) */
                down (&minor_table_mutex);
                for (minor = 0; minor < MAX_DEVICES; ++minor) {
                        if (minor_table[minor] == NULL)
                                break;
                }
                if (minor >= MAX_DEVICES) {
                        info ("Too many devices plugged in, can not handle this 
device.");
                        goto exit;
                }

                if( fpga_count > 0 )
                {
                        info( "This driver support only one FPGA card to be 
available in the system." );
                        goto exit;
                }
                fpga_count++;

                /* allocate memory for our device state and intialize it */
                dev = kmalloc (sizeof(struct usb_fpga_device), GFP_KERNEL);

                if (dev == NULL) {
                        err ("Out of memory");
                        goto exit;
                }
                fpga_dev = dev;

                memset (dev, 0x00, sizeof (*dev));
                minor_table[minor] = dev;

                interface = &udev->actconfig->interface[ifnum];

                init_MUTEX (&dev->sem);
                dev->udev = udev;
                dev->interface = interface;
                dev->minor = minor;

                /* set up the endpoint information */
                /* check out the endpoints */
                iface_desc = &interface->altsetting[0];
                
                char read_endpoint_found = 0;
                char write_endpoint_found = 0;

                for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
                  //for (i = iface_desc->bNumEndpoints-1; i >= 0; --i) {
                        endpoint = &iface_desc->endpoint[i];

                        if ((endpoint->bEndpointAddress & 0x80) &&
                                ((endpoint->bmAttributes & 3) == 0x02)) {
                                        /* we found a bulk in endpoint */
                                        buffer_size = endpoint->wMaxPacketSize;
                                        dev->bulk_in_size = buffer_size;
                                        dev->bulk_in_endpointAddr = 
endpoint->bEndpointAddress;
                                        dev->bulk_in_buffer = kmalloc 
(buffer_size, GFP_KERNEL);
                                        if (!dev->bulk_in_buffer) {
                                                err("Couldn't allocate 
bulk_in_buffer");
                                                goto error;
                                        }

                                        if( write_endpoint_found )
                                          break;
                                }

                                if (((endpoint->bEndpointAddress & 0x80) == 
0x00) &&
                                        ((endpoint->bmAttributes & 3) == 0x02)) 
{
                                                /* we found a bulk out endpoint 
*/
                                                dev->write_urb = 
usb_alloc_urb(0);
                                                if (!dev->write_urb) {
                                                        err("No free urbs 
available");
                                                        goto error;
                                                }
                                                buffer_size = 
endpoint->wMaxPacketSize;
                                                dev->bulk_out_size = 
buffer_size;
                                                dev->bulk_out_endpointAddr = 
endpoint->bEndpointAddress;
                                                dev->bulk_out_buffer = kmalloc 
(buffer_size, GFP_KERNEL);
                                                if (!dev->bulk_out_buffer) {
                                                        err("Couldn't allocate 
bulk_out_buffer");
                                                        goto error;
                                                }
                                                FILL_BULK_URB(dev->write_urb, 
udev, 
                                                        usb_sndbulkpipe(udev, 
                                                        
endpoint->bEndpointAddress),
                                                        dev->bulk_out_buffer, 
buffer_size,
                                                        
skel_write_bulk_callback, dev);

                                        if( read_endpoint_found )
                                          break;

                                        }
                }

                /* initialize the devfs node for this device and register it */
                sprintf(name, "skel%d", dev->minor);

                dev->devfs = devfs_register (usb_devfs_handle, name,
                        DEVFS_FL_DEFAULT, USB_MAJOR,
                        USB_SKEL_MINOR_BASE + dev->minor,
                        S_IFCHR | S_IRUSR | S_IWUSR | 
                        S_IRGRP | S_IWGRP | S_IROTH, 
                        &skel_fops, NULL);

                fpga_write_buffer = dev->write_urb->transfer_buffer;
                fpga_read_buffer = dev->bulk_in_buffer;

                /* let the user know what node this device is now attached to */
                info ("USB Skeleton device now attached to USBSkel%d", 
dev->minor);
                goto exit;

error:
                skel_delete (dev);
                dev = NULL;

exit:
                up (&minor_table_mutex);
                return dev;
}


static void skel_disconnect(struct usb_device *udev, void *ptr)
{
        struct usb_fpga_device *dev;
        int minor;

        dev = (struct usb_fpga_device *)ptr;

        down (&minor_table_mutex);
        down (&dev->sem);

        minor = dev->minor;

        /* remove our devfs node */
        devfs_unregister(dev->devfs);

        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
                up (&dev->sem);
                skel_delete (dev);
        } else {
                dev->udev = NULL;
                up (&dev->sem);
        }

        fpga_dev = NULL;
        fpga_count = 0;

        info("USB Skeleton #%d now disconnected", minor);
        up (&minor_table_mutex);
}


ssize_t fpga_flush_write_buffer()
{
        struct usb_fpga_device *dev;
        ssize_t bytes_written = 0;
        int retval = 0;

        dev = fpga_dev;         

        if( dev == NULL )
        {
                retval = -ENODEV;
                goto exit;
        }

        /* lock this object */
        down (&dev->sem);

        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) 
        {
                retval = -ENODEV;
                goto exit;
        }

        /* see if we are already in the middle of a write */
        if (dev->write_urb->status == -EINPROGRESS) 
                goto exit;

        /* we can only write as much as 1 urb will hold */
        bytes_written = dev->bulk_out_size;

        //      usb_skel_debug_data (__FUNCTION__, bytes_written, 
dev->write_urb->transfer_buffer);

        /* set up our urb */
        FILL_BULK_URB(dev->write_urb, dev->udev, 
                usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
                dev->write_urb->transfer_buffer, bytes_written,
                skel_write_bulk_callback, dev);

        /* send the data out the bulk port */
        retval = usb_submit_urb(dev->write_urb);
        if (retval) {
                err(__FUNCTION__ " - failed submitting write urb, error %d",
                        retval);
        } else {
                retval = bytes_written;
        }

exit:
        /* unlock the device */
        up (&dev->sem);

        return retval;
}
EXPORT_SYMBOL_NOVERS( fpga_flush_write_buffer );


static void fpga_update_read_buffer()
{
        struct usb_fpga_device *dev;
        int count = 64;
        int bytes_read;

        dev = fpga_dev;

        rtl_printf( "Flag 0.5\n" );

        if( dev == NULL )
                return;

        rtl_printf( "Flag 01\n" );

        down ( &dev->sem );

        rtl_printf( "Flag 02\n" );
        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) 
        {
                up (&dev->sem);
                return;
        }

        rtl_printf( "Flag 03\n" );

        rtl_printf( "Flag 04\n" );
        /* do an immediate bulk read to get data from the device */
        usb_bulk_msg( dev->udev,
                usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
                dev->bulk_in_buffer, dev->bulk_in_size,
                &count, HZ*10 );
        rtl_printf( "Flag 05\n" );

        up ( &dev->sem );
}


void * fpga_write_thread_routine(void *arg)
{
        struct sched_param p;
        p . sched_priority = 1;
        pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);

        while (1) 
        {
                fpga_flush_write_buffer();
                fpga_update_read_buffer();
                pthread_mutex_lock( &fpga_write_buffer_mutex );
        }

        return 0;
}


static int __init usb_skel_init(void)
{
        int result;

        result = usb_register(&skel_driver);
        if (result < 0) 
        {
                err("usb_register failed for the "__FILE__" driver. Error 
number %d", result);
                return -1;
        }

        info(DRIVER_DESC " " DRIVER_VERSION);

        pthread_mutex_init( &fpga_write_buffer_mutex, NULL );
        pthread_mutex_lock( &fpga_write_buffer_mutex );

        rtl_printf( "Flag 00\n" );
        fpga_flush_write_buffer();
        fpga_update_read_buffer();
        rtl_printf( "Flag 10" );
        return pthread_create (&thread, NULL, fpga_write_thread_routine, 0);  
//The problem goes here
        return 0;
}


static void __exit usb_skel_exit(void)
{
        pthread_delete_np (thread);
        pthread_mutex_destroy( &fpga_write_buffer_mutex );

        usb_deregister(&skel_driver);
}


module_init (usb_skel_init);
module_exit (usb_skel_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");


Reply via email to