📄 usb_ctl.c
字号:
return ( i < MAX_STRING_DESC ) ? string_desc_array[i] : NULL;}/* optional: kmalloc and unicode up a string descriptor */string_desc_t *sa1100_usb_kmalloc_string_descriptor( const char * p ){ string_desc_t * pResult = NULL; if ( p ) { int len = strlen( p ); int uni_len = len * sizeof( __u16 ); pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */ if ( pResult != NULL ) { int i; pResult->bLength = uni_len + 2; pResult->bDescriptorType = USB_DESC_STRING; for( i = 0; i < len ; i++ ) { pResult->bString[i] = make_word( (__u16) p[i] ); } } } return pResult;}//////////////////////////////////////////////////////////////////////////////// Exports to rest of driver///////////////////////////////////////////////////////////////////////////////* called by the int handler here and the two endpoint files when interesting .."events" happen */intusbctl_next_state_on_event( int event ){ int next_state = device_state_machine[ sm_state ][ event ]; if ( next_state != kError ) { int next_device_state = sm_state_to_device_state[ next_state ]; printk( "%s%s --> [%s] --> %s. Device in %s state.\n", pszMe, state_names[ sm_state ], event_names[ event ], state_names[ next_state ], device_state_names[ next_device_state ] ); sm_state = next_state; if ( usbd_info.state != next_device_state ) { if ( configured_callback != NULL && next_device_state == USB_STATE_CONFIGURED && usbd_info.state != USB_STATE_SUSPENDED ) { configured_callback(); } usbd_info.state = next_device_state; ep1_state_change_notify( next_device_state ); ep2_state_change_notify( next_device_state ); } }#if 0 else printk( "%s%s --> [%s] --> ??? is an error.\n", pszMe, state_names[ sm_state ], event_names[ event ] );#endif return next_state;}//////////////////////////////////////////////////////////////////////////////// Private Helpers///////////////////////////////////////////////////////////////////////////////* setup default descriptors */static voidinitialize_descriptors(void){ desc.dev.bLength = sizeof( device_desc_t ); desc.dev.bDescriptorType = USB_DESC_DEVICE; desc.dev.bcdUSB = 0x100; /* 1.0 */ desc.dev.bDeviceClass = 0xFF; /* vendor specific */ desc.dev.bDeviceSubClass = 0; desc.dev.bDeviceProtocol = 0; desc.dev.bMaxPacketSize0 = 8; /* ep0 max fifo size */ desc.dev.idVendor = 0; /* vendor ID undefined */ desc.dev.idProduct = 0; /* product */ desc.dev.bcdDevice = 0; /* vendor assigned device release num */ desc.dev.iManufacturer = 0; /* index of manufacturer string */ desc.dev.iProduct = 0; /* index of product description string */ desc.dev.iSerialNumber = 0; /* index of string holding product s/n */ desc.dev.bNumConfigurations = 1; desc.b.cfg.bLength = sizeof( config_desc_t ); desc.b.cfg.bDescriptorType = USB_DESC_CONFIG; desc.b.cfg.wTotalLength = make_word_c( sizeof(struct cdb) ); desc.b.cfg.bNumInterfaces = 1; desc.b.cfg.bConfigurationValue = 1; desc.b.cfg.iConfiguration = 0; desc.b.cfg.bmAttributes = USB_CONFIG_BUSPOWERED; desc.b.cfg.MaxPower = USB_POWER( 500 ); desc.b.intf.bLength = sizeof( intf_desc_t ); desc.b.intf.bDescriptorType = USB_DESC_INTERFACE; desc.b.intf.bInterfaceNumber = 0; /* unique intf index*/ desc.b.intf.bAlternateSetting = 0; desc.b.intf.bNumEndpoints = 2; desc.b.intf.bInterfaceClass = 0xFF; /* vendor specific */ desc.b.intf.bInterfaceSubClass = 0; desc.b.intf.bInterfaceProtocol = 0; desc.b.intf.iInterface = 0; desc.b.ep1.bLength = sizeof( ep_desc_t ); desc.b.ep1.bDescriptorType = USB_DESC_ENDPOINT; desc.b.ep1.bEndpointAddress = USB_EP_ADDRESS( 1, USB_OUT ); desc.b.ep1.bmAttributes = USB_EP_BULK; desc.b.ep1.wMaxPacketSize = make_word_c( 64 ); desc.b.ep1.bInterval = 0; desc.b.ep2.bLength = sizeof( ep_desc_t ); desc.b.ep2.bDescriptorType = USB_DESC_ENDPOINT; desc.b.ep2.bEndpointAddress = USB_EP_ADDRESS( 2, USB_IN ); desc.b.ep2.bmAttributes = USB_EP_BULK; desc.b.ep2.wMaxPacketSize = make_word_c( 64 ); desc.b.ep2.bInterval = 0; /* set language */ /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */ sd_zero.bDescriptorType = USB_DESC_STRING; sd_zero.bLength = sizeof( string_desc_t ); sd_zero.bString[0] = make_word_c( 0x409 ); /* American English */ sa1100_usb_set_string_descriptor( 0, &sd_zero );}/* soft_connect_hook() * Some devices have platform-specific circuitry to make USB * not seem to be plugged in, even when it is. This allows * software to control when a device 'appears' on the USB bus * (after Linux has booted and this driver has loaded, for * example). If you have such a circuit, control it here. */static voidsoft_connect_hook( int enable ){#ifdef CONFIG_SA1100_EXTENEX1 if (machine_is_extenex1() ) { if ( enable ) { PPDR |= PPC_USB_SOFT_CON; PPSR |= PPC_USB_SOFT_CON; } else { PPSR &= ~PPC_USB_SOFT_CON; PPDR &= ~PPC_USB_SOFT_CON; } }#endif}/* disable the UDC at the source */static voidudc_disable(void){ soft_connect_hook( 0 ); UDC_set( Ser0UDCCR, UDCCR_UDD );}/* enable the udc at the source */static voidudc_enable(void){ UDC_clear(Ser0UDCCR, UDCCR_UDD);}// HACK DEBUG 3Mar01ww// Well, maybe not, it really seems to help! 08Mar01wwstatic voidcore_kicker( void ){ __u32 car = Ser0UDCAR; __u32 imp = Ser0UDCIMP; __u32 omp = Ser0UDCOMP; UDC_set( Ser0UDCCR, UDCCR_UDD ); udelay( 300 ); UDC_clear(Ser0UDCCR, UDCCR_UDD); Ser0UDCAR = car; Ser0UDCIMP = imp; Ser0UDCOMP = omp;}//////////////////////////////////////////////////////////////////////////////// Proc Filesystem Support//////////////////////////////////////////////////////////////////////////////#if CONFIG_PROC_FS#define SAY( fmt, args... ) p += sprintf(p, fmt, ## args )#define SAYV( num ) p += sprintf(p, num_fmt, "Value", num )#define SAYC( label, yn ) p += sprintf(p, yn_fmt, label, yn )#define SAYS( label, v ) p += sprintf(p, cnt_fmt, label, v )static int usbctl_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ const char * num_fmt = "%25.25s: %8.8lX\n"; const char * cnt_fmt = "%25.25s: %lu\n"; const char * yn_fmt = "%25.25s: %s\n"; const char * yes = "YES"; const char * no = "NO"; unsigned long v; char * p = page; int len; SAY( "SA1100 USB Controller Core\n" ); SAY( "USB state: %s (%s) %d\n", device_state_names[ sm_state_to_device_state[ sm_state ] ], state_names[ sm_state ], sm_state ); SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read ); SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written ); SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures ); SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures ); SAY( "\n" ); v = Ser0UDCAR; SAY( "%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v ); v = Ser0UDCIMP; SAY( "%25.25s: %ld (%8.8lX)\n", "IN max packet size", v+1, v ); v = Ser0UDCOMP; SAY( "%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v ); v = Ser0UDCCR; SAY( "\nUDC Mask Register\n" ); SAYV( v ); SAYC( "UDC Active", ( v & UDCCR_UDA ) ? yes : no ); SAYC( "Suspend interrupts masked", ( v & UDCCR_SUSIM ) ? yes : no ); SAYC( "Resume interrupts masked", ( v & UDCCR_RESIM ) ? yes : no ); SAYC( "Reset interrupts masked", ( v & UDCCR_REM ) ? yes : no ); v = Ser0UDCSR; SAY( "\nUDC Interrupt Request Register\n" ); SAYV( v ); SAYC( "Reset pending", ( v & UDCSR_RSTIR ) ? yes : no ); SAYC( "Suspend pending", ( v & UDCSR_SUSIR ) ? yes : no ); SAYC( "Resume pending", ( v & UDCSR_RESIR ) ? yes : no ); SAYC( "ep0 pending", ( v & UDCSR_EIR ) ? yes : no ); SAYC( "receiver pending", ( v & UDCSR_RIR ) ? yes : no ); SAYC( "tramsitter pending", ( v & UDCSR_TIR ) ? yes : no );#ifdef CONFIG_SA1100_EXTENEX1 SAYC( "\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden" );#endif#if 0 v = Ser0UDCCS0; SAY( "\nUDC Endpoint Zero Status Register\n" ); SAYV( v ); SAYC( "Out Packet Ready", ( v & UDCCS0_OPR ) ? yes : no ); SAYC( "In Packet Ready", ( v & UDCCS0_IPR ) ? yes : no ); SAYC( "Sent Stall", ( v & UDCCS0_SST ) ? yes : no ); SAYC( "Force Stall", ( v & UDCCS0_FST ) ? yes : no ); SAYC( "Data End", ( v & UDCCS0_DE ) ? yes : no ); SAYC( "Data Setup End", ( v & UDCCS0_SE ) ? yes : no ); SAYC( "Serviced (SO)", ( v & UDCCS0_SO ) ? yes : no ); v = Ser0UDCCS1; SAY( "\nUDC Receiver Status Register\n" ); SAYV( v ); SAYC( "Receive Packet Complete", ( v & UDCCS1_RPC ) ? yes : no ); SAYC( "Sent Stall", ( v & UDCCS1_SST ) ? yes : no ); SAYC( "Force Stall", ( v & UDCCS1_FST ) ? yes : no ); SAYC( "Receive Packet Error", ( v & UDCCS1_RPE ) ? yes : no ); SAYC( "Receive FIFO not empty", ( v & UDCCS1_RNE ) ? yes : no ); v = Ser0UDCCS2; SAY( "\nUDC Transmitter Status Register\n" ); SAYV( v ); SAYC( "FIFO has < 8 of 16 chars", ( v & UDCCS2_TFS ) ? yes : no ); SAYC( "Transmit Packet Complete", ( v & UDCCS2_TPC ) ? yes : no ); SAYC( "Transmit FIFO underrun", ( v & UDCCS2_TUR ) ? yes : no ); SAYC( "Transmit Packet Error", ( v & UDCCS2_TPE ) ? yes : no ); SAYC( "Sent Stall", ( v & UDCCS2_SST ) ? yes : no ); SAYC( "Force Stall", ( v & UDCCS2_FST ) ? yes : no );#endif len = ( p - page ) - off; if ( len < 0 ) len = 0; *eof = ( len <=count ) ? 1 : 0; *start = page + off; return len;}#endif /* CONFIG_PROC_FS *///////////////////////////////////////////////////////////////////////////////// Module Initialization and Shutdown///////////////////////////////////////////////////////////////////////////////* * usbctl_init() * Module load time. Allocate dma and interrupt resources. Setup /proc fs * entry. Leave UDC disabled. */int __init usbctl_init( void ){ int retval = 0; udc_disable(); memset( &usbd_info, 0, sizeof( usbd_info ) );#if CONFIG_PROC_FS create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL);#endif /* setup rx dma */ retval = sa1100_request_dma(&usbd_info.dmach_rx, "USB receive", DMA_Ser0UDCRd); if (retval) { printk("%sunable to register for rx dma rc=%d\n", pszMe, retval ); goto err_rx_dma; } /* setup tx dma */ retval = sa1100_request_dma(&usbd_info.dmach_tx, "USB transmit", DMA_Ser0UDCWr); if (retval) { printk("%sunable to register for tx dma rc=%d\n",pszMe,retval); goto err_tx_dma; } /* now allocate the IRQ. */ retval = request_irq(IRQ_Ser0UDC, udc_int_hndlr, SA_INTERRUPT, "SA USB core", NULL); if (retval) { printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval); goto err_irq; } printk( "SA1100 USB Controller Core Initialized\n"); return 0;err_irq: sa1100_free_dma(usbd_info.dmach_tx); usbd_info.dmach_tx = 0;err_tx_dma: sa1100_free_dma(usbd_info.dmach_rx); usbd_info.dmach_rx = 0;err_rx_dma: return retval;}/* * usbctl_exit() * Release DMA and interrupt resources */void __exit usbctl_exit( void ){ printk("Unloading SA1100 USB Controller\n"); udc_disable();#if CONFIG_PROC_FS remove_proc_entry ( PROC_NODE_NAME, NULL);#endif sa1100_free_dma(usbd_info.dmach_rx); sa1100_free_dma(usbd_info.dmach_tx); free_irq(IRQ_Ser0UDC, NULL);}EXPORT_SYMBOL( sa1100_usb_open );EXPORT_SYMBOL( sa1100_usb_start );EXPORT_SYMBOL( sa1100_usb_stop );EXPORT_SYMBOL( sa1100_usb_close );EXPORT_SYMBOL( sa1100_usb_get_descriptor_ptr );EXPORT_SYMBOL( sa1100_usb_set_string_descriptor );EXPORT_SYMBOL( sa1100_usb_get_string_descriptor );EXPORT_SYMBOL( sa1100_usb_kmalloc_string_descriptor );module_init( usbctl_init );module_exit( usbctl_exit );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -