📄 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>#if (CONFIG_COMMANDS & CFG_CMD_USB)#include <usb.h>#ifdef CONFIG_4xx#include <405gp_pci.h>#endif#undef USB_DEBUG#ifdef USB_DEBUG#define USB_PRINTF(fmt,args...) printf (fmt ,##args)#else#define USB_PRINTF(fmt,args...)#endif#define USB_BUFSIZ 512static struct usb_device usb_dev[USB_MAX_DEVICE];static int dev_index;static int running;static int asynch_allowed;static struct devrequest setup_packet;char usb_started; /* flag for the started/stopped USB status *//********************************************************************** * some forward declerations... */void usb_scan_devices(void);int usb_hub_probe(struct usb_device *dev, int ifnum);void usb_hub_reset(void);/*********************************************************************** * wait_ms */void __inline__ wait_ms(unsigned long ms){ while(ms-->0) udelay(1000);}/*************************************************************************** * Init USB Device */int usb_init(void){ int result; running=0; dev_index=0; asynch_allowed=1; usb_hub_reset(); /* init low_level USB */ printf("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) { printf("scanning bus for devices... "); running=1; usb_scan_devices(); usb_started = 1; return 0; } else { printf("Error, couldn't init Lowlevel part\n"); usb_started = 0; return -1; }}/****************************************************************************** * Stop USB this stops the LowLevel Part and deregisters USB devices. */int usb_stop(void){ asynch_allowed=1; usb_started = 0; 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){ 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\n", request,requesttype,value,index,size); 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, curr_if_num; int i; unsigned char *ch; ifno = -1; epno = -1; curr_if_num = -1; dev->configno = cfgno; head = (struct usb_descriptor_header *) &buffer[0]; if(head->bDescriptorType != USB_DT_CONFIG) { printf(" 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: if(((struct usb_interface_descriptor *) &buffer[index])-> bInterfaceNumber != curr_if_num) { /* this is a new interface, copy new desc */ ifno = dev->config.no_of_if; dev->config.no_of_if++; memcpy(&dev->config.if_desc[ifno], &buffer[index], buffer[index]); dev->config.if_desc[ifno].no_of_ep = 0; dev->config.if_desc[ifno].num_altsetting = 1; curr_if_num = dev->config.if_desc[ifno].bInterfaceNumber; } else { /* found alternate setting for the interface */ dev->config.if_desc[ifno].num_altsetting++; } 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); { 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); if (result < 8) { if (result < 0) printf("unable to get descriptor, error %lX\n",dev->status); else printf("config descriptor too short (expected %i, got %i)\n",8,result); return -1; } tmp=swap_16(config->wTotalLength); if (tmp > USB_BUFSIZ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -