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

📄 usb_ctl_pxa.c

📁 LUBBOCK板的BLOB
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *  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 DEBUG
static 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 16
static string_desc_t * string_desc_array[ MAX_STRING_DESC ];
static string_desc_t sd_zero;  /* special sd_zero holds language codes */

// called when configured
static 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 sus
USB_STATE_DEFAULT, USB_STATE_SUSPENDED,
//  addr              addr sus         
USB_STATE_ADDRESS, USB_STATE_SUSPENDED, 
//  config            config sus
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
//////////////////////////////////////////////////////////////////////////////

/* 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);
}

void
udc_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 */

int
pxa_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 */
int
pxa_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 */
int
pxa_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 + -