⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_ctl.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
 /* *	Copyright (C) Compaq Computer Corporation, 1998, 1999 *  Copyright (C) Extenex Corporation, 2001 * *  usb_ctl.c * *  SA1100 USB controller core driver. * *  This file provides interrupt routing and overall coordination *  of the three endpoints in usb_ep0, usb_receive (1),  and usb_send (2). * *  Please see linux/Documentation/arm/SA1100/SA1100_USB for details. * */#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 <asm/mach-types.h>#include "sa1100_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 );static void soft_connect_hook( int enable );static void udc_disable(void);static void udc_enable(void);#if CONFIG_PROC_FS#define PROC_NODE_NAME "sausb"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 *//* 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;//////////////////////////////////////////////////////////////////////////////// Async//////////////////////////////////////////////////////////////////////////////static void core_kicker(void);static inline void enable_resume_mask_suspend( void );static inline void enable_suspend_mask_resume(void);static voidudc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs){  	__u32 status = Ser0UDCSR;	/* ReSeT Interrupt Request - UDC has been reset */	if ( status & UDCSR_RSTIR )	{		if ( usbctl_next_state_on_event( kEvReset ) != kError )		{			/* starting 20ms or so reset sequence now... */			printk("%sResetting\n", pszMe);			ep0_reset();  // just set state to idle			ep1_reset();  // flush dma, clear false stall			ep2_reset();  // flush dma, clear false stall		}		// mask reset ints, they flood during sequence, enable		// suspend and resume		Ser0UDCCR |= UDCCR_REM;    // mask reset		Ser0UDCCR &= ~(UDCCR_SUSIM | UDCCR_RESIM); // enable suspend and resume		UDC_flip(  Ser0UDCSR, status );	// clear all pending sources		return;		// <-- no reason to continue if resetting	}	// else we have done something other than reset, so be sure reset enabled	UDC_clear( Ser0UDCCR, UDCCR_REM );	/* RESume Interrupt Request */	if ( status & UDCSR_RESIR )	{		usbctl_next_state_on_event( kEvResume );		core_kicker();		enable_suspend_mask_resume();	}	/* SUSpend Interrupt Request */	if ( status & UDCSR_SUSIR )	{		usbctl_next_state_on_event( kEvSuspend );		enable_resume_mask_suspend();	}	UDC_flip(Ser0UDCSR, status); // clear all pending sources	if (status & UDCSR_EIR)		 ep0_int_hndlr();	if (status & UDCSR_RIR)		ep1_int_hndlr(status);	if (status & UDCSR_TIR)		ep2_int_hndlr(status);}static inline void enable_resume_mask_suspend( void ){	 int i = 0;	 while( 1 ) {		  Ser0UDCCR |= UDCCR_SUSIM; // mask future suspend events		  udelay( i );		  if ( (Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR) )			   break;		  if ( ++i == 50 ) {			   printk( "%senable_resume(): Could not set SUSIM %8.8X\n",					   pszMe, Ser0UDCCR );			   break;		  }	 }	 i = 0;	 while( 1 ) {		  Ser0UDCCR &= ~UDCCR_RESIM;		  udelay( i );		  if ( ( Ser0UDCCR & UDCCR_RESIM ) == 0			   ||			   (Ser0UDCSR & UDCSR_RSTIR)			 )			   break;		  if ( ++i == 50 ) {			   printk( "%senable_resume(): Could not clear RESIM %8.8X\n",					   pszMe, Ser0UDCCR );			   break;		  }	 }}static inline void enable_suspend_mask_resume(void){	 int i = 0;	 while( 1 ) {		  Ser0UDCCR |= UDCCR_RESIM; // mask future resume events		  udelay( i );		  if ( Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR) )			   break;		  if ( ++i == 50 ) {			   printk( "%senable_suspend(): Could not set RESIM %8.8X\n",					   pszMe, Ser0UDCCR );			   break;		  }	 }	 i = 0;	 while( 1 ) {		  Ser0UDCCR &= ~UDCCR_SUSIM;		  udelay( i );		  if ( ( Ser0UDCCR & UDCCR_SUSIM ) == 0			   ||			   (Ser0UDCSR & UDCSR_RSTIR)			 )			   break;		  if ( ++i == 50 ) {			   printk( "%senable_suspend(): Could not clear SUSIM %8.8X\n",					   pszMe, Ser0UDCCR );			   break;		  }	 }}//////////////////////////////////////////////////////////////////////////////// Public Interface///////////////////////////////////////////////////////////////////////////////* Open SA usb core on behalf of a client, but don't start running */intsa1100_usb_open( const char * client ){	 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 */	 sm_state = kStateZombieSuspend;	 usbd_info.state = USB_STATE_SUSPENDED;	 /* create descriptors for enumeration */	 initialize_descriptors();	 printk( "%sOpened for %s\n", pszMe, client );	 return 0;}/* Start running. Must have called usb_open (above) first */intsa1100_usb_start( void ){	 if ( usbd_info.client_name == NULL ) {		  printk( "%s%s - no client registered\n",				  pszMe, __FUNCTION__ );		  return -EPERM;	 }	 /* start UDC internal machinery running */	 udc_enable();	 udelay( 100 );	 /* clear stall - receiver seems to start stalled? 19Jan01ww */	 /* also clear other stuff just to be thurough 22Feb01ww */	 UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC );	 UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC );	 /* mask everything */	 Ser0UDCCR = 0xFC;	 /* flush DMA and fire through some -EAGAINs */	 ep1_init( usbd_info.dmach_rx );	 ep2_init( usbd_info.dmach_tx );	 /* give endpoint notification we are starting */	 ep1_state_change_notify( USB_STATE_SUSPENDED );	 ep2_state_change_notify( USB_STATE_SUSPENDED );	 /* enable any platform specific hardware */	 soft_connect_hook( 1 );	/* clear all top-level sources */	 Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR   |		         UDCSR_RIR   | UDCSR_TIR   | UDCSR_SUSIR ;	 /* EXERIMENT - a short line in the spec says toggling this	  ..bit diddles the internal state machine in the udc to	  ..expect a suspend */	 Ser0UDCCR  |= UDCCR_RESIM;	 /* END EXPERIMENT 10Feb01ww */	 /* enable any platform specific hardware */	 soft_connect_hook( 1 );	 /* enable interrupts. If you are unplugged you will	    immediately get a suspend interrupt. If you are plugged	    and have a soft connect-circuit, you will get a reset        If you are plugged without a soft-connect, I think you	    also get suspend. In short, start with suspend masked	    and everything else enabled */	 UDC_write( Ser0UDCCR, UDCCR_SUSIM );	 printk( "%sStarted for %s\n", pszMe, usbd_info.client_name );	 return 0;}/* Stop USB core from running */intsa1100_usb_stop( void ){	 if ( usbd_info.client_name == NULL ) {		  printk( "%s%s - no client registered\n",				  pszMe, __FUNCTION__ );		  return -EPERM;	 }	 /* mask everything */	 Ser0UDCCR = 0xFC;	 ep1_reset();	 ep2_reset();	 udc_disable();	 printk( "%sStopped\n", pszMe );	 return 0;}/* Tell SA core client is through using it */intsa1100_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;	 printk( "%sClosed\n", pszMe );	 return 0;}/* set a proc to be called when device is configured */usb_notify_t sa1100_set_configured_callback( usb_notify_t func ){	 usb_notify_t retval = configured_callback;	 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 *sa1100_usb_get_descriptor_ptr( void ) { return &desc; }/* optional: set a string descriptor */intsa1100_usb_set_string_descriptor( int i, string_desc_t * p ){	 int retval;	 if ( i < MAX_STRING_DESC ) {		  string_desc_array[i] = p;		  retval = 0;	 } else {		  retval = -EINVAL;	 }	 return retval;}/* optional: get a previously set string descriptor */string_desc_t *sa1100_usb_get_string_descriptor( int i ){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -