📄 usb_ctl_pxa.c
字号:
/* * Copyright (C) Compaq Computer Corporation, 1998, 1999 * Copyright (C) Extenex Corporation, 2001 * Copyright (C) Intrinsyc, Inc., 2002 * * PXA USB controller core driver. * * This file provides interrupt routing and overall coordination * of the endpoints. * * Please see: * linux/Documentation/arm/SA1100/SA1100_USB * for more info. * * 02-May-2002 * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c * */#ifdef HAVE_CONFIG_H# include <blob/config.h>#endif#include <blob/arch.h>#include <blob/init.h>#include <blob/types.h>#include <blob/time.h>#include "linux/errno.h"#include "pxa_usb.h"#include "usb_ctl_pxa.h"//#define DEBUG 1#if DEBUGstatic unsigned int usb_debug = DEBUG;#else#define usb_debug 0 /* gcc will remove all the debug code for us */#endif//////////////////////////////////////////////////////////////////////////////// Prototypes//////////////////////////////////////////////////////////////////////////////int usbctl_next_state_on_event( int event );void udc_int_hndlr(int, void *);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 "driver/pxausb"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 16static 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};/* * FIXME: The PXA UDC handles several host device requests without user * notification/intervention. The table could be collapsed quite a bit... */static int device_state_machine[8][6] = {// suspend reset resume adddr config deconfig/* zombie */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError },/* zom sus */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError },/* default */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kStateAddr, kStateConfig, kError },/* def sus */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kError , kError , kError },/* addr */ { kStateAddrSuspend , kStateDefault, kStateAddr , kError , kStateConfig, kError },/* addr sus */{ kStateAddrSuspend , kStateDefault, kStateAddr , kError , kError , kError },/* config */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError , kError , kStateDefault },/* cfg sus */ { kStateConfigSuspend , 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 USB_STATE_POWERED, USB_STATE_SUSPENDED, // default default susUSB_STATE_DEFAULT, USB_STATE_SUSPENDED,// addr addr sus USB_STATE_ADDRESS, USB_STATE_SUSPENDED, // config config susUSB_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///////////////////////////////////////////////////////////////////////////////* The UDCCR reg contains mask and interrupt status bits, * so using '|=' isn't safe as it may ack an interrupt. */void udc_set_mask_UDCCR( int mask ){ UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);}void udc_clear_mask_UDCCR( int mask){ UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);}void udc_ack_int_UDCCR( int mask){ /* udccr contains the bits we dont want to change */ __u32 udccr = UDCCR & UDCCR_MASK_BITS; UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);}voidudc_int_hndlr(int irq, void *dev_id){ __u32 status = UDCCR; __u32 ir0_status = USIR0; __u32 ir1_status = USIR1; __u32 uicr0 = UICR0; __u32 uicr1 = UICR1; //mask ints udc_set_mask_UDCCR( UDCCR_REM | UDCCR_SRM); UICR0 = 0xff; UICR1 = 0xff; //SerialOutputString("in udc_int_hndlr\n"); if( usb_debug > 2) { /* printk("%s--- udc_int_hndlr\n" "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n" "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", pszMe, status, UDCCS0, UDCCS1, UDCCS2, ir0_status, ir1_status, uicr0, uicr1); */ } /* SUSpend Interrupt Request */ if ( status & UDCCR_SUSIR ) { udc_ack_int_UDCCR( UDCCR_SUSIR); //SerialOutputString("suspend irq\n"); //if( usb_debug) printk("%sSuspend...\n", pszMe); usbctl_next_state_on_event( kEvSuspend ); } /* RESume Interrupt Request */ if ( status & UDCCR_RESIR ) { //SerialOutputString("resume irq\n"); udc_ack_int_UDCCR( UDCCR_RESIR); //if( usb_debug) printk("%sResume...\n", pszMe); usbctl_next_state_on_event( kEvResume ); } /* ReSeT Interrupt Request - UDC has been reset */ if ( status & UDCCR_RSTIR ) { //SerialOutputString("reset irq\n"); /* clear the reset interrupt */ udc_ack_int_UDCCR( UDCCR_RSTIR); /* check type of reset */ if( (UDCCR & UDCCR_UDA) == 0) { /* reset assertion took place, nothing to do */ //if( usb_debug) printk("%sReset assertion...\n", pszMe); //SerialOutputString("Reset assertion\n"); } /* ok, it's a reset negation, go on with reset */ else if ( usbctl_next_state_on_event( kEvReset ) != kError ) { /* starting reset sequence now... */ //if( usb_debug) printk("%sResetting\n", pszMe); //SerialOutputString("Resetting\n"); ep0_reset(); ep1_reset(); ep2_reset(); usbctl_next_state_on_event( kEvConfig ); /* reset driver */ usb_driver_reset(); } else { //printk("%sUnexpected reset\n", pszMe); SerialOutputString("unexpected reset\n"); } } else { /* ep0 int */ if (ir0_status & USIR0_IR0) { //SerialOutputString("ep0 int\n"); ep0_int_hndlr(); } /* transmit bulk */ if (ir0_status & USIR0_IR1) { //SerialOutputString("ep1/in int\n"); ep1_int_hndlr(ir0_status); } /* receive bulk */ if ( ir0_status & USIR0_IR2) { //SerialOutputString("ep1/out int\n"); ep2_int_hndlr(ir0_status); } while (UDCCS2 & UDCCS_BO_RNE) { //if( usb_debug) printk("More Bulk-out data...\n"); ep2_int_hndlr(ir0_status); } } UICR0 = uicr0; UICR1 = uicr1; udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); /* enable suspend/resume, reset */ /* clear all endpoint ints */ USIR0 |= 0xff; USIR1 |= 0xff; if( usb_debug > 2) { /* printk("%sudc_int_hndlr\n" "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n" "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", pszMe, UDCCR, UDCCS0, UDCCS1, UDCCS2, USIR0, USIR1, UICR0, UICR1); */ } //SerialOutputString("exit interrupt\n");}//////////////////////////////////////////////////////////////////////////////// Public Interface///////////////////////////////////////////////////////////////////////////////* Open PXA usb core on behalf of a client, but don't start running */intpxa_usb_open( const char * client ){ if ( usbd_info.client_name != NULL ) { /* printk( "%sUnable to register %s (%s already registered).\n", pszMe, client, usbd_info.client_name ); */ SerialOutputString("pxa_usb_open failed\n"); 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( "%s%s registered.\n", pszMe, client ); return 0;}/* Start running. Must have called usb_open (above) first */intpxa_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 ); msleep(1); /* flush DMA and fire through some -EAGAINs */ //ep2_init( usbd_info.dmach_rx ); //ep1_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 ); /* enable suspend/resume, reset */ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); /* enable ep0, ep1, ep2 */ UICR0 &= ~(UICR0_IM0 | UICR0_IM1 | UICR0_IM2) ; //if( usb_debug) printk( "%sStarted %s\n", pszMe, usbd_info.client_name ); return 0;}/* Stop USB core from running */intpxa_usb_stop( void ){ if ( usbd_info.client_name == NULL ) { /* printk( "%s%s - no client registered\n", pszMe, __FUNCTION__ ); */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -