📄 dm320.c.svn-base
字号:
/* * linux/drivers/usb/gadget/dm320/dm320.c * Texas Instruments DM320 on-chip full speed USB device controllers * Author : Vishal Borker, November 2005, Ingenient Technologies * Report Bugs/Patches to vishal.borker@gmail.com * * 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 * */#include <linux/config.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/timer.h>#include <linux/usb_ch9.h>#include <linux/usb_gadget.h>#include <linux/dma-mapping.h>#include <asm/arch/gio.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>#include "dm320_reg_def.h"#include "dm320_usb_config.h"#include "dm320_usb.h"#define EP_BULK_IN_NUM 1 // Endpoing on which we send data to the Host controller Tx EP#define EP_BULK_OUT_NUM 2 // Endpoint on which we get data from the Host controller Rx EP#define EP_INTR_IN_NUM 3 // INTR Endpoint on which the hos periodically polls for interrupt data.#define HOST_CONNECT 1#define HOST_DISCONNECT 0/* * We have a set of debug MACROS's each enabling a different level of debug commands. * define all of the below to enable full debug support * */static int paddr_status = 0;#define IO_DEBUG #ifdef IO_DEBUG#define printkio(fmt,args...) \ printk(fmt , ## args)#else#define printkio(fmt,args...) \ do { } while (0)#endif /* DEBUG */#ifdef CORE_DEBUG#define core_debug(fmt,args...) \ printk(fmt , ## args)#else#define core_debug(fmt,args...) \ do { } while (0)#endif /* DEBUG */#ifdef PRINT_INFO#define dm320_info(fmt,args...) \ printk(fmt , ## args)#else#define dm320_info(fmt,args...) \ do { } while (0)#endif /* DEBUG */#define DM320_USB_BASE 0x80000000#define DRIVER_DESC "DM320 USB Peripheral Controller (test version 1.0) "#define DRIVER_VERSION "2005 September 01, Ingenient Technologies "#define DMA_ADDR_INVALID (~(dma_addr_t)0)const char driver_name [] = "dm320";const char driver_desc [] = DRIVER_DESC;const char ep0name [] = "ep0";const char *ep_name [] = { ep0name, "ep1in-bulk", "ep2out-bulk", "ep3in-intr",};#define DEBUG /* messages on error and most fault paths */#define VERBOSE /* extra debug messages (success too) */#include "dm320.h"#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")/* * function prototypes */static int use_dma = 0;static struct usb_ep_ops dm320_ep_ops;static void nuke (struct dm320_ep *);static void usb_reset (struct dm320 *dev);static void usb_reinit (struct dm320 *dev);static void ep_reset (struct dm320_ep *ep);static void dm320_reset_ep(unsigned int index);static void dm320_clear_intrs();static void dm320_reconnect_init(struct dm320 *dev);static int kick_dma (struct dm320_ep *ep, struct dm320_request *req);static int dm320_fifo_status (struct usb_ep *_ep);static void flushEPFIFO( int iEndpoint ) //Vishal: Derived from USB_FlushFifo(i){// printk("dm320 : %s: %d\n", __FUNCTION__, iEndpoint); if( ( iEndpoint < USB_EP0_SELECT ) || ( iEndpoint >= RX_EP_MAX ) ) return ; writeb( iEndpoint, USB_INDEX ); if( iEndpoint == USB_EP0_SELECT ) { writeb( USB_CSR2_FLFIFO, USB_CSR2 ); writeb( USB_CSR2_FLFIFO, USB_CSR2 ); } else { writeb( USB_TXCSR1_FLFIFO, USB_PER_TXCSR1 ); writeb( USB_RXCSR1_FLFIFO, USB_PER_RXCSR1 ); }}static int ep_name_to_index(char *name){ if(!strcmp(name,ep0name)) return 0; if(!strcmp(name,"ep1in-bulk")) return 1; if(!strcmp(name,"ep2out-bulk")) return 2; if(!strcmp(name,"ep3in-intr")) return 3;}static intdm320_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc){ unsigned int ep_num; ep_num = ep_name_to_index(_ep->name); return 0;}static voiddone (struct dm320_ep *ep, struct dm320_request *req, int status){ struct dm320 *dev; unsigned stopped = ep->stopped; if (ep->num == 0) { if (ep->dev->protocol_stall) { ep->stopped = 1; set_halt (ep); } allow_status (ep); } dev = the_controller; if (req->req.status == -EINPROGRESS) req->req.status = status; else status = req->req.status; /* don't modify queue heads during completion callback */// spin_unlock (&dev->lock); req->req.complete (&ep->ep, &req->req); list_del_init (&req->queue); // spin_lock (&dev->lock); ep->stopped = stopped;}/* returns: 0: still running, 1: completed, negative: errno */static int write_fifo (struct dm320_ep *ep, struct dm320_request *req){ u8 *buf; int ret = -1; int count = 0 , max = 0 , total = 0 ; int is_last; int status; int nBytesWritten = 0; while(1) { if(req){ buf = req->req.buf + req->req.actual; prefetch (buf); total = req->req.length - req->req.actual; //printkio("%s: <1> request of size: %d, wrote so far: %d, total left: %d\n", __FUNCTION__,req->req.length,req->req.actual, total); mdelay(1); }else { //printkio("%s: req NULL. Invalid condition. Cannot occur. \n", __FUNCTION__); return 0; } count = ep->ep.maxpacket; if (count > total) /* min() cannot be used on a bitfield */ count = total; if(count <= 0) goto finish; if( ( count = USB_WriteEP(ep_name_to_index(ep->ep.name),buf , total ) ) <= 0 ) { printkio("USB_WriteEP( ) error! : %d\n", count ); return ret; } req->req.actual += count; //printkio("%s: <1> request of size: %d, wrote so far: %d, total left: %d\n", __FUNCTION__,req->req.length,req->req.actual, total); if ((req->req.length == req->req.actual) || count < BULK_TRANS_SIZE) /*Modify to handle control ep's as well */ {finish: //printkio("%s: wrote . Calling Done.\n", __FUNCTION__); done (ep, req, 0); return 0; } } return 0;// return -1;}static int read_fifo (struct dm320_ep *ep, struct dm320_request *req){ u8 *buf; unsigned count, max, total= 0; int is_last; int status; int nBytesWritten = 0; while(1) { //udelay(250); //udelay(5); if(req){ buf = req->req.buf+ req->req.actual; } if( ( count = USB_ReadEP(ep_name_to_index(ep->ep.name),buf , BULK_TRANS_SIZE ) ) <= 0 ) return -1; else req->req.actual += count; if (req->req.length == req->req.actual || count < BULK_TRANS_SIZE ) /*Modify to handle control ep's as well */ { // printk("%s: read . Calling Done.\n", __FUNCTION__); done (ep, req, 0); return 0; } } //return -1; return 0;}/* returns 0 on success, else negative errno */static int kick_dma (struct dm320_ep *ep, struct dm320_request *req){ return -1;}int rx_pending = 0 ;int rx_pending = 0 ;static intdm320_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags){ struct dm320_request *req; struct dm320_ep *ep; struct dm320 *dev; unsigned long flags;// spin_lock_irqsave (&dev->lock, flags); int status = -1; int ep_num; u8 s; ep = container_of (_ep, struct dm320_ep, ep); dev = ep->dev; req = container_of (_req, struct dm320_request, req); if (!_req || !_req->complete || !_req->buf) return -EINVAL; if(!_ep) return -EINVAL; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; _req->status = -EINPROGRESS; _req->actual = 0; spin_lock_irqsave (&dev->lock, flags); local_irq_disable(); //printk("\n\n %s: queued the request of length %d to ep: %s\n", __FUNCTION__,_req->length, ep->ep.name); /* if list is empty */ if(_req->length==0 && (ep->is_in || ep_num == 3) ){ printk("NULL PACKET SENDING\n"); writeb( readb( USB_PER_TXCSR1 ) | USB_TXCSR1_TXPKTRDY, USB_PER_TXCSR1 ); list_add_tail (&req->queue, &ep->queue); goto done; } if (list_empty (&ep->queue) && !ep->stopped) { /* maybe there's no control data, just status ack */ if (ep->num == 0 && _req->length == 0) { /* No dta to transfer */ done (ep, req, 0); printk("%s: %s status ack\n",__FUNCTION__, ep->ep.name); goto done; } /* try dma first */ status = kick_dma (ep, req); if (status < 0) { /* dma failed (most likely in use by another endpoint) * fallback to pio */ status = 0; ep_num = ep_name_to_index(ep->ep.name); if((ep->is_in)|| ep_num == 3) status = write_fifo (ep, req); else { if(rx_pending) { //printk("%s: rx pending interrupt\n", __FUNCTION__); status = read_fifo (ep, req); /*Vishal: read from FIFO into request struct */ rx_pending = 0; } else status = -1; } // status = -1; /*Vishal: read from FIFO into request struct */ } } /*Add to queue of pertinent endpoint */ if (status != 0) list_add_tail (&req->queue, &ep->queue);done: local_irq_enable(); spin_unlock_irqrestore (&dev->lock, flags); return 0;}/* dequeue ALL requests */static void nuke (struct dm320_ep *ep){ struct dm320_request *req; /* called with spinlock held */// ep->stopped = 1; while (!list_empty (&ep->queue)) { req = list_entry (ep->queue.next,struct dm320_request,queue); done (ep, req, -ESHUTDOWN); }}/* dequeue JUST ONE request */static int dm320_dequeue (struct usb_ep *_ep, struct usb_request *_req){ struct dm320_ep *ep; struct dm320 *dev; dev = the_controller; if (!_ep) return 0; ep = container_of (_ep, struct dm320_ep, ep); printk("%s: dm320 API called\n", __FUNCTION__); spin_lock (&dev->lock); nuke(ep); spin_unlock (&dev->lock); return 0;}//#define PIPE_STALL 1static intdm320_set_halt (struct usb_ep *_ep, int value){ struct dm320_ep *ep; unsigned long flags; int retval = 0;#ifdef PIPE_STALL printk("%s: Non functional dm320 API called\n", __FUNCTION__); writeb(EP_BULK_IN_NUM, USB_INDEX ); writeb(readb(USB_PER_TXCSR1)|USB_TXCSR1_SENDST,USB_PER_TXCSR1); printk("Stalled BULK-IN Endpoint\n"); return 0;#endif return -1;}static intdm320_fifo_status (struct usb_ep *_ep){ printk("%s: Non functional dm320 API called\n", __FUNCTION__);}static voiddm320_fifo_flush (struct usb_ep *_ep){ //printk("dm320: Flushing H/W FIFO's\n"); flushEPFIFO( ep_name_to_index(_ep->name) );}static voidstop_activity (struct dm320 *dev, struct usb_gadget_driver *driver){ printk("%s: Non functional dm320 USB gadget API\n", __FUNCTION__);}static int dm320_disable (struct usb_ep *_ep){ struct dm320_ep *ep; unsigned long flags; ep = container_of (_ep, struct dm320_ep, ep); if (!_ep || !ep->desc || _ep->name == ep0name) return -EINVAL; spin_lock_irqsave (&ep->dev->lock, flags); nuke (ep); ep_reset (ep); VDEBUG (ep->dev, "disabled %s\n", _ep->name); spin_unlock_irqrestore (&ep->dev->lock, flags); return 0;}static struct dm320 *the_controller;static void usb_reinit (struct dm320 *dev){ int tmp; for (tmp = 0; tmp < NUM_OF_ENDPOINTS + 1; tmp++) { struct dm320_ep *ep = &dev->ep[tmp]; ep->ep.name = ep_name [tmp]; ep->dev = dev; ep->num = tmp; if (tmp > 0 && tmp <= NUM_OF_ENDPOINTS + 1) { ep->fifo_size = EP0_FIFO_SIZE; } else ep->fifo_size = EP0_FIFO_SIZE; ep_reset (ep); } dev->ep [0].ep.maxpacket = EP0_FIFO_SIZE; /* Vishal: CHANGE /8 handled this statically. Not good*/ //Vishal : dev->ep [1].ep.maxpacket = 8 ; /* Bulk IN endpoint */ dev->ep [1].ep.maxpacket = BULK_TRANS_SIZE ; /* Bulk IN endpoint */ dev->ep [1].is_in = 1; //Vishal: dev->ep [2].ep.maxpacket = 8; /* Bulk OUT endpoint */ dev->ep [2].ep.maxpacket = BULK_TRANS_SIZE; /* Bulk OUT endpoint */ dev->ep [2].is_in = 0; dev->ep [3].ep.maxpacket = INTR_TRANS_SIZE; /* INTR IN endpoint */ dev->gadget.ep0 = &dev->ep [0].ep; dev->ep [0].stopped = 0; dev->ep[0].pending = dev->ep[1].pending = dev->ep[2].pending = dev->ep[2].pending= 0; INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);}static void ep0_start (struct dm320 *dev){ dm320_reset_ep(0); writeb( USB_EP0, USB_INTRTX1E ); // enable endpoint EP0 RX/TX ) writeb( USB_RESET | USB_RESUME | USB_SUSPEND | USB_SESSREQ | USB_SOF , USB_INTRUSBE ); // Peripheral mode & 'B' type( slave ) }static void ep_reset (struct dm320_ep *ep){ ep->desc = NULL; INIT_LIST_HEAD (&ep->queue); ep->ep.maxpacket = ~0; ep->ep.ops = &dm320_ep_ops; dm320_reset_ep(ep);}static struct usb_request *dm320_alloc_request (struct usb_ep *_ep, int gfp_flags){ struct dm320_ep *ep; struct dm320_request *req; if (!_ep) return NULL; ep = container_of (_ep, struct dm320_ep, ep); req = kmalloc (sizeof *req, gfp_flags); if (!req) return NULL; memset (req, 0, sizeof *req); req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD (&req->queue); return &req->req;}static voiddm320_free_request (struct usb_ep *_ep, struct usb_request *_req){ struct dm320_ep *ep;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -