📄 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "..\hardware\LPC2468.h" /* 24xx Peripheral Registers */
#include "..\rtxOS\rtl.h"
#include "usb.h"
#define USB_PRINTF(fmt,args...)
void os_dly_waitms(unsigned int ms);
#define USB_BUFSIZ 512
struct usb_device usb_dev[USB_MAX_DEVICE];
static int asynch_allowed;
static struct devrequest setup_packet;
char usb_started; /* flag for the started/stopped USB status */
int usb_get_port_status(struct usb_device *dev, int port, void *data);
void usb_hub_port_connect_change(struct usb_device *dev, int port);
int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
static void usb_hub_power_on(struct usb_hub_device *hub);
static struct usb_hub_device hub_dev[USB_MAX_HUB];
static int usb_hub_index;
/**********************************************************************
* some forward declerations...
*/
void usb_scan_devices(void);
int usb_hub_probe(struct usb_device *dev, int ifnum);
void usb_hub_reset(void);
int usb_stor_exists(void);
unsigned char get_usb_state( void )
{unsigned char state = 0;
if(! usb_stor_exists())
{ state |= (1<<2); }
return state;
}
void usb_device_clear_all( void )
{unsigned char i;
/* New Device %d\n",dev_index); */
for(i=0; i<USB_MAX_DEVICE; i++)
{ memset(&usb_dev[i], 0, sizeof(struct usb_device));
}
}
/***************************************************************************
* Init USB Device
*/
int usb_init(void)
{
int result;
//s_SetIRQHandler(INT_USBH,hc_interrupt_irq );
usb_device_clear_all();
asynch_allowed = 1;
usb_hub_reset();
/* init low_level 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)
{ usb_scan_devices();
usb_started = 1;
return 0;
}
else
{ usb_started = 0;
return -1; /* Error, couldn't init Lowlevel part\n" */
}
}
int usb_scan(void)
{
struct usb_port_status portsts;
unsigned short portstatus, portchange;
struct usb_device *dev;
struct usb_hub_device *hub;
unsigned char i, hi;
unsigned char bchange = 0;
if(usb_started == 0) return 0;
if(usb_hub_index == 0) return 0;
for(hi=0; hi<usb_hub_index; hi++)
{ hub = &hub_dev[hi];
dev = hub->pusb_dev;
for (i = 0; i < dev->maxchild; i++)
{ if(usb_get_port_status(dev, i + 1, &portsts) < 0)
{ continue; /* get_port_status failed! */
}
portstatus = swap_16(portsts.wPortStatus);
portchange = swap_16(portsts.wPortChange);
/* Port %d Status %X Change %X\n",i+1,portstatus,portchange); */
if (portchange & USB_PORT_STAT_C_CONNECTION)
{ bchange = 1;
usb_hub_port_connect_change(dev, i);
}
if (portchange & USB_PORT_STAT_C_ENABLE)
{
usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
/* EM interference sometimes causes bad shielded USB devices to
* be shutdown by the hub, this hack enables them again.
* Works at least with mouse driver */
if (!(portstatus & USB_PORT_STAT_ENABLE) &&
(portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i]))
{ bchange = 1;
usb_hub_port_connect_change(dev, i);
}
}
if (portstatus & USB_PORT_STAT_SUSPEND)
{
usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT)
{
usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
usb_hub_power_on(hub);
}
if (portchange & USB_PORT_STAT_C_RESET)
{
usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
}
}
}
if(usb_started == 0) return 0;
if(usb_hub_index == 0) return 0;
return bchange;
}
/******************************************************************************
* 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);
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(!(dev->status & USB_ST_NOT_PROC))
{ break; }
os_dly_waitms(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(!(dev->status & USB_ST_NOT_PROC))
{ break; }
os_dly_waitms(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;
}
else
{ if((ep->bEndpointAddress & 0x80) == 0)
{ /* OUT Endpoint */
if(ep->wMaxPacketSize > dev->epmaxpacketout[b])
{ dev->epmaxpacketout[b] = ep->wMaxPacketSize; }
}
else
{ /* IN Endpoint */
if(ep->wMaxPacketSize > dev->epmaxpacketin[b])
{ dev->epmaxpacketin[b] = ep->wMaxPacketSize; }
}
/* 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;
//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; }
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -