📄 usb_ctl.c
字号:
/* * This program is derived from Extenex Corporation's SA-1100 usb * controller core driver by MIZI. * * usb_ctl.c * * S3C2410 USB controller core driver. * * This file provides interrupt routing and overall coordination * of the five endpoints. * * Seungbum Lim <shawn@mizi.com> *//* * ep0 - register * ep2~4 - dual port async. RAM (interrupt or DMA) * * config: * ep0. * ep2 : input - DMA_CH0 ? * ep1 : output - DMA_CH3 ? */#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/slab.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/mach-types.h>#include "s3c2410_usb.h"#include "usb_ctl.h"//////////////////////////////////////////////////////////////////////////////// Prototypes//////////////////////////////////////////////////////////////////////////////int usbctl_next_state_on_event( int event );static void udc_int_hndlr(int, void *, struct pt_regs *);static void initialize_descriptors( void );void ChangeUPllValue(int mdiv, int pdiv, int sdiv);void reset_usbd(void);void reconfig_usbd(void);//#define USB_DEBUG 1#ifdef USB_DEBUG#define LOG(arg...) printk(__FILE__":"__FUNCTION__"(): " ##arg)#else#define LOG(arg...) (void)(0)#endif#if CONFIG_PROC_FS#define PROC_NODE_NAME "usb"static int usbctl_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);#endif//////////////////////////////////////////////////////////////////////////////// Globals//////////////////////////////////////////////////////////////////////////////static const char pszMe[] = "usbctl: ";struct usb_info_t usbd_info; /* global to ep0, usb_recv, usb_send *///static int cnt=0;/* device descriptors */static desc_t desc;#define MAX_STRING_DESC 8static string_desc_t * string_desc_array[ MAX_STRING_DESC ];static string_desc_t sd_zero; /* special sd_zero holds language codes */// called when configuredstatic usb_notify_t configured_callback = NULL;enum { kStateZombie = 0, kStateZombieSuspend = 1, kStateDefault = 2, kStateDefaultSuspend = 3, kStateAddr = 4, kStateAddrSuspend = 5, kStateConfig = 6, kStateConfigSuspend = 7};static int device_state_machine[8][6] = {// suspend reset resume adddr config deconfig/* zombie */ { kStateZombieSuspend, kStateDefault, kError, kError, kError, kError },/* zom sus */ { kError, kStateDefault, kStateZombie, kError, kError, kError },/* default */ { kStateDefaultSuspend, kError, kStateDefault, kStateAddr, kError, kError },/* def sus */ { kError, kStateDefault, kStateDefault, kError, kError, kError },/* addr */ { kStateAddrSuspend, kStateDefault, kError, kError, kStateConfig, kError },/* addr sus */{ kError, kStateDefault, kStateAddr, kError, kError, kError },/* config */ { kStateConfigSuspend, kStateDefault, kError, kError, kError, kStateAddr },/* cfg sus */ { kError, kStateDefault, kStateConfig, kError, kError, kError }};/* "device state" is the usb device framework state, as opposed to the "state machine state" which is whatever the driver needs and is much more fine grained*/static int sm_state_to_device_state[8] =// zombie zom suspend default default sus{ USB_STATE_POWERED, USB_STATE_SUSPENDED, USB_STATE_DEFAULT, USB_STATE_SUSPENDED,// addr addr sus config config sus USB_STATE_ADDRESS, USB_STATE_SUSPENDED, USB_STATE_CONFIGURED, USB_STATE_SUSPENDED};static char * state_names[8] ={ "zombie", "zombie suspended", "default", "default suspended", "address", "address suspended", "configured", "config suspended"};static char * event_names[6] ={ "suspend", "reset", "resume", "address assigned", "configure", "de-configure"};static char * device_state_names[] ={ "not attached", "attached", "powered", "default", "address", "configured", "suspended" };static int sm_state = kStateZombie;//////////////////////////////////////////////////////////////////////////////// Reset Fucntions//////////////////////////////////////////////////////////////////////////////void reset_usbd(void){ int i; UD_PWR = UD_PWR_DEFAULT | UD_PWR_RESET; /* UD_PWR default value, MCU_RESET */ UD_PWR; UD_PWR = UD_PWR_DEFAULT; LOG("UD_PWR = 0x%08x\n", UD_PWR); for(i = 0; i< 0x100; i++) ;}void reconfig_usbd(void){ LOG("\n"); /* sec like, shawn */ ep0_state = EP0_STATE_IDLE; set_configuration = 1; set_interface = 1; device_status = 0; ep0_status = 0; ep_bulk_in_status = 0; ep_bulk_out_status = 0; UD_PWR = UD_PWR_DEFAULT; /* EP0 */ UD_INDEX = UD_INDEX_EP0; UD_MAXP = UD_MAXP_8; // 8 byte UD_INDEX = UD_INDEX_EP0; UD_ICSR1 = EP0_CSR_SOPKTRDY | EP0_CSR_SSE; /* EP2 */ UD_INDEX = UD_INDEX_EP2; UD_MAXP = UD_MAXP_64; // 64 byte UD_INDEX = UD_INDEX_EP2; UD_ICSR1 = UD_ICSR1_FFLUSH | UD_ICSR1_CLRDT; // fifo flush, data toggle UD_INDEX = UD_INDEX_EP2; UD_ICSR2 = UD_ICSR2_MODEIN | UD_ICSR2_DMAIEN; // input mode, IN_PKT_RDY dis #ifdef USE_USBD_DMA UD_ICSR2 &= ~UD_ICSR2_DMAIEN;#endif /* EP1 */ UD_INDEX = UD_INDEX_EP1; UD_MAXP = UD_MAXP_64; // 64 byte UD_INDEX = UD_INDEX_EP1; UD_ICSR1 = UD_ICSR1_FFLUSH | UD_ICSR1_CLRDT; // fifo flush, data toggle UD_INDEX = UD_INDEX_EP1; UD_ICSR2 = 0x0; // output mode UD_INDEX = UD_INDEX_EP1; UD_OCSR1 = UD_OCSR1_FFLUSH | UD_OCSR1_CLRDT; // fifo flush UD_INDEX = UD_INDEX_EP1; UD_OCSR2 = UD_OCSR2_DMAIEN; // OUT_PKT_RDY interrupt disable#ifdef USE_USBD_DMA UD_OCSR2 &= ~UD_OCSR2_DMAIEN; // OUT_PKT_RDY interrupt disable#endif UD_INTE = UD_INTE_EP0 | UD_INTE_EP2 | UD_INTE_EP1; UD_USBINTE = UD_USBINTE_RESET | UD_USBINTE_SUSPND; initialize_descriptors(); bINTCTL(oINTMSK) &= ~(INT_USBD);} static voidudc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs){ __u8 saveIdx = UD_INDEX; __u8 usb_status = UD_USBINT; __u8 usbd_status = UD_INT; static int sb_debug_cnt = 1; LOG("usb_status = 0x%02x, usbd_status = 0x%02x\n", usb_status, usbd_status); if ( usb_status & UD_USBINT_RESET ) { LOG("\n[%d]RESET interrupt\n",sb_debug_cnt++); if( usbctl_next_state_on_event(kEvReset) != kError ) { LOG("%s Resetting\n",pszMe); ep0_reset(); ep1_reset();/* output */ ep2_reset();/* input */ } // reset_usbd(); reconfig_usbd(); UD_USBINT = UD_USBINT_RESET; //RESET_INT should be cleared after reconfig_usbd().- by samsung src ep0_state = EP0_STATE_IDLE; } /* RESume Interrupt Request */ if ( usb_status & UD_USBINT_RESUM ) { LOG("[%d]RESUME interrupt\n", sb_debug_cnt++); UD_USBINT = UD_USBINT_RESUM;/* clear */ usbctl_next_state_on_event( kEvResume ); } /* SUSpend Interrupt Request */ if ( usb_status & UD_USBINT_SUSPND ) { LOG("[%d]SUSPEND interrupt\n", sb_debug_cnt++); UD_USBINT = UD_USBINT_SUSPND; /* clear */ usbctl_next_state_on_event( kEvSuspend ); } if ( usbd_status & UD_INT_EP0 ) { LOG("\n[%d]EP0 interrupt\n",sb_debug_cnt++); UD_INT = UD_INT_EP0; /* clear */ ep0_int_hndlr(); } /* output */ if ( usbd_status & UD_INT_EP1 ) { LOG("[%d]EP1 interrupt\n", sb_debug_cnt++); UD_INT = UD_INT_EP1;/* clear */ ep1_int_hndlr(usbd_status); } /* input */ if ( usbd_status & UD_INT_EP2 ) { LOG("[%d]EP2 interrupt\n", sb_debug_cnt++); UD_INT = UD_INT_EP2; /* clear */ ep2_int_hndlr(usbd_status); } if(usbd_status & UD_INT_EP3) UD_INT = UD_INT_EP3; if(usbd_status & UD_INT_EP4) UD_INT = UD_INT_EP4; Clear_pending(INT_USBD); UD_INDEX= saveIdx; }//////////////////////////////////////////////////////////////////////////////// Public Interface///////////////////////////////////////////////////////////////////////////////* Open S3C2410 usb core on behalf of a client, but don't start running */ints3c2410_usb_open( const char * client ){ LOG("\n"); if ( usbd_info.client_name != NULL ) return -EBUSY; usbd_info.client_name = (char*) client; memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t)); memset(string_desc_array, 0, sizeof(string_desc_array)); /* hack to start in zombie suspended state */#if 0 sm_state = kStateZombieSuspend; usbd_info.state = USB_STATE_SUSPENDED;#endif /* create descriptors for enumeration */ initialize_descriptors(); printk( "%sOpened for %s\n", pszMe, client ); return 0;}/* Start running. Must have called usb_open (above) first */ints3c2410_usb_start( void ){ unsigned long tmp; LOG("\n"); if ( usbd_info.client_name == NULL ) { printk( "%s%s - no client registered\n", pszMe, __FUNCTION__ ); return -EPERM; } /* start UDC internal machinery running */ udelay( 100 ); /* clear stall - receiver seems to start stalled? */ UD_INDEX = UD_INDEX_EP2; // EP2 input tmp = UD_ICSR1; tmp &= ~(UD_ICSR1_SENTSTL | UD_ICSR1_FFLUSH | UD_ICSR1_UNDRUN); tmp &= ~(UD_ICSR1_PKTRDY | UD_ICSR1_SENDSTL); UD_ICSR1 = tmp; UD_INDEX = UD_INDEX_EP1; // EP1 output tmp = UD_OCSR1; tmp &= ~(UD_OCSR1_SENTSTL | UD_OCSR1_FFLUSH | UD_OCSR1_OVRRUN); tmp &= ~(UD_OCSR1_PKTRDY | UD_OCSR1_SENDSTL); UD_OCSR1 = tmp; /* flush DMA and fire through some -EAGAINs */ ep2_init( usbd_info.dmach_tx ); ep1_init( usbd_info.dmach_rx ); /* clear all top-level sources */ UD_INT = UD_INT_EP0 | UD_INT_EP1 | UD_INT_EP2; UD_USBINT = UD_USBINT_RESET | UD_USBINT_RESUM | UD_USBINT_SUSPND; printk( "%sStarted for %s\n", pszMe, usbd_info.client_name ); return 0;}/* Stop USB core from running */ints3c2410_usb_stop( void ){ LOG("name=%s\n", usbd_info.client_name ? usbd_info.client_name : "NULL"); if ( usbd_info.client_name == NULL ) { printk( "%s%s - no client registered\n", pszMe, __FUNCTION__ ); return -EPERM; }#if 0 /* It may be default value of S3C2410 USBD and makes only RESET be enalble*/ UD_INTM = 0x13f;#endif ep1_reset(); ep2_reset(); printk( "%sStopped \n", pszMe ); return 0;}/* Tell S3C2410 core client is through using it */ints3c2410_usb_close( void ){ if ( usbd_info.client_name == NULL ) { printk( "%s%s - no client registered\n", pszMe, __FUNCTION__ ); return -EPERM; } usbd_info.client_name = NULL; return 0;}/* set a proc to be called when device is configured */usb_notify_t s3c2410_set_configured_callback( usb_notify_t func ){ usb_notify_t retval = configured_callback; LOG("\n"); configured_callback = func; return retval;}/*==================================================== * Descriptor Manipulation. * Use these between open() and start() above to setup * the descriptors for your device. * *//* get pointer to static default descriptor */desc_t *s3c2410_usb_get_descriptor_ptr( void ) { return &desc; }/* optional: set a string descriptor */ints3c2410_usb_set_string_descriptor( int i, string_desc_t * p )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -