📄 osrfx2.c~
字号:
/*****************************************************************************//* osrfx2.c A Driver for the OSR USB FX2 Learning Kit device *//* *//* Copyright (C) 2006 by Robin Callender *//* *//* This program is free software. You can redistribute it and/or *//* modify it under the terms of the GNU General Public License as *//* published by the Free Software Foundation, version 2. *//* *//*****************************************************************************//*****************************************************************************//* modified by Yunxiang Liu *//*****************************************************************************/#include <linux/version.h>//#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/kref.h>#include <linux/poll.h>#include <asm/uaccess.h>#include <linux/usb.h>/*****************************************************************************//* Define the vendor id and product id. *//*****************************************************************************/#define VENDOR_ID 0x0547 #define PRODUCT_ID 0x1002#define DEVICE_MINOR_BASE 192#define CYPRESS_MAX_REQSIZE 8 #undef TRUE#define TRUE (1)#undef FALSE#define FALSE (0)/*****************************************************************************//* Define the vendor commands supported by OSR USB FX2 device. *//*****************************************************************************/#define OSRFX2_SET_XFER_START 0xBE//0xD8 /*****************************************************************************//* Table of devices that work with this driver *//*****************************************************************************/static struct usb_device_id id_table [] = { { USB_DEVICE( VENDOR_ID, PRODUCT_ID ) }, { },};MODULE_DEVICE_TABLE(usb, id_table);/*****************************************************************************//* This is the private device context structure. *//*****************************************************************************/struct osrfx2 { struct usb_device * udev; struct usb_interface * interface; /* * This queue is used by the poll and irq methods */ wait_queue_head_t FieldEventQueue; /* * Transfer Buffers */ //unsigned char * int_in_buffer; unsigned char * bulk_in_buffer; unsigned char * bulk_out_buffer; /* * Buffer sizes */ //size_t int_in_size; size_t bulk_in_size; size_t bulk_out_size; /* * USB Endpoints */ //__u8 int_in_endpointAddr; __u8 bulk_in_endpointAddr; __u8 bulk_out_endpointAddr; /* * Endpoint intervals */ //__u8 int_in_endpointInterval; __u8 bulk_in_endpointInterval; __u8 bulk_out_endpointInterval; /* * URBs */ struct urb * bulk_in_urb; //struct urb * int_in_urb; struct urb * bulk_out_urb; /* * Refrence counter */ struct kref kref; struct semaphore sem; /* * Data from interrupt is retained here. */ //struct switches_state switches; unsigned char notify; /* * Track usage of the bulk pipes: serialize each pipe's use. */ atomic_t bulk_write_available; atomic_t bulk_read_available; /* * Data tracking for Read/Write. * Writes will add to the pending_data count and * reads will deplete the pending_data count. * * Note: The OSRFX2 device specs states that the firmware will buffer * up-to four write packet (two on EP6 and two on EP8). * The buffers can be drained by issuing reads to EP8. * The fifth outstanding write packet attempt will cause the write * to block, waiting for the arrival of a read request to * effectively free a buffer into which the write data can be * held. */ size_t pending_data; /* * Power Managment related fields */ int suspended; /* boolean */}; /*****************************************************************************//* Forward declaration for our usb_driver definition later. *//*****************************************************************************/static struct usb_driver osrfx2_driver;/* Send a vendor command to device */static int vendor_command(struct usb_device *dev, unsigned char request, unsigned char value, unsigned char index, void *buf, int size){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index, buf, size, USB_CTRL_GET_TIMEOUT);}/*****************************************************************************//* This routine will set the bargraph LEDs. *//* *//* Note the two different function defintions depending on kernel version. *//*****************************************************************************/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)static ssize_t set_xfer_start(struct device * dev, const char * buf, size_t count)#elsestatic ssize_t set_xfer_start(struct device * dev, struct device_attribute * attr, const char * buf, size_t count)#endif{ struct usb_interface * intf = to_usb_interface(dev); struct osrfx2 * fx2dev = usb_get_intfdata(intf); //struct bargraph_state * packet; unsigned int value; int retval; char * end; unsigned char *iobuf; value = (simple_strtoul(buf, &end, 10) & 0xFF); if (buf == end) { value = 0; } /* allocate some memory for the i/o buffer*/ iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL);/* retval = usb_control_msg(fx2dev->udev, usb_sndctrlpipe(fx2dev->udev, 0), OSRFX2_SET_BARGRAPH_DISPLAY, USB_DIR_OUT | USB_TYPE_VENDOR, 0, 0, iobuf,//packet, CYPRESS_MAX_REQSIZE,//sizeof(*packet), USB_CTRL_GET_TIMEOUT);*/ retval = vendor_command(fx2dev->udev, OSRFX2_SET_XFER_START, 0, 0, iobuf, CYPRESS_MAX_REQSIZE); if (retval < 0) { dev_err(&fx2dev->udev->dev, "%s - retval=%d\n", __FUNCTION__, retval); } //kfree(packet); kfree(iobuf); return count;}/*****************************************************************************//* This macro creates an attribute under the sysfs directory *//* --- /sys/bus/usb/devices/<root_hub>-<hub>:1.0/bargraph *//* *//* The DEVICE_ATTR() will create "dev_attr_bargraph". *//* "dev_attr_bargraph" is referenced in both probe and disconnect routines. *//*****************************************************************************/static DEVICE_ATTR( start, S_IWUGO, NULL, set_xfer_start );/*****************************************************************************//* *//*****************************************************************************/static int init_bulks(struct osrfx2 * fx2dev){ fx2dev->bulk_in_buffer = kmalloc(fx2dev->bulk_in_size, GFP_KERNEL); if (!fx2dev->bulk_in_buffer) { return -ENOMEM; } fx2dev->bulk_out_buffer = kmalloc(fx2dev->bulk_out_size, GFP_KERNEL); if (!fx2dev->bulk_out_buffer) { return -ENOMEM; } init_MUTEX( &fx2dev->sem ); init_waitqueue_head( &fx2dev->FieldEventQueue ); return 0; }/*****************************************************************************//* This routine will attempt to locate the required endpoints and *//* retain relevant information in the osrfx2 structure instance. *//*****************************************************************************/static int find_endpoints(struct osrfx2 * fx2dev){ struct usb_interface * interface = fx2dev->interface; struct usb_endpoint_descriptor * endpoint; unsigned char dir; unsigned char attr; int i; for (i=0; i < interface->cur_altsetting->desc.bNumEndpoints; i++) { endpoint = &interface->cur_altsetting->endpoint[i].desc; dir = endpoint->bEndpointAddress & USB_DIR_IN; attr = endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; switch ((dir << 8) + attr) { /*case ((USB_DIR_IN << 8) + USB_ENDPOINT_XFER_INT) : fx2dev->int_in_endpointAddr = endpoint->bEndpointAddress; fx2dev->int_in_endpointInterval = endpoint->bInterval; fx2dev->int_in_size = endpoint->wMaxPacketSize; break;*/ case ((USB_DIR_IN << 8) + USB_ENDPOINT_XFER_BULK) : fx2dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; fx2dev->bulk_in_endpointInterval = endpoint->bInterval; fx2dev->bulk_in_size = endpoint->wMaxPacketSize; break; case ((USB_DIR_OUT << 8) + USB_ENDPOINT_XFER_BULK) : fx2dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; fx2dev->bulk_out_endpointInterval = endpoint->bInterval; fx2dev->bulk_out_size = endpoint->wMaxPacketSize; break; default: break; } } if (//fx2dev->int_in_endpointAddr == 0 || fx2dev->bulk_in_endpointAddr == 0 || fx2dev->bulk_out_endpointAddr == 0) { dev_err(&interface->dev, "%s - failed to find required endpoints\n", __FUNCTION__); return -ENODEV; } return 0;}/*****************************************************************************//* *//*****************************************************************************/static void osrfx2_delete(struct kref * kref){ struct osrfx2 * fx2dev = container_of(kref, struct osrfx2, kref); usb_put_dev( fx2dev->udev ); /*if (fx2dev->int_in_urb) { usb_free_urb(fx2dev->int_in_urb); } if (fx2dev->int_in_buffer) { kfree(fx2dev->int_in_buffer); }*/ if (fx2dev->bulk_in_buffer) { kfree( fx2dev->bulk_in_buffer ); } if (fx2dev->bulk_out_buffer) { kfree( fx2dev->bulk_out_buffer ); } kfree( fx2dev );}/*****************************************************************************//* osrfx2_open *//* *//* Note: *//* The serialization method used below has a side-effect which I don't *//* particularly care for. In effect switch_events and bulk I/O are *//* mutually exclusive, e.g. an open for switch_events will exclude *//* opens for bulk I/O (osrbulk) and vis-a-verse. *//* *//* Note: *//* The usb_clear_halt() is being used to effect a pipe reset. *//* This will clear any residual data at the endpoint and ready it for *//* the new endpoint user's data. *//*****************************************************************************/static int osrfx2_open(struct inode * inode, struct file * file){ struct usb_interface * interface; struct osrfx2 * fx2dev; int retval; int flags; interface = usb_find_interface(&osrfx2_driver, iminor(inode)); if (interface == NULL) return -ENODEV; fx2dev = usb_get_intfdata(interface); if (fx2dev == NULL) return -ENODEV; /* * Serialize access to each of the bulk pipes. */ flags = (file->f_flags & O_ACCMODE); if ((flags == O_WRONLY) || (flags == O_RDWR)) { if (atomic_dec_and_test( &fx2dev->bulk_write_available ) == 0) { atomic_inc( &fx2dev->bulk_write_available ); return -EBUSY; } /* * The write interface is serialized, so reset bulk-out pipe (ep-6). */ retval = usb_clear_halt(fx2dev->udev, fx2dev->bulk_out_endpointAddr); if ((retval != 0) && (retval != -EPIPE)) { dev_err(&interface->dev, "%s - error(%d) usb_clear_halt(%02X)\n", __FUNCTION__, retval, fx2dev->bulk_out_endpointAddr); } } if ((flags == O_RDONLY) || (flags == O_RDWR)) { if (atomic_dec_and_test( &fx2dev->bulk_read_available ) == 0) { atomic_inc( &fx2dev->bulk_read_available ); if (flags == O_RDWR) atomic_inc( &fx2dev->bulk_write_available ); return -EBUSY; } /* * The read interface is serialized, so reset bulk-in pipe (ep-8). */ retval = usb_clear_halt(fx2dev->udev, fx2dev->bulk_in_endpointAddr); if ((retval != 0) && (retval != -EPIPE)) { dev_err(&interface->dev, "%s - error(%d) usb_clear_halt(%02X)\n", __FUNCTION__, retval, fx2dev->bulk_in_endpointAddr); } } /* * Set this device as non-seekable. */ retval = nonseekable_open(inode, file); if (retval != 0) { return retval; } /* * Increment our usage count for the device. */ kref_get(&fx2dev->kref); /* * Save pointer to device instance in the file's private structure. */ file->private_data = fx2dev; return 0;}/*****************************************************************************//* *//*****************************************************************************/static int osrfx2_release(struct inode * inode, struct file * file){ struct osrfx2 * fx2dev; int flags; fx2dev = (struct osrfx2 *)file->private_data; if (fx2dev == NULL) return -ENODEV; /* * Release any bulk_[write|read]_available serialization. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -