📄 de4_dev.c
字号:
/******************************************************************************* * * Copyright (c) 2003 Cypress Semiconductor * * * 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; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *//******************************************************************* * * DESCRIPTION: Peripheral Funciton Driver for EZ-HOST Design * Example Four of the development kit. * *******************************************************************//** 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 * +---------------------+---------------+--------------+ * | 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){ 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; } de4_priv->hidrpt.valid = 0; /* 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; } /* 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;}/****************************************************************************** * * DESCRIPTION: not used in DE4 * * 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 */ } 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;}/****************************************************************************** * * DESCRIPTION: Event handler that processes events from the usbd core. * * 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_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_UNKNOWN: case DEVICE_CREATE: case DEVICE_HUB_CONFIGURED: case DEVICE_RESET: case DEVICE_ADDRESS_ASSIGNED: case DEVICE_CONFIGURED: case DEVICE_SET_INTERFACE: case DEVICE_SET_FEATURE: case DEVICE_CLEAR_FEATURE: case DEVICE_DE_CONFIGURED: case DEVICE_BUS_INACTIVE: case DEVICE_BUS_ACTIVITY: case DEVICE_POWER_INTERRUPTION: case DEVICE_HUB_RESET: case DEVICE_DESTROY: case DEVICE_FUNCTION_PRIVATE: break; }}/****************************************************************************** * * 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);}/****************************************************************************** * * 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) { dev_dbg("Valid HID report"); de4_priv->hidrpt.valid = 1; } } } usbd_recycle_urb(recv_urb); ret_value = SUCCESS; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -