📄 de1_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 driver for EZ-HOST Design Example * One of the development kit. This example is * for an USB OTG driver. *******************************************************************//** 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 "de1_dev.h"/** local definitions **/struct de1_priv { int major_number; struct usb_device_instance * device; struct urb_link bulk_out_rcv; struct urb_link int_out_rcv; struct urb_link bulk_in_tx; struct urb_link int_in_tx; int open_count; struct semaphore sem;};static struct de1_priv * de1_priv = NULL;extern int dbgflg_usbdfd_usbe;#define dbg_usbe(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_usbe,lvl,fmt,##args)/* function prototypes */static void de1_event(struct usb_device_instance *, usb_device_event_t, int);static int de1_urb_sent(struct usbd_urb *, int);static int de1_recv_urb(struct usbd_urb *);static void de1_function_init(struct usb_bus_instance *, struct usb_device_instance *, struct usb_function_driver *);static void de1_function_exit(struct usb_device_instance *);static ssize_t de1_read(struct file *, char *, size_t, loff_t *);static ssize_t ep_read(struct de1_priv *, char *, size_t, int);static ssize_t de1_write(struct file *, const char *, size_t, loff_t *);static ssize_t ep_write(struct de1_priv *, const char *, size_t, int);static int de1_open(struct inode *, struct file *);static int de1_release(struct inode *, struct file *);static int de1_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static void de1_recycle_urb(struct usbd_urb *urb, struct urb_link *link);/******************************************************************************* FUNCTION CONFIGURATION DESCRIPTORS */struct usb_otg_description de1_otg_description = { bmAttributes : BMATTRIBUTE_HNP_SUPPORT | BMATTRIBUTE_SRP_SUPPORT}; struct usb_endpoint_description de1_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 : INT_IN_EP, bmAttributes : INTERRUPT, wMaxPacketSize : 64, bInterval : 100, // polling interval, from 1 to 255 direction : IN, transferSize : 64 }, { bEndpointAddress : INT_OUT_EP, bmAttributes : INTERRUPT, wMaxPacketSize : 64, bInterval : 100, // polling interval, from 1 to 255 direction : OUT, transferSize : 64 } };struct usb_alternate_description de1_alternate_description = { iInterface : 0, bAlternateSetting : 0, classes : 0, class_list : NULL, endpoints : sizeof(de1_endpoint_description) / sizeof(struct usb_endpoint_description), endpoint_list : de1_endpoint_description, otg_description : &de1_otg_description};struct usb_interface_description de1_interface_description = { bInterfaceClass : 0, bInterfaceSubClass : 0, bInterfaceProtocol : 0, iInterface : 0, alternates : sizeof(de1_alternate_description) / sizeof(struct usb_alternate_description), alternate_list : &de1_alternate_description};struct usb_configuration_description de1_configuration_description = { iConfiguration : 0, bmAttributes : BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED, bMaxPower : 0, interfaces : sizeof(de1_interface_description) / sizeof(struct usb_interface_description), interface_list : &de1_interface_description};struct usb_device_description de1_device_description = { bDeviceClass : DVK1_DEVICE_CLASS, bDeviceSubClass : DVK1_DEVICE_SUBCLASS, bDeviceProtocol : DVK1_DEVICE_PROTOCOL, idVendor : DVK1_VENDOR_ID, idProduct : DVK1_PRODUCT_ID, iManufacturer : DVK1_MANUFACTURER_STR, iProduct : DVK1_PRODUCT_STR, iSerialNumber : DVK1_SERIAL_NUMBER_STR};/*****************************************************************************/struct usb_function_operations de1_function_ops = { event : de1_event, urb_sent : de1_urb_sent, recv_urb : de1_recv_urb, recv_setup : 0, function_init : de1_function_init, function_exit : de1_function_exit,};struct usb_function_driver de1_function_driver = { name : "DVK1_function_driver", ops : &de1_function_ops, device_description : &de1_device_description, configurations : sizeof(de1_configuration_description) / sizeof(struct usb_configuration_description), configuration_description : &de1_configuration_description, this_module : THIS_MODULE,};struct file_operations de1_file_ops = { owner : THIS_MODULE, read : de1_read, write : de1_write, open : de1_open, release : de1_release, ioctl : de1_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 de1_function_init(struct usb_bus_instance * bus, struct usb_device_instance * device, struct usb_function_driver * func_driver){ cy_dbg("de1_function_init enter"); de1_priv = kmalloc( sizeof(struct de1_priv), GFP_KERNEL); if(de1_priv == NULL) { cy_err("de1_priv memory allocation failed."); return; } /* Register device driver */ de1_priv->major_number = register_chrdev( 0, DE1_DEVICE_NAME, &de1_file_ops ); if( de1_priv->major_number == 0 ) { cy_err("register_chrdev() failed."); kfree(de1_priv); de1_priv = NULL; return; } /* save off the usb_device_instance pointer */ de1_priv->device = device; de1_priv->open_count = 0; /* initialize the semaphore, (kernel) */ sema_init(&de1_priv->sem, 1); /* save our private data into the usb_function_instance private pointer */ device->function_instance_array->privdata = de1_priv;}/****************************************************************************** * PARAMETERS: device -> pointer to usb_device_instance * * DESCRIPTION: Not used for DE1 * * RETURNS: * */void de1_function_exit(struct usb_device_instance * device){ int i; cy_dbg("de1_function_exit enter"); /* deallocate URB's for each endpoint */ for(i = 0; i < TOTAL_ENDPOINTS; i++) { /* free up URB buffers */ } unregister_chrdev( de1_priv->major_number, DE1_DEVICE_NAME ); /* deallocate the function private structure */ kfree(de1_priv); de1_priv = NULL; /* set the usb_function_instance privdata pointer to null */ device->function_instance_array->privdata = NULL;}/****************************************************************************** * PARAMETERS: device -> pointer to usb_device_instance * event -> device event to handle * data -> event data * * DESCRIPTION: Handle an event from the usbd core. * * RETURNS: * */void de1_event(struct usb_device_instance * device, usb_device_event_t event, int data){ //extern char *usbd_device_events[]; cy_dbg("de1_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(&de1_priv->bulk_out_rcv); urb_link_init(&de1_priv->int_out_rcv); urb_link_init(&de1_priv->bulk_in_tx); urb_link_init(&de1_priv->int_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); de1_recycle_urb(urb, &de1_priv->bulk_in_tx); } /* allocate int send urbs */ urb = usbd_alloc_urb(device, device->function_instance_array, INT_IN_EP, INT_IN_BUFF_SZ); de1_recycle_urb(urb, &de1_priv->int_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; }}/****************************************************************************** * PARAMETERS: sent_urb -> pointer to the URB that was sent * data -> unused value * * DESCRIPTION: Callback to notify function that a URB has been transmitted * on the bus. * * RETURNS: Zero for SUCCESS, negative for ERROR. * */static int de1_urb_sent(struct usbd_urb * sent_urb, int data){ int return_value = ERROR; cy_dbg("de1_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: de1_recycle_urb(sent_urb, &de1_priv->bulk_in_tx); return_value = SUCCESS; break; case INT_IN_EP: de1_recycle_urb(sent_urb, &de1_priv->int_in_tx); return_value = SUCCESS; break; default: cy_warn("ERROR didn't recycle urb"); break; } break; default: cy_err("ERROR de1_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 de1_recv_urb(struct usbd_urb * recv_urb){ int port = 0; struct usb_device_instance *device = recv_urb->device; struct de1_priv * priv = (device->function_instance_array+port)->privdata; int ret_value = -EINVAL; cy_dbg("de1_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: 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; /* save off the pointer to this URB, it will be read by * the application through an IOCTL call, which will then * recycle the URB */ case INT_OUT_EP: urb_append_irq(&priv->int_out_rcv, recv_urb); cy_dbg("int urb received"); /* the ioctl() function will recycle the URB after the * application retrieves the data, so we are done */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -