📄 usb.c
字号:
/* * (C) Copyright 2001 * Denis Peter, MPL AG Switzerland * * Most of this source has been derived from the Linux USB * project. * * 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>#if (CONFIG_COMMANDS & CFG_CMD_USB)#include <usb.h>#ifdef CONFIG_4xx#include <405gp_pci.h>#endif/* #define 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;/********************************************************************** * 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(); return 0; } else { printf("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){ 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; ifno=-1; epno=-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: 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; unsigned short status; 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; result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp, &status, sizeof(status), USB_CNTL_TIMEOUT * 3); if (result < 0) return result; USB_PRINTF("usb_clear_halt: status 0x%x\n",status); if (status & 1) return -1; /* still halted */ 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -