de4_dev.c
来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 988 行 · 第 1/2 页
C
988 行
/******************************************************************* * * DESCRIPTION: Peripheral Funciton Driver for Lyberty Design * Example Four of the development kit. * * AUTHOR: GXJ@CYPRESS.COM * * HISTORY: * *******************************************************************//** include files **///#define MODULE#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/ctype.h>#include <linux/string.h>#include <linux/fs.h>#include <linux/compatmac.h>#include <linux/slab.h>#include <asm/semaphore.h>#include <asm/ioctls.h>#include "../usbd.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-debug.h"#include "../usbd-inline.h"#include "../usbd-arch.h"#include "../usbd-export.h"#include "../usbd-build.h"#include "../../cy7c67200_300_common.h"#include "../../cy7c67200_300_debug.h"#include "de4_dev.h"static int dev_dbg_on = 0;#define dev_dbg(format, arg...) \ if( dev_dbg_on != 0 ) \ printk(KERN_DEBUG __FILE__ ":" "%d: " format "\n" ,__LINE__, ## arg)/** local definitions **/struct de4_priv { int major_number; struct usb_device_instance * device; struct urb_link bulk_out_rcv; struct urb_link bulk_in_tx; hid_keyboard_report_t hidrpt; int open_count; struct semaphore sem;};static struct de4_priv * de4_priv = NULL;extern int dbgflg_usbdfd_usbe;#define dbg_usbe(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_usbe,lvl,fmt,##args)/* function prototypes */static void de4_event(struct usb_device_instance *, usb_device_event_t, int);static int de4_urb_sent(struct usbd_urb *, int);static int de4_recv_urb(struct usbd_urb *);static void de4_function_init(struct usb_bus_instance *, struct usb_device_instance *, struct usb_function_driver *);static void de4_function_exit(struct usb_device_instance *);static ssize_t de4_read(struct file *, char *, size_t, loff_t *);static ssize_t ep_read(struct de4_priv *, char *, size_t, int);static ssize_t de4_write(struct file *, const char *, size_t, loff_t *);static ssize_t ep_write(struct de4_priv *, const char *, size_t, int);static int de4_open(struct inode *, struct file *);static int de4_release(struct inode *, struct file *);static int de4_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static void de4_recycle_urb(struct usbd_urb *urb, struct urb_link *link);/******************************************************************************* FUNCTION CONFIGURATION DESCRIPTORS *//* Design Example 4 Endpoints * +---------------------+---------------+--------------+ * | Control in | | | * +---------------------+ Endpoint 0 | Control | * | Control out | | | * +---------------------+---------------+--------------+ * | Bulk in | Endpoint 1 | loopback | * +---------------------+ --------------+--------------| * | Bulk out | Endpoint 2 | loopback | * +---------------------+---------------+--------------+ * | Bulk out | Endpoint 3 | report | * +---------------------+---------------+--------------+ */ struct usb_endpoint_description de4_endpoint_description[] = { { bEndpointAddress : BULK_IN_EP, bmAttributes : BULK, wMaxPacketSize : 64, bInterval : 0, direction : IN, transferSize : 1024, }, { bEndpointAddress : BULK_OUT_EP, bmAttributes : BULK, wMaxPacketSize : 64, bInterval : 0, direction : OUT, transferSize : 1024, }, { bEndpointAddress : BULK_OUT2_EP, bmAttributes : BULK, wMaxPacketSize : 64, bInterval : 0, direction : OUT, transferSize : 64, },};struct usb_alternate_description de4_alternate_description = { iInterface : 0, bAlternateSetting : 0, classes : 0, class_list : NULL, endpoints : sizeof(de4_endpoint_description) / sizeof(struct usb_endpoint_description), endpoint_list : de4_endpoint_description, otg_description : 0};struct usb_interface_description de4_interface_description = { bInterfaceClass : 0, bInterfaceSubClass : 0, bInterfaceProtocol : 0, iInterface : 0, alternates : sizeof(de4_alternate_description) / sizeof(struct usb_alternate_description), alternate_list : &de4_alternate_description};struct usb_configuration_description de4_configuration_description = { iConfiguration : 0, bmAttributes : BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED, bMaxPower : 0, interfaces : sizeof(de4_interface_description) / sizeof(struct usb_interface_description), interface_list : &de4_interface_description};struct usb_device_description de4_device_description = { bDeviceClass : DE4_DEVICE_CLASS, bDeviceSubClass : DE4_DEVICE_SUBCLASS, bDeviceProtocol : DE4_DEVICE_PROTOCOL, idVendor : DE4_VENDOR_ID, idProduct : DE4_PRODUCT_ID, iManufacturer : DE4_MANUFACTURER_STR, iProduct : DE4_PRODUCT_STR, iSerialNumber : DE4_SERIAL_NUMBER_STR};/*****************************************************************************/struct usb_function_operations de4_function_ops = { event : de4_event, urb_sent : de4_urb_sent, recv_urb : de4_recv_urb, recv_setup : 0, function_init : de4_function_init, function_exit : de4_function_exit,};struct usb_function_driver de4_function_driver = { name : "DE4_function_driver", ops : &de4_function_ops, device_description : &de4_device_description, configurations : sizeof(de4_configuration_description)/sizeof(struct usb_configuration_description), configuration_description : &de4_configuration_description, this_module : THIS_MODULE,};struct file_operations de4_file_ops = { owner : THIS_MODULE, read : de4_read, write : de4_write, open : de4_open, release : de4_release, ioctl : de4_ioctl,};/****************************************************************************** * PARAMETERS: bus -> pointer to usb_bus_instance * device -> pointer to usb_device_instance * func_driver -> pointer to usb_function_driver * DESCRIPTION: This routine will initialize the function driver's private * data. It is called from the peripheral controller * * RETURNS: * */void de4_function_init(struct usb_bus_instance * bus, struct usb_device_instance * device, struct usb_function_driver * func_driver){ //struct usbd_urb * urb; dev_dbg("de4_function_init enter"); de4_priv = kmalloc( sizeof(struct de4_priv), GFP_KERNEL); if(de4_priv == NULL) { cy_err("de4_priv memory allocation failed."); return; //exit(EXIT_FAILURE); } de4_priv->hidrpt.valid = 0; /* Initialize wait queues for read/write */ //init_waitqueue_head(&de4_priv->inq); //init_waitqueue_head(&de4_priv->outq); /* Register device driver */ de4_priv->major_number = register_chrdev( 0, DE4_DEVICE_NAME, &de4_file_ops ); if( de4_priv->major_number == 0 ) { cy_err("register_chrdev() failed."); kfree(de4_priv); de4_priv = NULL; return; //exit(EXIT_FAILURE); } /* save off the usb_device_instance pointer */ de4_priv->device = device; de4_priv->open_count = 0; /* initialize the semaphore, (kernel) */ sema_init(&de4_priv->sem, 1); /* save our private data into the usb_function_instance private pointer */ device->function_instance_array->privdata = de4_priv;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */void de4_function_exit(struct usb_device_instance * device){ int i; dev_dbg("de4_function_exit enter"); /* deallocate URB's for each endpoint */ for(i = 0; i < TOTAL_ENDPOINTS; i++) { /* free up URB buffers */ // FIXME next line needs to be fixed //kfree(dev->endpoint_data[i].buffer); } unregister_chrdev( de4_priv->major_number, DE4_DEVICE_NAME ); /* deallocate the function private structure */ kfree(de4_priv); de4_priv = NULL; /* set the usb_function_instance privdata pointer to null */ device->function_instance_array->privdata = NULL;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */void de4_event(struct usb_device_instance * device, usb_device_event_t event, int data){ extern char *usbd_device_events[]; dev_dbg("de4_event enter: event: %s, data = %d", usbd_device_events[event], data); switch(event) { case DEVICE_UNKNOWN: break; case DEVICE_INIT: { struct usbd_urb * urb; size_t i; /* initialize URB linked lists */ urb_link_init(&de4_priv->bulk_out_rcv); urb_link_init(&de4_priv->bulk_in_tx); /* allocate bulk send urbs */ for(i=0; i<5; i++) { urb = usbd_alloc_urb(device, device->function_instance_array, BULK_IN_EP, BULK_IN_BUFF_SZ); de4_recycle_urb(urb, &de4_priv->bulk_in_tx); } } break; case DEVICE_CREATE: break; case DEVICE_HUB_CONFIGURED: break; case DEVICE_RESET: break; case DEVICE_ADDRESS_ASSIGNED: break; case DEVICE_CONFIGURED: break; case DEVICE_SET_INTERFACE: break; case DEVICE_SET_FEATURE: break; case DEVICE_CLEAR_FEATURE: break; case DEVICE_DE_CONFIGURED: break; case DEVICE_BUS_INACTIVE: break; case DEVICE_BUS_ACTIVITY: break; case DEVICE_POWER_INTERRUPTION: break; case DEVICE_HUB_RESET: break; case DEVICE_DESTROY: break; case DEVICE_FUNCTION_PRIVATE: break; }}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: Callback to notify function that a URB has been transmitted * on the bus successfully. * * RETURNS: Zero for SUCCESS, negative for ERROR. * */int de4_urb_sent(struct usbd_urb * sent_urb, int data){ int return_value = ERROR; dev_dbg("de4_urb_sent enter"); /* check the status of the completed URB */ switch(sent_urb->status) { case SEND_FINISHED_OK: case SEND_FINISHED_ERROR: switch( sent_urb->endpoint->endpoint_address & 0xf) { case BULK_IN_EP: de4_recycle_urb(sent_urb, &de4_priv->bulk_in_tx); return_value = SUCCESS; break; default: cy_warn("ERROR didn't recycle urb"); break; } break; default: cy_err("ERROR de4_urb_sent: unhandled sent status."); break; } return(return_value);}/****************************************************************************** * PARAMETERS: recv_urb -> a pointer to a URB passed from the peripheral core * layer. * * DESCRIPTION: Called to receive a URB, called in the interrupt context. * This function determines to which endpoint the received URB belongs, and * saves off the pointer to this URB in the function's private data. This * will then be processed in the read() function when called by the * application. The read() function will then recycle the URB. * * In the future, this may just store the data in a buffer and return. Then * the read function would read directly from the buffer. This implementation * would return the URB's immediately to the peripheral controller driver. * Currently, instead of allocating a separate buffer, this function saves * off a pointer to the URB and the read() function handles it directly, * essentially using the URB buffer to store the data, instead of allocating * separate buffer space. * * RETURNS: A negative value for an error condition, and zero for success. * If an error is returned, then the calling function will check this return * value, and recycle the URB, essentially discarding the data. * */int de4_recv_urb(struct usbd_urb * recv_urb){ int port = 0; struct usb_device_instance *device = recv_urb->device; struct de4_priv * priv = (device->function_instance_array+port)->privdata; int ret_value = -EINVAL; dev_dbg("de4_recv_urb enter"); if((recv_urb != NULL) && (recv_urb->status != RECV_ERROR)) { // determine which endpoint received the URB. switch(recv_urb->endpoint->endpoint_address & 0xf) { /* save off the URB pointer for a subsequent read by the * application, this will add the URB to a linked list, it * allows us to receive data faster than the application * may request it */ case BULK_OUT_EP: dev_dbg("de4_recv_urb BULK_OUT"); urb_append_irq(&priv->bulk_out_rcv, recv_urb); /* the read() function will recycle the URB after the * application retrieves the data, so we are done */ ret_value = SUCCESS; break; case BULK_OUT2_EP: dev_dbg("de4_recv_urb BULK_OUT2"); if (de4_priv->hidrpt.valid == 0) { if (recv_urb->actual_length == HID_REPORT_SIZE ) { if( memcpy(de4_priv->hidrpt.report, recv_urb->buffer, HID_REPORT_SIZE) != NULL)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?