📄 usb_ep0_pxa.c
字号:
//SerialOutputString("GET_DESCRIPTOR\n");
get_descriptor( &req );
break;
case SET_INTERFACE:
//SerialOutputString("SET_INTERFACE\n");
//PRINTKD( "%sSET_INTERFACE TODO...\n", pszMe);
break;
case SET_DESCRIPTOR:
//SerialOutputString("SET_DESCRIPTOR\n");
//PRINTKD( "%sSET_DESCRIPTOR TODO...\n", pszMe );
break;
case SET_CONFIGURATION:
//SerialOutputString("SET_CONFIGURATION\n");
//PRINTKD( "%sSET_CONFIGURATION %d\n", pszMe, req.wValue);
/*
* FIXME: Something is not quite right here... I only ever get a
* de-configure from the host. Ignoring it for now, since usb
* ethernet won't do anything unless usb is 'configured'.
*
*/
#if 0
switch( req.wValue)
{
case 0:
/* configured */
usbctl_next_state_on_event( kEvConfig );
break;
case 1:
/* de-configured */
usbctl_next_state_on_event( kEvDeConfig );
break;
default:
PRINTKD( "%sSET_CONFIGURATION: unknown configuration value (%d)\n", pszMe, req.wValue);
break;
}
#endif
break;
default :
//printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
break;
} /* switch( bRequest ) */
sh_sb_end:
return;
}
/*
* sh_write()
*
* Due to UDC bugs we push everything into the fifo in one go.
* Using interrupts just didn't work right...
* This should be ok, since control request are small.
*/
static void sh_write()
{
//PRINTKD( "sh_write\n" );
do
{
write_fifo();
} while( ep0_state != EP0_END_XFER);
}
/***************************************************************************
Other Private Subroutines
***************************************************************************/
/*
* queue_and_start_write()
* data == data to send
* req == bytes host requested
* act == bytes we actually have
*
* Sets up the global "wr"-ite structure and load the outbound FIFO
* with data.
*
*/
static void queue_and_start_write( void * data, int req, int act )
{
//PRINTKD( "write start: bytes requested=%d actual=%d\n", req, act);
wr.p = (unsigned char*) data;
wr.bytes_left = MIN( act, req );
ep0_state = EP0_IN_DATA_PHASE;
sh_write();
return;
}
/*
* write_fifo()
* Stick bytes in the endpoint zero FIFO.
*
*/
static void write_fifo( void )
{
int bytes_this_time = MIN( wr.bytes_left, EP0_FIFO_SIZE );
int bytes_written = 0;
//SerialOutputString("in write_fifo\n");
while( bytes_this_time-- ) {
// PRINTKD( "%2.2X ", *wr.p );
UDDR0 = *wr.p++;
bytes_written++;
}
wr.bytes_left -= bytes_written;
usbd_info.stats.ep0_bytes_written += bytes_written;
if( (wr.bytes_left==0))
{
wr.p = 0; /* be anal */
if(bytes_written < EP0_FIFO_SIZE)
{
int count;
int udccs0;
/* We always end the transfer with a short or zero length packet */
ep0_state = EP0_END_XFER;
current_handler = sh_setup_begin;
/* Let the packet go... */
UDCCS0 = UDCCS0_IPR;
/* Wait until we get to status-stage, then ack.
*
* When the UDC sets the UDCCS0[OPR] bit, an interrupt
* is supposed to be generated (see 12.5.1 step 14ff, PXA Dev Manual).
* That approach didn't work out. Usually a new SETUP command was
* already in the fifo. I tried many approaches but was always losing
* at least some OPR interrupts. Thus the polling below...
*/
count = 1000;
udccs0 = UDCCS0;
do
{
if( (UDCCS0 & UDCCS0_OPR))
{
/* clear OPR, generate ack */
UDCCS0 = UDCCS0_OPR;
break;
}
count--;
msleep(1);
//udelay(1);
} while( count);
PRINTKD( "write fifo: count=%d UDCCS0=%x UDCCS0=%x\n", count, udccs0, UDCCS0);
}
}
/* something goes poopy if I dont wait here ... */
msleep(1);
//udelay(500);
//PRINTKD( "write fifo: bytes sent=%d, bytes left=%d\n", bytes_written, wr.bytes_left);
}
/*
* read_fifo()
* Read bytes out of FIFO and put in request.
* Called to do the initial read of setup requests
* from the host. Return number of bytes read.
*
*/
static int read_fifo( usb_dev_request_t * request )
{
int bytes_read = 0;
unsigned char * pOut = (unsigned char*) request;
int udccs0 = UDCCS0;
if( (udccs0 & SETUP_READY) == SETUP_READY)
{
/* ok it's a setup command */
while( UDCCS0 & UDCCS0_RNE)
{
if( bytes_read >= sizeof( usb_dev_request_t))
{
/* We've already read enought o fill usb_dev_request_t.
* Our tummy is full. Go barf...
*/
//printk( "%sread_fifo(): read failure\n", pszMe );
usbd_info.stats.ep0_fifo_read_failures++;
break;
}
*pOut++ = UDDR0;
bytes_read++;
}
}
//PRINTKD( "read_fifo %d bytes\n", bytes_read );
/* clear SA & OPR */
UDCCS0 = SETUP_READY;
usbd_info.stats.ep0_bytes_read += bytes_read;
return bytes_read;
}
/*
* get_descriptor()
* Called from sh_setup_begin to handle data return
* for a GET_DESCRIPTOR setup request.
*
* +-----+------------------------------------------------+-----------------+
* | dev | cfg1 | intf 1 | ep 1..N | intf 2 | ep 1..N |...| cfg2 .......... |
* +-----+------------------------------------------------+-----------------+
*/
static void get_descriptor( usb_dev_request_t * pReq )
{
string_desc_t * pString;
ep_desc_t * pEndpoint = 0;
config_desc_t *pcfg = 0;
desc_t * pDesc = pxa_usb_get_descriptor_ptr();
int type = pReq->wValue >> 8;
int idx = pReq->wValue & 0xFF;
// PRINTKD( "%sget_descriptor for %d\n", pszMe, type );
switch( type ) {
case USB_DESC_DEVICE:
/* return device descritpor */
queue_and_start_write( &pDesc->dev,
pReq->wLength,
pDesc->dev.bLength );
break;
// return config descriptor buffer, cfg, intf 1..N, ep 1..N
case USB_DESC_CONFIG:
{
int i,len;
config_desc_t *cfg =(config_desc_t*) (pDesc->cdb);
len=0;
for( i=0; i<pDesc->dev.bNumConfigurations; i++) {
len += __le16_to_cpu(cfg->wTotalLength);
cfg = (config_desc_t*) ( (unsigned char*) cfg
+ __le16_to_cpu(cfg->wTotalLength)) ;
}
queue_and_start_write( pDesc->cdb,
pReq->wLength,
len);
}
break;
// not quite right, since doesn't do language code checking
case USB_DESC_STRING:
pString = pxa_usb_get_string_descriptor( idx );
if ( pString ) {
if ( idx != 0 ) { // if not language index
//printk( "%sReturn string %d: ", pszMe, idx );
psdesc( pString );
}
queue_and_start_write( pString,
pReq->wLength,
pString->bLength );
}
else {
//printk("%sunkown string index %d Stall.\n", pszMe, idx );
}
break;
/*
case USB_DESC_INTERFACE:
for( i = 0; i < pDesc->intf_num; i++) {
if ( idx == pDesc->intf[i].bInterfaceNumber ) {
queue_and_start_write( &pDesc->intf[i],
pReq->wLength,
pDesc->intf[i].bLength );
}
}
break;
case USB_DESC_ENDPOINT:
for( i = 0; i < pDesc->ep_num; i++) {
if ( idx == (0x0F & pDesc->ep[i].bEndpointAddress)) {
queue_and_start_write( &pDesc->ep[i],
pReq->wLength,
pDesc->ep[i].bLength );
}
}
break;
*/
default :
//printk("%sunknown descriptor type %d. Stall.\n", pszMe, type );
break;
}
}
/* end usb_ep0.c - who needs this comment? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -