📄 usb_ep0.c
字号:
/* * Copyright (C) Intrinsyc, Inc., 2002 * Modified for 24A0A board * usb_ep0.h * */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/tqueue.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include "s3c2440_usb.h" /* public interface */#include "usb_ctl.h" /* private stuff */#include "usb_ep0.h"//#define VERBOSITY 1enum { false = 0, true = 1 };#ifndef MIN#define MIN( a, b ) ((a)<(b)?(a):(b))#endif#if 1 && !defined( ASSERT )# define ASSERT(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ }#else# define ASSERT(expr)#endif#if VERBOSITY#define PRINTKD(fmt, args...) printk( fmt , ## args)#else#define PRINTKD(fmt, args...)#endifunsigned int ep0_state;__u8 set_configuration;__u8 set_interface;__u8 device_status;__u8 ep0_status;__u8 ep_bulk_in_status;__u8 ep_bulk_out_status;unsigned int control_complete;/*=======================================================================*//** USB Protocol Stuff. This part includes the code for basic Enumeration*//*************************************************************************/static int read_fifo(usb_dev_request_t * p);static void standard_dev_req(usb_dev_request_t req);static void set_feature(usb_dev_request_t req);static void clear_feature(usb_dev_request_t req);static void set_descriptor(void);static void get_descriptor(usb_dev_request_t req);static void ep0_transmit(void);static void ep0_receive(void);static void queue_and_start_write( void * p, int req, int act );/*************************************************************************//*Inline Helpers*//**************************************************************************/inline intrequest_target(__u8 b){ return (int) (b & 0x0F);}inline intwindex_to_ep_num(__u16 w){ return (int) (w & 0x000F);}inline inttype_code_from_request(__u8 by){ return ((by >> 4) & 3);}/* print string descriptor */static inline voidpsdesc(string_desc_t * p){ int i; int nchars = (p->bLength - 2) / sizeof (__u16); for (i = 0; i < nchars; i++) { //printk( "%c", (char) p->bString[i] ); }}#if VERBOSITY/* "pcs" == "print control status" */static inline voidpcs(void){ unsigned long backup; __u32 foo; backup = UD_INDEX; UD_INDEX = UD_INDEX_EP0; foo = UD_ICSR1; UD_INDEX = backup;}static inline voidpreq(usb_dev_request_t * pReq){ static char *tnames[] = { "dev", "intf", "ep", "oth" }; static char *rnames[] = { "std", "class", "vendor", "???" }; char *psz; switch (pReq->bRequest) { case GET_STATUS: psz = "get stat"; break; case CLEAR_FEATURE: psz = "clr feat"; break; case SET_FEATURE: psz = "set feat"; break; case SET_ADDRESS: psz = "set addr"; break; case GET_DESCRIPTOR: psz = "get desc"; break; case SET_DESCRIPTOR: psz = "set desc"; break; case GET_CONFIGURATION: psz = "get cfg"; break; case SET_CONFIGURATION: psz = "set cfg"; break; case GET_INTERFACE: psz = "get intf"; break; case SET_INTERFACE: psz = "set intf"; break; default: psz = "unknown"; break; } // printk( "- [%s: %s req to %s. dir=%s]\n", psz, // rnames[ (pReq->bmRequestType >> 5) & 3 ], // tnames[ pReq->bmRequestType & 3 ], // ( pReq->bmRequestType & 0x80 ) ? "in" : "out" );}#else#define pcs() (void)(0)#define preq(x) (void)(0)#endif/***************************************************************************Globals***************************************************************************/static const char pszMe[] = "usbep0: ";/* global write struct to keep write ..state around across interrupts */static struct { unsigned char *p; int bytes_left; unsigned int transfer_length; unsigned int transfered_data;} wr;/***************************************************************************Public Interface***************************************************************************//* reset received from HUB (or controller just went nuts and reset by itself!) so udc core has been reset, track this state here */voidep0_reset(void){ /* reset state machine */ wr.p = NULL; wr.bytes_left = 0; wr.transfer_length = 0; wr.transfered_data = 0; usbd_info.address = 0; control_complete = 0;}/* handle interrupt for endpoint zero */#define clear_ep0_sst { \ UD_INDEX = UD_INDEX_EP0; \ UD_ICSR1 = 0x00; /*EP0_CSR_SENTSTL*/ \}#define clear_ep0_se { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg=UD_ICSR1;\ reg=( reg & ~0xC0) | EP0_CSR_SSE; \ UD_ICSR1 = reg;\}#define clear_ep0_opr { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg=UD_ICSR1;\ reg=( reg & ~0xC0) | EP0_CSR_SOPKTRDY; \ UD_ICSR1=reg;\}#define set_ep0_ipr { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg=UD_ICSR1;\ reg= ( reg & ~0xC0) | EP0_CSR_IPKRDY; \ UD_ICSR1=reg;\}#define set_ep0_de { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg = UD_ICSR1\ reg = EP0_CSR_DE; \ UD_ICSR1= reg;\}#define set_ep0_ss { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg = UD_ICSR1;\ reg = EP0_CSR_SENDSTL; \ UD_ICSR1 = reg;\}#define set_ep0_de_out { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg= UD_ICSR1;\ reg = ( reg & ~0xC0) | (EP0_CSR_SOPKTRDY | EP0_CSR_DE); \ UD_ICSR1 = reg;\}#define set_ep0_de_in { \ __u32 reg;\ UD_INDEX = UD_INDEX_EP0; \ reg = UD_ICSR1;\ reg = ( reg & ~0xC0) |(EP0_CSR_IPKRDY | EP0_CSR_DE); \ UD_ICSR1=reg;\}#define clear_stall_ep4_out { \ __u32 reg; \ UD_INDEX = UD_INDEX_EP4; \ reg = UD_OCSR1; \ UD_OCSR1 = reg; \}#define clear_stall_ep3_out { \ __u32 reg; \ UD_INDEX = UD_INDEX_EP3; \ reg = UD_OCSR1; \ UD_OCSR1 = reg; \}#define clear_stall_ep1_out { \ __u32 reg; \ UD_INDEX = UD_INDEX_EP1; \ reg = UD_OCSR1; \ UD_OCSR1 = reg; \}#define clear_stall_ep2_out { \ __u32 reg; \ UD_INDEX = UD_INDEX_EP2; \ reg = UD_OCSR1; \ UD_OCSR1 = reg; \}voidep0_int_hndlr(void){ usb_dev_request_t req; int request_type, n; __u32 cs_reg; UD_INDEX = UD_INDEX_EP0; cs_reg = UD_ICSR1; pcs(); if (cs_reg & EP0_CSR_SENTSTL) { clear_ep0_sst; ep0_state = EP0_STATE_IDLE; /* return; */ /* Remove to respond simultaneous interrupt. by SW Lee */ } if (cs_reg & EP0_CSR_SE) { clear_ep0_se; ep0_state = EP0_STATE_IDLE; /* return; */ /* Remove to respond simultaneous interrupt. by SW Lee */ } switch (ep0_state) { case EP0_STATE_IDLE: if (cs_reg & EP0_CSR_OPKRDY) { /* read setup request */ n = read_fifo(&req); if (n != sizeof (req)) { printk ("%ssettup begin : fifo READ ERROR wanted %d bytes got %d. Stalling out...\n", pszMe, sizeof (req), n); set_ep0_ss; return; }#if VERBOSITY { unsigned char *pdb = (unsigned char *) &req; PRINTKD("%2.2X %2.2X %2.2X %2.2X" " %2.2X %2.2X %2.2X %2.2X ", pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]); preq(&req); }#endif request_type = type_code_from_request(req.bmRequestType); switch (request_type) { case 0: // standard request standard_dev_req(req); break; default: // class, vendor, resolved types#if defined(CONFIG_S3C2440_USB_CDC_ENCM) || defined(CONFIG_S3C2440_USB_CDC_ENCM_MODULE) if (req.bRequest == CDC_ENCM_SET_ETHERNET_PACKET_FILTER) { printk("%sCDC_ENCM_SET_ETHERNET_PACKET_FILTER\n", pszMe); clear_ep0_opr; set_ep0_ipr; } else { printk("%sunknown request packet:\n", pszMe); printk ("%sbmRequestType: 0x%02x, bRequest: 0x%02x, " "wValue: 0x%04x, wIndex: 0x%04x, wLength: 0x%04x\n", pszMe, req.bmRequestType, req.bRequest, req.wValue, req.wIndex, req.wLength);// set_ep0_ipr;// clear_ep0_opr; }#else printk ("%ssetup begin : unsupported bmRequestType :" " %d ignored\n", pszMe, request_type);#endif return; } } break; case EP0_STATE_TRANSFER: ep0_transmit(); break; case EP0_STATE_RECEIVER: ep0_receive(); break; } pcs();}/* working shawn */static voidstandard_dev_req(usb_dev_request_t req){ __u32 address; int n, e; n = request_target(req.bmRequestType); switch (n) { /* device recipient */ case kTargetDevice: switch (req.bRequest) { case SET_FEATURE: set_feature(req); /* work?, shawn */ break; case CLEAR_FEATURE: clear_feature(req); /* work? shawn */ break; case SET_ADDRESS: address = (__u32) (req.wValue & 0x7F); UD_FUNC = (address | 0x80); usbd_info.address = address; usbctl_next_state_on_event(kEvAddress); set_ep0_de_out; ep0_state = EP0_STATE_IDLE; break; case SET_DESCRIPTOR: set_descriptor(); break; case SET_CONFIGURATION: set_configuration = (__u8) req.wValue; /* low byte */#if 0 set_ep0_de_out;#endif if (req.wValue == 1) { /* configured */ if (usbctl_next_state_on_event(kEvConfig) != kError) { desc_t *pDesc = elfin_usb_get_descriptor_ptr(); __u32 in = __le16_to_cpu(pDesc->b.ep2.wMaxPacketSize); __u32 out = __le16_to_cpu(pDesc->b.ep1.wMaxPacketSize); UD_INDEX = 2; UD_MAXP = UD_MAXP_64; UD_INDEX = 1; UD_MAXP = UD_MAXP_64; printk ("%sConfigured (IN MAX PACKET=%d, OUT MAX PACKET=%d)\n", pszMe, in, out); } } else if (req.wValue == 0) { if (usbctl_next_state_on_event(kEvDeConfig) != kError) printk("%sDe-Configuration\n", pszMe); } else { printk ("%ssetup phase : Unknown [set configuration] data %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -