📄 usb.c
字号:
/*
*
* Most of this source has been derived from the Linux USB
* project:
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
* (C) Copyright Randy Dunlap 2000
* (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
* (C) Copyright Yggdrasil Computing, Inc. 2000
* (usb_device_id matching changes by Adam J. Richter)
*
* Adapted for U-Boot:
* (C) Copyright 2001 Denis Peter, MPL AG Switzerland
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/*
* How it works:
*
* Since this is a bootloader, the devices will not be automatic
* (re)configured on hotplug, but after a restart of the USB the
* device should work.
*
* For each transfer (except "Interrupt") we wait for completion.
*/
//#include <common.h>
//#include <command.h>
//#include <asm/processor.h>
//#include <linux/ctype.h>
#include "usb.h"
#include "base.h"
#include "s3c2410.h"
//#undef USB_DEBUG
#define USB_DEBUG
#ifdef USB_DEBUG
#define USB_PRINTF s_UartPrint
#else
#define USB_PRINTF()
#endif
#define USB_BUFSIZ 512
static struct usb_device usb_dev[USB_MAX_DEVICE];
static int dev_index;
static int running;
static int asynch_allowed;
static struct devrequest setup_packet;
//extern void hc_interrupt_irq (void);
/**********************************************************************
* some forward declerations...
*/
void usb_scan_devices(void);
int usb_hub_probe(struct usb_device *dev, int ifnum);
void usb_hub_reset(void);
void udelay (unsigned long usec)
{
unsigned long j,i;
//for(i=0;i<50;i++);
j=usec/1000;
for(i=0;i<j;i++)
{
rINTMSK |= (1<<13);
rTCON &= ~(0x0f<<16); //stop timer3
rSRCPND = (1<<13);
rTCNTB3 = 2028; //1ms=2028
rTCMPB3=0;
rTCON &= ~(0x0f<<16); //STOP TIMER 3
rTCON |= (0x02<<16); // AUTOLOAD=0 update=1
rTCON &= ~(1<<17); //CLEAR MANUAL UPDATE BIT
rTCON |= (1<<16); //START
while((rSRCPND & (1<<13))==0);
rSRCPND = (1<<13);
}
}
/***********************************************************************
* wait_ms
*/
void __inline wait_ms(unsigned long ms)
{
while(ms-->0)
udelay(1000);
}
void TestWaitMs(void)
{
int i,j;
s_UartPrint("Test Wait Ms... Any Key to Start...\n");
s_getkey();
j=0;
for(i=0;i<120;i++)
{
s_UartPrint("j=%d sec\n",j);
wait_ms(1000);
j++;
}
}
/***************************************************************************
* Init USB Device
*/
int usb_init(void)
{
int result;
//s_SetIRQHandler(INT_USBH,hc_interrupt_irq );
running=0;
dev_index=0;
asynch_allowed=1;
usb_hub_reset();
/* init low_level USB */
//s_UartPrint("USB: ");
result = usb_lowlevel_init();
/* if lowlevel init is OK, scan the bus for devices i.e. search HUBs and configure them */
if(result==0)
{
running=1;
usb_scan_devices();
return 0;
}
else
{
s_UartPrint("Error, couldn't init Lowlevel part\n");
return -1;
}
}
/******************************************************************************
* Stop USB this stops the LowLevel Part and deregisters USB devices.
*/
int usb_stop(void)
{
asynch_allowed=1;
usb_hub_reset();
return usb_lowlevel_stop();
}
/*
* disables the asynch behaviour of the control message. This is used for data
* transfers that uses the exclusiv access to the control and bulk messages.
*/
void usb_disable_asynch(int disable)
{
asynch_allowed=!disable;
}
/*-------------------------------------------------------------------
* Message wrappers.
*
*/
/*
* submits an Interrupt Message
*/
int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
void *buffer,int transfer_len, int interval)
{
return submit_int_msg(dev,pipe,buffer,transfer_len,interval);
}
/*
* submits a control message and waits for comletion (at least timeout * 1ms)
* If timeout is 0, we don't wait for completion (used as example to set and
* clear keyboards LEDs). For data transfers, (storage transfers) we don't
* allow control messages with 0 timeout, by previousely resetting the flag
* asynch_allowed (usb_disable_asynch(1)).
* returns the transfered length if OK or -1 if error. The transfered length
* and the current status are stored in the dev->act_len and dev->status.
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
unsigned char request, unsigned char requesttype,
unsigned short value, unsigned short index,
void *data, unsigned short size, int timeout)
{
//s_UartPrint("asynch_allowed=%d",asynch_allowed);
if((timeout==0)&&(!asynch_allowed)) /* request for a asynch control pipe is not allowed */
return -1;
/* set setup command */
setup_packet.requesttype = requesttype;
setup_packet.request = request;
setup_packet.value = swap_16(value);
setup_packet.index = swap_16(index);
setup_packet.length = swap_16(size);
USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X\nvalue 0x%X index 0x%X length 0x%X pipe 0x%X \n",
request,requesttype,value,index,size,pipe);
dev->status=USB_ST_NOT_PROC; /*not yet processed */
submit_control_msg(dev,pipe,data,size,&setup_packet);
if(timeout==0)
{
return (int)size;
}
while(timeout--)
{
if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
break;
wait_ms(1);
}
if(dev->status==0)
return dev->act_len;
else
{
return -1;
}
}
/*-------------------------------------------------------------------
* submits bulk message, and waits for completion. returns 0 if Ok or
* -1 if Error.
* synchronous behavior
*/
int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
if (len < 0)
return -1;
dev->status=USB_ST_NOT_PROC; /*not yet processed */
submit_bulk_msg(dev,pipe,data,len);
while(timeout--)
{
if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
break;
wait_ms(1);
}
*actual_length=dev->act_len;
if(dev->status==0)
return 0;
else
return -1;
}
/*-------------------------------------------------------------------
* Max Packet stuff
*/
/*
* returns the max packet size, depending on the pipe direction and
* the configurations values
*/
int usb_maxpacket(struct usb_device *dev,unsigned long pipe)
{
if((pipe & USB_DIR_IN)==0) /* direction is out -> use emaxpacket out */
return(dev->epmaxpacketout[((pipe>>15) & 0xf)]);
else
return(dev->epmaxpacketin[((pipe>>15) & 0xf)]);
}
/*
* set the max packed value of all endpoints in the given configuration
*/
int usb_set_maxpacket(struct usb_device *dev)
{
int i,ii,b;
struct usb_endpoint_descriptor *ep;
for(i=0; i<dev->config.bNumInterfaces;i++)
{
for(ii=0; ii<dev->config.if_desc[i].bNumEndpoints; ii++)
{
ep=&dev->config.if_desc[i].ep_desc[ii];
b=ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_CONTROL)
{
/* Control => bidirectional */
dev->epmaxpacketout[b] = ep->wMaxPacketSize;
dev->epmaxpacketin [b] = ep->wMaxPacketSize;
USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",b,dev->epmaxpacketin[b]);
}
else
{
if ((ep->bEndpointAddress & 0x80)==0)
{
/* OUT Endpoint */
if(ep->wMaxPacketSize > dev->epmaxpacketout[b])
{
dev->epmaxpacketout[b] = ep->wMaxPacketSize;
USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",b,dev->epmaxpacketout[b]);
}
}
else
{
/* IN Endpoint */
if(ep->wMaxPacketSize > dev->epmaxpacketin[b])
{
dev->epmaxpacketin[b] = ep->wMaxPacketSize;
USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",b,dev->epmaxpacketin[b]);
}
}
/* if out */
}
/* if control */
}
/* for each endpoint */
}
return 0;
}
/*******************************************************************************
* Parse the config, located in buffer, and fills the dev->config structure.
* Note that all little/big endian swapping are done automatically.
*/
int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno)
{
struct usb_descriptor_header *head;
int index,ifno,epno;
ifno=-1;
epno=-1;
dev->configno=cfgno;
head =(struct usb_descriptor_header *)&buffer[0];
if(head->bDescriptorType!=USB_DT_CONFIG)
{
s_UartPrint(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
return -1;
}
memcpy(&dev->config,buffer,buffer[0]);
dev->config.wTotalLength=swap_16(dev->config.wTotalLength);
dev->config.no_of_if=0;
index=dev->config.bLength;
/* Ok the first entry must be a configuration entry, now process the others */
head=(struct usb_descriptor_header *)&buffer[index];
while(index+1 < dev->config.wTotalLength)
{
switch(head->bDescriptorType)
{
case USB_DT_INTERFACE:
ifno=dev->config.no_of_if;
dev->config.no_of_if++; /* found an interface desc, increase numbers */
memcpy(&dev->config.if_desc[ifno],&buffer[index],buffer[index]); /* copy new desc */
dev->config.if_desc[ifno].no_of_ep=0;
break;
case USB_DT_ENDPOINT:
epno=dev->config.if_desc[ifno].no_of_ep;
dev->config.if_desc[ifno].no_of_ep++; /* found an endpoint */
memcpy(&dev->config.if_desc[ifno].ep_desc[epno],&buffer[index],buffer[index]);
dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize
=swap_16(dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize);
USB_PRINTF("if %d, ep %d\n",ifno,epno);
break;
default:
if(head->bLength==0)
return 1;
USB_PRINTF("unknown Description Type : %x\n",head->bDescriptorType);
{
int i;
unsigned char *ch;
ch=(unsigned char *)head;
for(i=0;i<head->bLength; i++)
USB_PRINTF("%02X ",*ch++);
USB_PRINTF("\n\n\n");
}
break;
}
index+=head->bLength;
head=(struct usb_descriptor_header *)&buffer[index];
}
return 1;
}
/***********************************************************************
* Clears an endpoint
* endp: endpoint number in bits 0-3;
* direction flag in bit 7 (1 = IN, 0 = OUT)
*/
int usb_clear_halt(struct usb_device *dev, int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
/* don't clear if failed */
if (result < 0)
return result;
/*
* NOTE: we do not get status and verify reset was successful
* as some devices are reported to lock up upon this check..
*/
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
/* toggle is reset on clear */
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
return 0;
}
/**********************************************************************
* get_descriptor type
*/
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{
int res;
res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(type << 8) + index, 0,
buf, size, USB_CNTL_TIMEOUT);
return res;
}
/**********************************************************************
* gets configuration cfgno and store it in the buffer
*/
int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cfgno)
{
int result;
unsigned int tmp;
struct usb_config_descriptor *config;
config=(struct usb_config_descriptor *)&buffer[0];
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -