📄 usb-uhci.c
字号:
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; */
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
0x00, /* __u16 idVendor; */
0x00,
0x00, /* __u16 idProduct; */
0x00,
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
/* Configuration descriptor */
_static __u8 root_hub_config_des[] =
{
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, /* __u16 wTotalLength; */
0x00,
0x01, /* __u8 bNumInterfaces; */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
0x00, /* __u8 MaxPower; */
/* interface */
0x09, /* __u8 if_bLength; */
0x04, /* __u8 if_bDescriptorType; Interface */
0x00, /* __u8 if_bInterfaceNumber; */
0x00, /* __u8 if_bAlternateSetting; */
0x01, /* __u8 if_bNumEndpoints; */
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* __u8 if_bInterfaceSubClass; */
0x00, /* __u8 if_bInterfaceProtocol; */
0x00, /* __u8 if_iInterface; */
/* endpoint */
0x07, /* __u8 ep_bLength; */
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
0x00,
0xff /* __u8 ep_bInterval; 255 ms */
};
_static __u8 root_hub_hub_des[] =
{
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
0x00, /* __u16 wHubCharacteristics; */
0x00,
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
};
/*-------------------------------------------------------------------------*/
/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
_static int rh_send_irq (struct urb *urb)
{
int len = 1;
int i;
uhci_t *uhci = urb->dev->bus->hcpriv;
unsigned int io_addr = uhci->io_addr;
__u16 data = 0;
for (i = 0; i < uhci->rh.numports; i++) {
data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
len = (i + 1) / 8 + 1;
}
*(__u16 *) urb->transfer_buffer = cpu_to_le16 (data);
urb->actual_length = len;
urb->status = 0;
if ((data > 0) && (uhci->rh.send != 0)) {
dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
urb->complete (urb);
}
return 0;
}
/*-------------------------------------------------------------------------*/
/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
_static int rh_init_int_timer (struct urb *urb);
_static void rh_int_timer_do (unsigned long ptr)
{
int len;
struct urb *urb = (struct urb *) ptr;
uhci_t *uhci = urb->dev->bus->hcpriv;
if (uhci->rh.send) {
len = rh_send_irq (urb);
if (len > 0) {
urb->actual_length = len;
if (urb->complete)
urb->complete (urb);
}
}
rh_init_int_timer (urb);
}
/*-------------------------------------------------------------------------*/
/* Root Hub INTs are polled by this timer, polling interval 20ms */
_static int rh_init_int_timer (struct urb *urb)
{
uhci_t *uhci = urb->dev->bus->hcpriv;
uhci->rh.interval = urb->interval;
init_timer (&uhci->rh.rh_int_timer);
uhci->rh.rh_int_timer.function = rh_int_timer_do;
uhci->rh.rh_int_timer.data = (unsigned long) urb;
uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 1000;
add_timer (&uhci->rh.rh_int_timer);
return 0;
}
/*-------------------------------------------------------------------------*/
#define OK(x) len = (x); break
#define CLR_RH_PORTSTAT(x) \
status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
status = (status & 0xfff5) & ~(x); \
outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
#define SET_RH_PORTSTAT(x) \
status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
status = (status & 0xfff5) | (x); \
outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
/*-------------------------------------------------------------------------*/
/****
** Root Hub Control Pipe
*************************/
_static int rh_submit_urb (struct urb *urb)
{
struct usb_device *usb_dev = urb->dev;
uhci_t *uhci = usb_dev->bus->hcpriv;
unsigned int pipe = urb->pipe;
struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
void *data = urb->transfer_buffer;
int leni = urb->transfer_buffer_length;
int len = 0;
int status = 0;
int stat = 0;
int i;
unsigned int io_addr = uhci->io_addr;
__u16 cstatus;
__u16 bmRType_bReq;
__u16 wValue;
__u16 wIndex;
__u16 wLength;
if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
dbg("Root-Hub submit IRQ: every %d ms", urb->interval);
uhci->rh.urb = urb;
uhci->rh.send = 1;
uhci->rh.interval = urb->interval;
rh_init_int_timer (urb);
return 0;
}
bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
wValue = le16_to_cpu (cmd->wValue);
wIndex = le16_to_cpu (cmd->wIndex);
wLength = le16_to_cpu (cmd->wLength);
for (i = 0; i < 8; i++)
uhci->rh.c_p_r[i] = 0;
dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
switch (bmRType_bReq) {
/* Request Destination:
without flags: Device,
RH_INTERFACE: interface,
RH_ENDPOINT: endpoint,
RH_CLASS means HUB here,
RH_OTHER | RH_CLASS almost ever means HUB_PORT here
*/
case RH_GET_STATUS:
*(__u16 *) data = cpu_to_le16 (1);
OK (2);
case RH_GET_STATUS | RH_INTERFACE:
*(__u16 *) data = cpu_to_le16 (0);
OK (2);
case RH_GET_STATUS | RH_ENDPOINT:
*(__u16 *) data = cpu_to_le16 (0);
OK (2);
case RH_GET_STATUS | RH_CLASS:
*(__u32 *) data = cpu_to_le32 (0);
OK (4); /* hub power ** */
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
((status & USBPORTSC_PEC) >> (3 - 1)) |
(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
status = (status & USBPORTSC_CCS) |
((status & USBPORTSC_PE) >> (2 - 1)) |
((status & USBPORTSC_SUSP) >> (12 - 2)) |
((status & USBPORTSC_PR) >> (9 - 4)) |
(1 << 8) | /* power on ** */
((status & USBPORTSC_LSDA) << (-8 + 9));
*(__u16 *) data = cpu_to_le16 (status);
*(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
OK (4);
case RH_CLEAR_FEATURE | RH_ENDPOINT:
switch (wValue) {
case (RH_ENDPOINT_STALL):
OK (0);
}
break;
case RH_CLEAR_FEATURE | RH_CLASS:
switch (wValue) {
case (RH_C_HUB_OVER_CURRENT):
OK (0); /* hub power over current ** */
}
break;
case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
switch (wValue) {
case (RH_PORT_ENABLE):
CLR_RH_PORTSTAT (USBPORTSC_PE);
OK (0);
case (RH_PORT_SUSPEND):
CLR_RH_PORTSTAT (USBPORTSC_SUSP);
OK (0);
case (RH_PORT_POWER):
OK (0); /* port power ** */
case (RH_C_PORT_CONNECTION):
SET_RH_PORTSTAT (USBPORTSC_CSC);
OK (0);
case (RH_C_PORT_ENABLE):
SET_RH_PORTSTAT (USBPORTSC_PEC);
OK (0);
case (RH_C_PORT_SUSPEND):
/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
OK (0);
case (RH_C_PORT_OVER_CURRENT):
OK (0); /* port power over current ** */
case (RH_C_PORT_RESET):
uhci->rh.c_p_r[wIndex - 1] = 0;
OK (0);
}
break;
case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
switch (wValue) {
case (RH_PORT_SUSPEND):
SET_RH_PORTSTAT (USBPORTSC_SUSP);
OK (0);
case (RH_PORT_RESET):
SET_RH_PORTSTAT (USBPORTSC_PR);
uhci_wait_ms (10);
uhci->rh.c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT (USBPORTSC_PR);
udelay (10);
SET_RH_PORTSTAT (USBPORTSC_PE);
uhci_wait_ms (10);
SET_RH_PORTSTAT (0xa);
OK (0);
case (RH_PORT_POWER):
OK (0); /* port power ** */
case (RH_PORT_ENABLE):
SET_RH_PORTSTAT (USBPORTSC_PE);
OK (0);
}
break;
case RH_SET_ADDRESS:
uhci->rh.devnum = wValue;
OK (0);
case RH_GET_DESCRIPTOR:
switch ((wValue & 0xff00) >> 8) {
case (0x01): /* device descriptor */
len = min_t(unsigned int, leni,
min_t(unsigned int,
sizeof (root_hub_dev_des), wLength));
memcpy (data, root_hub_dev_des, len);
OK (len);
case (0x02): /* configuration descriptor */
len = min_t(unsigned int, leni,
min_t(unsigned int,
sizeof (root_hub_config_des), wLength));
memcpy (data, root_hub_config_des, len);
OK (len);
case (0x03): /* string descriptors */
len = usb_root_hub_string (wValue & 0xff,
uhci->io_addr, "UHCI",
data, wLength);
if (len > 0) {
OK(min_t(int, leni, len));
} else
stat = -EPIPE;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
root_hub_hub_des[2] = uhci->rh.numports;
len = min_t(unsigned int, leni,
min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
memcpy (data, root_hub_hub_des, len);
OK (len);
case RH_GET_CONFIGURATION:
*(__u8 *) data = 0x01;
OK (1);
case RH_SET_CONFIGURATION:
OK (0);
default:
stat = -EPIPE;
}
dbg("Root-Hub stat port1: %x port2: %x",
inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
urb->actual_length = len;
urb->status = stat;
urb->dev=NULL;
if (urb->complete)
urb->complete (urb);
return 0;
}
/*-------------------------------------------------------------------------*/
_static int rh_unlink_urb (struct urb *urb)
{
uhci_t *uhci = urb->dev->bus->hcpriv;
if (uhci->rh.urb==urb) {
dbg("Root-Hub unlink IRQ");
uhci->rh.send = 0;
del_timer (&uhci->rh.rh_int_timer);
}
return 0;
}
/*-------------------------------------------------------------------*/
/*
* Map status to standard result codes
*
* <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
* <dir_out> is True for output TDs and False for input TDs.
*/
_static int uhci_map_status (int status, int dir_out)
{
if (!status)
return 0;
if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */
return -EPROTO;
if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
if (dir_out)
return -ETIMEDOUT;
else
return -EILSEQ;
}
if (status & TD_CTRL_NAK) /* NAK */
return -ETIMEDOUT;
if (status & TD_CTRL_BABBLE) /* Babble */
return -EOVERFLOW;
if (status & TD_CTRL_DBUFERR) /* Buffer error */
return -ENOSR;
if (status & TD_CTRL_STALLED) /* Stalled */
return -EPIPE;
if (status & TD_CTRL_ACTIVE) /* Active */
return 0;
return -EPROTO;
}
/*
* Only the USB core should call uhci_alloc_dev and uhci_free_dev
*/
_static int uhci_alloc_dev (struct usb_device *usb_dev)
{
return 0;
}
_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
{
unsigned long flags;
struct list_head *p;
struct list_head *p2;
struct urb *urb;
spin_lock_irqsave (&s->urb_list_lock, flags);
p = s->urb_list.prev;
while (p != &s->urb_list) {
p2 = p;
p = p->prev ;
urb = list_entry (p2, struct urb, urb_list);
dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
//urb->transfer_flags |=USB_ASYNC_UNLINK;
if (remove_all || (usb_dev == urb->dev)) {
spin_unlock_irqrestore (&s->urb_list_lock, flags);
warn("forced removing of queued URB %p due to disconnect",urb);
uhci_unlink_urb(urb);
urb->dev = NULL; // avoid further processing of this URB
spin_lock_irqsave (&s->urb_list_lock, flags);
p = s->urb_list.prev;
}
}
spin_unlock_irqrestore (&s->urb_list_lock, flags);
}
_static int uhci_free_dev (struct usb_device *usb_dev)
{
uhci_t *s;
if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
return -EINVAL;
s=(uhci_t*) usb_dev->bus->hcpriv;
uhci_unlink_urbs(s, usb_dev, 0);
return 0;
}
/*
* uhci_get_current_frame_number()
*
* returns the current frame number for a USB bus/controller.
*/
_static int uhci_get_current_frame_n
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -