9
0
Fork 0

initial USB support imported from U-Boot-1

imported from commit bd76729bcbfd64b5d016a9b936f058931fc06eaf.
Only minor changes to make it compile.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2009-02-24 21:10:30 +01:00
parent fcfbd10d3c
commit 03c2189aa8
10 changed files with 3137 additions and 0 deletions

View File

@ -5,5 +5,6 @@ source "drivers/net/Kconfig"
source "drivers/spi/Kconfig"
source "drivers/nor/Kconfig"
source "drivers/nand/Kconfig"
source "drivers/usb/Kconfig"
endmenu

View File

@ -2,4 +2,5 @@ obj-y += net/
obj-y += serial/
obj-y += nand/
obj-y += nor/
obj-y += usb/
obj-$(CONFIG_SPI) += spi/

9
drivers/usb/Kconfig Normal file
View File

@ -0,0 +1,9 @@
menuconfig USB
bool "USB support "
if USB
config USB_EHCI
bool "EHCI driver"
endif

2
drivers/usb/Makefile Normal file
View File

@ -0,0 +1,2 @@
obj-$(CONFIG_USB) += usb.o
obj-$(CONFIG_USB_EHCI) += usb_ehci_core.o

1365
drivers/usb/usb.c Normal file

File diff suppressed because it is too large Load Diff

194
drivers/usb/usb_ehci.h Normal file
View File

@ -0,0 +1,194 @@
/*-
* Copyright (c) 2007-2008, Juniper Networks, Inc.
* Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
* All rights reserved.
*
* 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 version 2 of
* the License.
*
* 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
*/
#ifndef USB_EHCI_H
#define USB_EHCI_H
#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
#endif
/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
#define DeviceRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
#define DeviceOutRequest \
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
#define InterfaceRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
#define EndpointRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
#define EndpointOutRequest \
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
/*
* Register Space.
*/
struct ehci_hccr {
uint32_t cr_capbase;
#define HC_LENGTH(p) (((p) >> 0) & 0x00ff)
#define HC_VERSION(p) (((p) >> 16) & 0xffff)
uint32_t cr_hcsparams;
#define HCS_PPC(p) ((p) & (1 << 4))
#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */
#define HCS_N_PORTS(p) (((p) >> 0) & 0xf)
uint32_t cr_hccparams;
uint8_t cr_hcsp_portrt[8];
} __attribute__ ((packed));
struct ehci_hcor {
uint32_t or_usbcmd;
#define CMD_PARK (1 << 11) /* enable "park" */
#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */
#define CMD_ASE (1 << 5) /* async schedule enable */
#define CMD_LRESET (1 << 7) /* partial reset */
#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */
#define CMD_PSE (1 << 4) /* periodic schedule enable */
#define CMD_RESET (1 << 1) /* reset HC not bus */
#define CMD_RUN (1 << 0) /* start/stop HC */
uint32_t or_usbsts;
#define STD_ASS (1 << 15)
#define STS_HALT (1 << 12)
uint32_t or_usbintr;
uint32_t or_frindex;
uint32_t or_ctrldssegment;
uint32_t or_periodiclistbase;
uint32_t or_asynclistaddr;
uint32_t _reserved_[9];
uint32_t or_configflag;
#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
uint32_t or_systune;
} __attribute__ ((packed));
#define USBMODE 0x68 /* USB Device mode */
#define USBMODE_SDIS (1 << 3) /* Stream disable */
#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */
#define USBMODE_CM_HC (3 << 0) /* host controller mode */
#define USBMODE_CM_IDLE (0 << 0) /* idle state */
/* Interface descriptor */
struct usb_linux_interface_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bInterfaceNumber;
unsigned char bAlternateSetting;
unsigned char bNumEndpoints;
unsigned char bInterfaceClass;
unsigned char bInterfaceSubClass;
unsigned char bInterfaceProtocol;
unsigned char iInterface;
} __attribute__ ((packed));
/* Configuration descriptor information.. */
struct usb_linux_config_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned short wTotalLength;
unsigned char bNumInterfaces;
unsigned char bConfigurationValue;
unsigned char iConfiguration;
unsigned char bmAttributes;
unsigned char MaxPower;
} __attribute__ ((packed));
#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
#define ehci_readl(x) (*((volatile u32 *)(x)))
#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b))
#else
#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x))))
#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \
cpu_to_le32(((volatile u32)b)))
#endif
#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
#define hc32_to_cpu(x) be32_to_cpu((x))
#define cpu_to_hc32(x) cpu_to_be32((x))
#else
#define hc32_to_cpu(x) le32_to_cpu((x))
#define cpu_to_hc32(x) cpu_to_le32((x))
#endif
#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */
#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */
#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */
#define EHCI_PS_PO (1 << 13) /* RW port owner */
#define EHCI_PS_PP (1 << 12) /* RW,RO port power */
#define EHCI_PS_LS (3 << 10) /* RO line status */
#define EHCI_PS_PR (1 << 8) /* RW port reset */
#define EHCI_PS_SUSP (1 << 7) /* RW suspend */
#define EHCI_PS_FPR (1 << 6) /* RW force port resume */
#define EHCI_PS_OCC (1 << 5) /* RWC over current change */
#define EHCI_PS_OCA (1 << 4) /* RO over current active */
#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */
#define EHCI_PS_PE (1 << 2) /* RW port enable */
#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */
#define EHCI_PS_CS (1 << 0) /* RO connect status */
#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10))
/*
* Schedule Interface Space.
*
* IMPORTANT: Software must ensure that no interface data structure
* reachable by the EHCI host controller spans a 4K page boundary!
*
* Periodic transfers (i.e. isochronous and interrupt transfers) are
* not supported.
*/
/* Queue Element Transfer Descriptor (qTD). */
struct qTD {
uint32_t qt_next;
#define QT_NEXT_TERMINATE 1
uint32_t qt_altnext;
uint32_t qt_token;
uint32_t qt_buffer[5];
};
/* Queue Head (QH). */
struct QH {
uint32_t qh_link;
#define QH_LINK_TERMINATE 1
#define QH_LINK_TYPE_ITD 0
#define QH_LINK_TYPE_QH 2
#define QH_LINK_TYPE_SITD 4
#define QH_LINK_TYPE_FSTN 6
uint32_t qh_endpt1;
uint32_t qh_endpt2;
uint32_t qh_curtd;
struct qTD qh_overlay;
/*
* Add dummy fill value to make the size of this struct
* aligned to 32 bytes
*/
uint8_t fill[16];
};
/* Low level init functions */
int ehci_hcd_init(void);
int ehci_hcd_stop(void);
#endif /* USB_EHCI_H */

884
drivers/usb/usb_ehci_core.c Normal file
View File

@ -0,0 +1,884 @@
/*-
* Copyright (c) 2007-2008, Juniper Networks, Inc.
* Copyright (c) 2008, Excito Elektronik i Skåne AB
* Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
*
* All rights reserved.
*
* 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 version 2 of
* the License.
*
* 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
*/
#include <common.h>
#include <asm/byteorder.h>
#include <usb.h>
#include <asm/io.h>
#include <malloc.h>
#include "usb_ehci.h"
int rootdev;
struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
volatile struct ehci_hcor *hcor;
static uint16_t portreset;
static struct QH qh_list __attribute__((aligned(32)));
static struct descriptor {
struct usb_hub_descriptor hub;
struct usb_device_descriptor device;
struct usb_linux_config_descriptor config;
struct usb_linux_interface_descriptor interface;
struct usb_endpoint_descriptor endpoint;
} __attribute__ ((packed)) descriptor = {
{
0x8, /* bDescLength */
0x29, /* bDescriptorType: hub descriptor */
2, /* bNrPorts -- runtime modified */
0, /* wHubCharacteristics */
0xff, /* bPwrOn2PwrGood */
0, /* bHubCntrCurrent */
{}, /* Device removable */
{} /* at most 7 ports! XXX */
},
{
0x12, /* bLength */
1, /* bDescriptorType: UDESC_DEVICE */
0x0002, /* bcdUSB: v2.0 */
9, /* bDeviceClass: UDCLASS_HUB */
0, /* bDeviceSubClass: UDSUBCLASS_HUB */
1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
64, /* bMaxPacketSize: 64 bytes */
0x0000, /* idVendor */
0x0000, /* idProduct */
0x0001, /* bcdDevice */
1, /* iManufacturer */
2, /* iProduct */
0, /* iSerialNumber */
1 /* bNumConfigurations: 1 */
},
{
0x9,
2, /* bDescriptorType: UDESC_CONFIG */
cpu_to_le16(0x19),
1, /* bNumInterface */
1, /* bConfigurationValue */
0, /* iConfiguration */
0x40, /* bmAttributes: UC_SELF_POWER */
0 /* bMaxPower */
},
{
0x9, /* bLength */
4, /* bDescriptorType: UDESC_INTERFACE */
0, /* bInterfaceNumber */
0, /* bAlternateSetting */
1, /* bNumEndpoints */
9, /* bInterfaceClass: UICLASS_HUB */
0, /* bInterfaceSubClass: UISUBCLASS_HUB */
0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */
0 /* iInterface */
},
{
0x7, /* bLength */
5, /* bDescriptorType: UDESC_ENDPOINT */
0x81, /* bEndpointAddress:
* UE_DIR_IN | EHCI_INTR_ENDPT
*/
3, /* bmAttributes: UE_INTERRUPT */
8, 0, /* wMaxPacketSize */
255 /* bInterval */
},
};
#if defined(CONFIG_EHCI_IS_TDI)
#define ehci_is_TDI() (1)
#else
#define ehci_is_TDI() (0)
#endif
#if defined(CONFIG_EHCI_DCACHE)
/*
* Routines to handle (flush/invalidate) the dcache for the QH and qTD
* structures and data buffers. This is needed on platforms using this
* EHCI support with dcache enabled.
*/
static void flush_invalidate(u32 addr, int size, int flush)
{
if (flush)
flush_dcache_range(addr, addr + size);
else
invalidate_dcache_range(addr, addr + size);
}
static void cache_qtd(struct qTD *qtd, int flush)
{
u32 *ptr = (u32 *)qtd->qt_buffer[0];
int len = (qtd->qt_token & 0x7fff0000) >> 16;
flush_invalidate((u32)qtd, sizeof(struct qTD), flush);
if (ptr && len)
flush_invalidate((u32)ptr, len, flush);
}
static inline struct QH *qh_addr(struct QH *qh)
{
return (struct QH *)((u32)qh & 0xffffffe0);
}
static void cache_qh(struct QH *qh, int flush)
{
struct qTD *qtd;
struct qTD *next;
static struct qTD *first_qtd;
/*
* Walk the QH list and flush/invalidate all entries
*/
while (1) {
flush_invalidate((u32)qh_addr(qh), sizeof(struct QH), flush);
if ((u32)qh & QH_LINK_TYPE_QH)
break;
qh = qh_addr(qh);
qh = (struct QH *)qh->qh_link;
}
qh = qh_addr(qh);
/*
* Save first qTD pointer, needed for invalidating pass on this QH
*/
if (flush)
first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay &
0xffffffe0);
else
qtd = first_qtd;
/*
* Walk the qTD list and flush/invalidate all entries
*/
while (1) {
if (qtd == NULL)
break;
cache_qtd(qtd, flush);
next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0);
if (next == qtd)
break;
qtd = next;
}
}
static inline void ehci_flush_dcache(struct QH *qh)
{
cache_qh(qh, 1);
}
static inline void ehci_invalidate_dcache(struct QH *qh)
{
cache_qh(qh, 0);
}
#else /* CONFIG_EHCI_DCACHE */
/*
*
*/
static inline void ehci_flush_dcache(struct QH *qh)
{
}
static inline void ehci_invalidate_dcache(struct QH *qh)
{
}
#endif /* CONFIG_EHCI_DCACHE */
static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
{
uint32_t result;
do {
result = ehci_readl(ptr);
if (result == ~(uint32_t)0)
return -1;
result &= mask;
if (result == done)
return 0;
udelay(1);
usec--;
} while (usec > 0);
return -1;
}
static void ehci_free(void *p, size_t sz)
{
}
static int ehci_reset(void)
{
uint32_t cmd;
uint32_t tmp;
uint32_t *reg_ptr;
int ret = 0;
cmd = ehci_readl(&hcor->or_usbcmd);
cmd |= CMD_RESET;
ehci_writel(&hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
if (ret < 0) {
printf("EHCI fail to reset\n");
goto out;
}
if (ehci_is_TDI()) {
reg_ptr = (uint32_t *)((u8 *)hcor + USBMODE);
tmp = ehci_readl(reg_ptr);
tmp |= USBMODE_CM_HC;
#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
tmp |= USBMODE_BE;
#endif
ehci_writel(reg_ptr, tmp);
}
out:
return ret;
}
static void *ehci_alloc(size_t sz, size_t align)
{
static struct QH qh __attribute__((aligned(32)));
static struct qTD td[3] __attribute__((aligned (32)));
static int ntds;
void *p;
switch (sz) {
case sizeof(struct QH):
p = &qh;
ntds = 0;
break;
case sizeof(struct qTD):
if (ntds == 3) {
debug("out of TDs\n");
return NULL;
}
p = &td[ntds];
ntds++;
break;
default:
debug("unknown allocation size\n");
return NULL;
}
memset(p, sz, 0);
return p;
}
static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
{
uint32_t addr, delta, next;
int idx;
addr = (uint32_t) buf;
idx = 0;
while (idx < 5) {
td->qt_buffer[idx] = cpu_to_hc32(addr);
next = (addr + 4096) & ~4095;
delta = next - addr;
if (delta >= sz)
break;
sz -= delta;
addr = next;
idx++;
}
if (idx == 5) {
debug("out of buffer pointers (%u bytes left)\n", sz);
return -1;
}
return 0;
}
static int
ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *req)
{
struct QH *qh;
struct qTD *td;
volatile struct qTD *vtd;
unsigned long ts;
uint32_t *tdp;
uint32_t endpt, token, usbsts;
uint32_t c, toggle;
uint32_t cmd;
int ret = 0;
debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
buffer, length, req);
if (req != NULL)
debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
req->request, req->request,
req->requesttype, req->requesttype,
le16_to_cpu(req->value), le16_to_cpu(req->value),
le16_to_cpu(req->index));
qh = ehci_alloc(sizeof(struct QH), 32);
if (qh == NULL) {
debug("unable to allocate QH\n");
return -1;
}
qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
usb_pipeendpoint(pipe) == 0) ? 1 : 0;
endpt = (8 << 28) |
(c << 27) |
(usb_maxpacket(dev, pipe) << 16) |
(0 << 15) |
(1 << 14) |
(usb_pipespeed(pipe) << 12) |
(usb_pipeendpoint(pipe) << 8) |
(0 << 7) | (usb_pipedevice(pipe) << 0);
qh->qh_endpt1 = cpu_to_hc32(endpt);
endpt = (1 << 30) |
(dev->portnr << 23) |
(dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
qh->qh_endpt2 = cpu_to_hc32(endpt);
qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
td = NULL;
tdp = &qh->qh_overlay.qt_next;
toggle =
usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
if (req != NULL) {
td = ehci_alloc(sizeof(struct qTD), 32);
if (td == NULL) {
debug("unable to allocate SETUP td\n");
goto fail;
}
td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
token = (0 << 31) |
(sizeof(*req) << 16) |
(0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
td->qt_token = cpu_to_hc32(token);
if (ehci_td_buffer(td, req, sizeof(*req)) != 0) {
debug("unable construct SETUP td\n");
ehci_free(td, sizeof(*td));
goto fail;
}
*tdp = cpu_to_hc32((uint32_t) td);
tdp = &td->qt_next;
toggle = 1;
}
if (length > 0 || req == NULL) {
td = ehci_alloc(sizeof(struct qTD), 32);
if (td == NULL) {
debug("unable to allocate DATA td\n");
goto fail;
}
td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
token = (toggle << 31) |
(length << 16) |
((req == NULL ? 1 : 0) << 15) |
(0 << 12) |
(3 << 10) |
((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
td->qt_token = cpu_to_hc32(token);
if (ehci_td_buffer(td, buffer, length) != 0) {
debug("unable construct DATA td\n");
ehci_free(td, sizeof(*td));
goto fail;
}
*tdp = cpu_to_hc32((uint32_t) td);
tdp = &td->qt_next;
}
if (req != NULL) {
td = ehci_alloc(sizeof(struct qTD), 32);
if (td == NULL) {
debug("unable to allocate ACK td\n");
goto fail;
}
td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
token = (toggle << 31) |
(0 << 16) |
(1 << 15) |
(0 << 12) |
(3 << 10) |
((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
td->qt_token = cpu_to_hc32(token);
*tdp = cpu_to_hc32((uint32_t) td);
tdp = &td->qt_next;
}
qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
/* Flush dcache */
ehci_flush_dcache(&qh_list);
usbsts = ehci_readl(&hcor->or_usbsts);
ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
/* Enable async. schedule. */
cmd = ehci_readl(&hcor->or_usbcmd);
cmd |= CMD_ASE;
ehci_writel(&hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
100 * 1000);
if (ret < 0) {
printf("EHCI fail timeout STD_ASS set\n");
goto fail;
}
#if 0
/* Wait for TDs to be processed. */
ts = get_timer(0);
vtd = td;
do {
/* Invalidate dcache */
ehci_invalidate_dcache(&qh_list);
token = hc32_to_cpu(vtd->qt_token);
if (!(token & 0x80))
break;
} while (get_timer(ts) < CONFIG_SYS_HZ);
#else
#warning FIXME
#endif
/* Disable async schedule. */
cmd = ehci_readl(&hcor->or_usbcmd);
cmd &= ~CMD_ASE;
ehci_writel(&hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
100 * 1000);
if (ret < 0) {
printf("EHCI fail timeout STD_ASS reset\n");
goto fail;
}
qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
token = hc32_to_cpu(qh->qh_overlay.qt_token);
if (!(token & 0x80)) {
debug("TOKEN=%#x\n", token);
switch (token & 0xfc) {
case 0:
toggle = token >> 31;
usb_settoggle(dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), toggle);
dev->status = 0;
break;
case 0x40:
dev->status = USB_ST_STALLED;
break;
case 0xa0:
case 0x20:
dev->status = USB_ST_BUF_ERR;
break;
case 0x50:
case 0x10:
dev->status = USB_ST_BABBLE_DET;
break;
default:
dev->status = USB_ST_CRC_ERR;
break;
}
dev->act_len = length - ((token >> 16) & 0x7fff);
} else {
dev->act_len = 0;
debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
dev->devnum, ehci_readl(&hcor->or_usbsts),
ehci_readl(&hcor->or_portsc[0]),
ehci_readl(&hcor->or_portsc[1]));
}
return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
fail:
td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
while (td != (void *)QT_NEXT_TERMINATE) {
qh->qh_overlay.qt_next = td->qt_next;
ehci_free(td, sizeof(*td));
td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
}
ehci_free(qh, sizeof(*qh));
return -1;
}
static inline int min3(int a, int b, int c)
{
if (b < a)
a = b;
if (c < a)
a = c;
return a;
}
int
ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *req)
{
uint8_t tmpbuf[4];
u16 typeReq;
void *srcptr = NULL;
int len, srclen;
uint32_t reg;
uint32_t *status_reg;
if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
printf("The request port(%d) is not configured\n",
le16_to_cpu(req->index) - 1);
return -1;
}
status_reg = (uint32_t *)&hcor->or_portsc[
le16_to_cpu(req->index) - 1];
srclen = 0;
debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
req->request, req->request,
req->requesttype, req->requesttype,
le16_to_cpu(req->value), le16_to_cpu(req->index));
typeReq = req->request << 8 | req->requesttype;
switch (le16_to_cpu(typeReq)) {
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch (le16_to_cpu(req->value) >> 8) {
case USB_DT_DEVICE:
debug("USB_DT_DEVICE request\n");
srcptr = &descriptor.device;
srclen = 0x12;
break;
case USB_DT_CONFIG:
debug("USB_DT_CONFIG config\n");
srcptr = &descriptor.config;
srclen = 0x19;
break;
case USB_DT_STRING:
debug("USB_DT_STRING config\n");
switch (le16_to_cpu(req->value) & 0xff) {
case 0: /* Language */
srcptr = "\4\3\1\0";
srclen = 4;
break;
case 1: /* Vendor */
srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
srclen = 14;
break;
case 2: /* Product */
srcptr = "\52\3E\0H\0C\0I\0 "
"\0H\0o\0s\0t\0 "
"\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
srclen = 42;
break;
default:
debug("unknown value DT_STRING %x\n",
le16_to_cpu(req->value));
goto unknown;
}
break;
default:
debug("unknown value %x\n", le16_to_cpu(req->value));
goto unknown;
}
break;
case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
switch (le16_to_cpu(req->value) >> 8) {
case USB_DT_HUB:
debug("USB_DT_HUB config\n");
srcptr = &descriptor.hub;
srclen = 0x8;
break;
default:
debug("unknown value %x\n", le16_to_cpu(req->value));
goto unknown;
}
break;
case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
debug("USB_REQ_SET_ADDRESS\n");
rootdev = le16_to_cpu(req->value);
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
debug("USB_REQ_SET_CONFIGURATION\n");
/* Nothing to do */
break;
case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */
tmpbuf[1] = 0;
srcptr = tmpbuf;
srclen = 2;
break;
case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
memset(tmpbuf, 0, 4);
reg = ehci_readl(status_reg);
if (reg & EHCI_PS_CS)
tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
if (reg & EHCI_PS_PE)
tmpbuf[0] |= USB_PORT_STAT_ENABLE;
if (reg & EHCI_PS_SUSP)
tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
if (reg & EHCI_PS_OCA)
tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
if (reg & EHCI_PS_PR &&
(portreset & (1 << le16_to_cpu(req->index)))) {
int ret;
/* force reset to complete */
reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
ehci_writel(status_reg, reg);
ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
if (!ret)
tmpbuf[0] |= USB_PORT_STAT_RESET;
else
printf("port(%d) reset error\n",
le16_to_cpu(req->index) - 1);
}
if (reg & EHCI_PS_PP)
tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
if (ehci_is_TDI()) {
switch ((reg >> 26) & 3) {
case 0:
break;
case 1:
tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
break;
case 2:
default:
tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
break;
}
} else {
tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
}
if (reg & EHCI_PS_CSC)
tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
if (reg & EHCI_PS_PEC)
tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
if (reg & EHCI_PS_OCC)
tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
if (portreset & (1 << le16_to_cpu(req->index)))
tmpbuf[2] |= USB_PORT_STAT_C_RESET;
srcptr = tmpbuf;
srclen = 4;
break;
case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
reg = ehci_readl(status_reg);
reg &= ~EHCI_PS_CLEAR;
switch (le16_to_cpu(req->value)) {
case USB_PORT_FEAT_ENABLE:
reg |= EHCI_PS_PE;
ehci_writel(status_reg, reg);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) {
reg |= EHCI_PS_PP;
ehci_writel(status_reg, reg);
}
break;
case USB_PORT_FEAT_RESET:
if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
!ehci_is_TDI() &&
EHCI_PS_IS_LOWSPEED(reg)) {
/* Low speed device, give up ownership. */
debug("port %d low speed --> companion\n",
req->index - 1);
reg |= EHCI_PS_PO;
ehci_writel(status_reg, reg);
break;
} else {
reg |= EHCI_PS_PR;
reg &= ~EHCI_PS_PE;
ehci_writel(status_reg, reg);
/*
* caller must wait, then call GetPortStatus
* usb 2.0 specification say 50 ms resets on
* root
*/
wait_ms(50);
portreset |= 1 << le16_to_cpu(req->index);
}
break;
default:
debug("unknown feature %x\n", le16_to_cpu(req->value));
goto unknown;
}
/* unblock posted writes */
ehci_readl(&hcor->or_usbcmd);
break;
case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
reg = ehci_readl(status_reg);
switch (le16_to_cpu(req->value)) {
case USB_PORT_FEAT_ENABLE:
reg &= ~EHCI_PS_PE;
break;
case USB_PORT_FEAT_C_ENABLE:
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams)))
reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
case USB_PORT_FEAT_C_CONNECTION:
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
break;
case USB_PORT_FEAT_OVER_CURRENT:
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
break;
case USB_PORT_FEAT_C_RESET:
portreset &= ~(1 << le16_to_cpu(req->index));
break;
default:
debug("unknown feature %x\n", le16_to_cpu(req->value));
goto unknown;
}
ehci_writel(status_reg, reg);
/* unblock posted write */
ehci_readl(&hcor->or_usbcmd);
break;
default:
debug("Unknown request\n");
goto unknown;
}
wait_ms(1);
len = min3(srclen, le16_to_cpu(req->length), length);
if (srcptr != NULL && len > 0)
memcpy(buffer, srcptr, len);
else
debug("Len is 0\n");
dev->act_len = len;
dev->status = 0;
return 0;
unknown:
debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n",
req->requesttype, req->request, le16_to_cpu(req->value),
le16_to_cpu(req->index), le16_to_cpu(req->length));
dev->act_len = 0;
dev->status = USB_ST_STALLED;
return -1;
}
int usb_lowlevel_stop(void)
{
return ehci_hcd_stop();
}
int usb_lowlevel_init(void)
{
uint32_t reg;
uint32_t cmd;
if (ehci_hcd_init() != 0)
return -1;
/* EHCI spec section 4.1 */
if (ehci_reset() != 0)
return -1;
#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
if (ehci_hcd_init() != 0)
return -1;
#endif
/* Set head of reclaim list */
memset(&qh_list, 0, sizeof(qh_list));
qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
qh_list.qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
qh_list.qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
qh_list.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
qh_list.qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
qh_list.qh_overlay.qt_token = cpu_to_hc32(0x40);
/* Set async. queue head pointer. */
ehci_writel(&hcor->or_asynclistaddr, (uint32_t)&qh_list);
reg = ehci_readl(&hccr->cr_hcsparams);
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
/* Port Indicators */
if (HCS_INDICATOR(reg))
descriptor.hub.wHubCharacteristics |= 0x80;
/* Port Power Control */
if (HCS_PPC(reg))
descriptor.hub.wHubCharacteristics |= 0x01;
/* Start the host controller. */
cmd = ehci_readl(&hcor->or_usbcmd);
/*
* Philips, Intel, and maybe others need CMD_RUN before the
* root hub will detect new devices (why?); NEC doesn't
*/
cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
cmd |= CMD_RUN;
ehci_writel(&hcor->or_usbcmd, cmd);
/* take control over the ports */
cmd = ehci_readl(&hcor->or_configflag);
cmd |= FLAG_CF;
ehci_writel(&hcor->or_configflag, cmd);
/* unblock posted write */
cmd = ehci_readl(&hcor->or_usbcmd);
wait_ms(5);
reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
rootdev = 0;
return 0;
}
int
submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length)
{
if (usb_pipetype(pipe) != PIPE_BULK) {
debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
return -1;
}
return ehci_submit_async(dev, pipe, buffer, length, NULL);
}
int
submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *setup)
{
if (usb_pipetype(pipe) != PIPE_CONTROL) {
debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
return -1;
}
if (usb_pipedevice(pipe) == rootdev) {
if (rootdev == 0)
dev->speed = USB_SPEED_HIGH;
return ehci_submit_root(dev, pipe, buffer, length, setup);
}
return ehci_submit_async(dev, pipe, buffer, length, setup);
}
int
submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, int interval)
{
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
return -1;
}

View File

@ -0,0 +1,29 @@
/*-
* Copyright (c) 2007-2008, Juniper Networks, Inc.
* Copyright (c) 2008, Excito Elektronik i Skåne AB
* All rights reserved.
*
* 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 version 2 of
* the License.
*
* 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
*/
#ifndef USB_EHCI_CORE_H
#define USB_EHCI_CORE_H
extern int rootdev;
extern struct ehci_hccr *hccr;
extern volatile struct ehci_hcor *hcor;
#endif

401
include/usb.h Normal file
View File

@ -0,0 +1,401 @@
/*
* (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
*
* Note: Part of this code has been derived from linux
*
*/
#ifndef _USB_H_
#define _USB_H_
#include <usb_defs.h>
/* Everything is aribtrary */
#define USB_ALTSETTINGALLOC 4
#define USB_MAXALTSETTING 128 /* Hard limit */
#define USB_MAX_DEVICE 32
#define USB_MAXCONFIG 8
#define USB_MAXINTERFACES 8
#define USB_MAXENDPOINTS 16
#define USB_MAXCHILDREN 8 /* This is arbitrary */
#define USB_MAX_HUB 16
#define USB_CNTL_TIMEOUT 100 /* 100ms timeout */
/* String descriptor */
struct usb_string_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned short wData[1];
} __attribute__ ((packed));
/* device request (setup) */
struct devrequest {
unsigned char requesttype;
unsigned char request;
unsigned short value;
unsigned short index;
unsigned short length;
} __attribute__ ((packed));
/* All standard descriptors have these 2 fields in common */
struct usb_descriptor_header {
unsigned char bLength;
unsigned char bDescriptorType;
} __attribute__ ((packed));
/* Device descriptor */
struct usb_device_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned short bcdUSB;
unsigned char bDeviceClass;
unsigned char bDeviceSubClass;
unsigned char bDeviceProtocol;
unsigned char bMaxPacketSize0;
unsigned short idVendor;
unsigned short idProduct;
unsigned short bcdDevice;
unsigned char iManufacturer;
unsigned char iProduct;
unsigned char iSerialNumber;
unsigned char bNumConfigurations;
} __attribute__ ((packed));
/* Endpoint descriptor */
struct usb_endpoint_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bEndpointAddress;
unsigned char bmAttributes;
unsigned short wMaxPacketSize;
unsigned char bInterval;
unsigned char bRefresh;
unsigned char bSynchAddress;
} __attribute__ ((packed)) __attribute__ ((aligned(2)));
/* Interface descriptor */
struct usb_interface_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bInterfaceNumber;
unsigned char bAlternateSetting;
unsigned char bNumEndpoints;
unsigned char bInterfaceClass;
unsigned char bInterfaceSubClass;
unsigned char bInterfaceProtocol;
unsigned char iInterface;
unsigned char no_of_ep;
unsigned char num_altsetting;
unsigned char act_altsetting;
struct usb_endpoint_descriptor ep_desc[USB_MAXENDPOINTS];
} __attribute__ ((packed));
/* Configuration descriptor information.. */
struct usb_config_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned short wTotalLength;
unsigned char bNumInterfaces;
unsigned char bConfigurationValue;
unsigned char iConfiguration;
unsigned char bmAttributes;
unsigned char MaxPower;
unsigned char no_of_if; /* number of interfaces */
struct usb_interface_descriptor if_desc[USB_MAXINTERFACES];
} __attribute__ ((packed));
enum {
/* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */
PACKET_SIZE_8 = 0,
PACKET_SIZE_16 = 1,
PACKET_SIZE_32 = 2,
PACKET_SIZE_64 = 3,
};
struct usb_device {
int devnum; /* Device number on USB bus */
int speed; /* full/low/high */
char mf[32]; /* manufacturer */
char prod[32]; /* product */
char serial[32]; /* serial number */
/* Maximum packet size; one of: PACKET_SIZE_* */
int maxpacketsize;
/* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int toggle[2];
/* endpoint halts; one bit per endpoint # & direction;
* [0] = IN, [1] = OUT
*/
unsigned int halted[2];
int epmaxpacketin[16]; /* INput endpoint specific maximums */
int epmaxpacketout[16]; /* OUTput endpoint specific maximums */
int configno; /* selected config number */
struct usb_device_descriptor descriptor; /* Device Descriptor */
struct usb_config_descriptor config; /* config descriptor */
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
int (*irq_handle)(struct usb_device *dev);
unsigned long irq_status;
int irq_act_len; /* transfered bytes */
void *privptr;
/*
* Child devices - if this is a hub device
* Each instance needs its own set of data structures.
*/
unsigned long status;
int act_len; /* transfered bytes */
int maxchild; /* Number of ports if hub */
int portnr;
struct usb_device *parent;
struct usb_device *children[USB_MAXCHILDREN];
};
/**********************************************************************
* this is how the lowlevel part communicate with the outer world
*/
int usb_lowlevel_init(void);
int usb_lowlevel_stop(void);
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int transfer_len);
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int transfer_len, struct devrequest *setup);
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int transfer_len, int interval);
void usb_event_poll(void);
/* Defines */
#define USB_UHCI_VEND_ID 0x8086
#define USB_UHCI_DEV_ID 0x7112
#ifdef CONFIG_USB_STORAGE
#define USB_MAX_STOR_DEV 5
block_dev_desc_t *usb_stor_get_dev(int index);
int usb_stor_scan(int mode);
int usb_stor_info(void);
#endif
#ifdef CONFIG_USB_KEYBOARD
int drv_usb_kbd_init(void);
int usb_kbd_deregister(void);
#endif
/* routines */
int usb_init(void); /* initialize the USB Controller */
int usb_stop(void); /* stop the USB Controller */
int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol);
int usb_set_idle(struct usb_device *dev, int ifnum, int duration,
int report_id);
struct usb_device *usb_get_dev_index(int index);
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);
int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout);
int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int transfer_len, int interval);
void usb_disable_asynch(int disable);
int usb_maxpacket(struct usb_device *dev, unsigned long pipe);
static inline void wait_ms(unsigned long ms)
{
mdelay(ms);
};
int usb_get_configuration_no(struct usb_device *dev, unsigned char *buffer,
int cfgno);
int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type,
unsigned char id, void *buf, int size);
int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
unsigned char type, unsigned char id, void *buf,
int size);
int usb_clear_halt(struct usb_device *dev, int pipe);
int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
/* big endian -> little endian conversion */
/* some CPUs are already little endian e.g. the ARM920T */
#define __swap_16(x) \
({ unsigned short x_ = (unsigned short)x; \
(unsigned short)( \
((x_ & 0x00FFU) << 8) | ((x_ & 0xFF00U) >> 8)); \
})
#define __swap_32(x) \
({ unsigned long x_ = (unsigned long)x; \
(unsigned long)( \
((x_ & 0x000000FFUL) << 24) | \
((x_ & 0x0000FF00UL) << 8) | \
((x_ & 0x00FF0000UL) >> 8) | \
((x_ & 0xFF000000UL) >> 24)); \
})
#ifdef __LITTLE_ENDIAN
# define swap_16(x) (x)
# define swap_32(x) (x)
#else
# define swap_16(x) __swap_16(x)
# define swap_32(x) __swap_32(x)
#endif
/*
* Calling this entity a "pipe" is glorifying it. A USB pipe
* is something embarrassingly simple: it basically consists
* of the following information:
* - device number (7 bits)
* - endpoint number (4 bits)
* - current Data0/1 state (1 bit)
* - direction (1 bit)
* - speed (2 bits)
* - max packet size (2 bits: 8, 16, 32 or 64)
* - pipe type (2 bits: control, interrupt, bulk, isochronous)
*
* That's 18 bits. Really. Nothing more. And the USB people have
* documented these eighteen bits as some kind of glorious
* virtual data structure.
*
* Let's not fall in that trap. We'll just encode it as a simple
* unsigned int. The encoding is:
*
* - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64)
* - direction: bit 7 (0 = Host-to-Device [Out],
* (1 = Device-to-Host [In])
* - device: bits 8-14
* - endpoint: bits 15-18
* - Data0/1: bit 19
* - speed: bit 26 (0 = Full, 1 = Low Speed, 2 = High)
* - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
* 10 = control, 11 = bulk)
*
* Why? Because it's arbitrary, and whatever encoding we select is really
* up to us. This one happens to share a lot of bit positions with the UHCI
* specification, so that much of the uhci driver can just mask the bits
* appropriately.
*/
/* Create various pipes... */
#define create_pipe(dev,endpoint) \
(((dev)->devnum << 8) | (endpoint << 15) | \
((dev)->speed << 26) | (dev)->maxpacketsize)
#define default_pipe(dev) ((dev)->speed << 26)
#define usb_sndctrlpipe(dev, endpoint) ((PIPE_CONTROL << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvctrlpipe(dev, endpoint) ((PIPE_CONTROL << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_sndisocpipe(dev, endpoint) ((PIPE_ISOCHRONOUS << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvisocpipe(dev, endpoint) ((PIPE_ISOCHRONOUS << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_sndbulkpipe(dev, endpoint) ((PIPE_BULK << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvbulkpipe(dev, endpoint) ((PIPE_BULK << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_sndintpipe(dev, endpoint) ((PIPE_INTERRUPT << 30) | \
create_pipe(dev, endpoint))
#define usb_rcvintpipe(dev, endpoint) ((PIPE_INTERRUPT << 30) | \
create_pipe(dev, endpoint) | \
USB_DIR_IN)
#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30) | \
default_pipe(dev))
#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | \
default_pipe(dev) | \
USB_DIR_IN)
/* The D0/D1 toggle bits */
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << ep))
#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = \
((dev)->toggle[out] & \
~(1 << ep)) | ((bit) << ep))
/* Endpoint halt control/status */
#define usb_endpoint_out(ep_dir) (((ep_dir >> 7) & 1) ^ 1)
#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
#define usb_packetid(pipe) (((pipe) & USB_DIR_IN) ? USB_PID_IN : \
USB_PID_OUT)
#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1)
#define usb_pipein(pipe) (((pipe) >> 7) & 1)
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
#define usb_pipedata(pipe) (((pipe) >> 19) & 1)
#define usb_pipespeed(pipe) (((pipe) >> 26) & 3)
#define usb_pipeslow(pipe) (usb_pipespeed(pipe) == USB_SPEED_LOW)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL)
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK)
/*************************************************************************
* Hub Stuff
*/
struct usb_port_status {
unsigned short wPortStatus;
unsigned short wPortChange;
} __attribute__ ((packed));
struct usb_hub_status {
unsigned short wHubStatus;
unsigned short wHubChange;
} __attribute__ ((packed));
/* Hub descriptor */
struct usb_hub_descriptor {
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bNbrPorts;
unsigned short wHubCharacteristics;
unsigned char bPwrOn2PwrGood;
unsigned char bHubContrCurrent;
unsigned char DeviceRemovable[(USB_MAXCHILDREN+1+7)/8];
unsigned char PortPowerCtrlMask[(USB_MAXCHILDREN+1+7)/8];
/* DeviceRemovable and PortPwrCtrlMask want to be variable-length
bitmaps that hold max 255 entries. (bit0 is ignored) */
} __attribute__ ((packed));
struct usb_hub_device {
struct usb_device *pusb_dev;
struct usb_hub_descriptor desc;
};
#endif /*_USB_H_ */

251
include/usb_defs.h Normal file
View File

@ -0,0 +1,251 @@
/*
* (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
*
* Note: Part of this code has been derived from linux
*
*/
#ifndef _USB_DEFS_H_
#define _USB_DEFS_H_
/* USB constants */
/* Device and/or Interface Class codes */
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 10
#define USB_CLASS_VENDOR_SPEC 0xff
/* some HID sub classes */
#define USB_SUB_HID_NONE 0
#define USB_SUB_HID_BOOT 1
/* some UID Protocols */
#define USB_PROT_HID_NONE 0
#define USB_PROT_HID_KEYBOARD 1
#define USB_PROT_HID_MOUSE 2
/* Sub STORAGE Classes */
#define US_SC_RBC 1 /* Typically, flash devices */
#define US_SC_8020 2 /* CD-ROM */
#define US_SC_QIC 3 /* QIC-157 Tapes */
#define US_SC_UFI 4 /* Floppy */
#define US_SC_8070 5 /* Removable media */
#define US_SC_SCSI 6 /* Transparent */
#define US_SC_MIN US_SC_RBC
#define US_SC_MAX US_SC_SCSI
/* STORAGE Protocols */
#define US_PR_CB 1 /* Control/Bulk w/o interrupt */
#define US_PR_CBI 0 /* Control/Bulk/Interrupt */
#define US_PR_BULK 0x50 /* bulk only */
/* USB types */
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
/* USB recipients */
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
/* USB directions */
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
/* USB device speeds */
#define USB_SPEED_FULL 0x0 /* 12Mbps */
#define USB_SPEED_LOW 0x1 /* 1.5Mbps */
#define USB_SPEED_HIGH 0x2 /* 480Mbps */
#define USB_SPEED_RESERVED 0x3
/* Descriptor types */
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
/* Descriptor sizes per descriptor type */
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
#define USB_DT_HUB_NONVAR_SIZE 7
#define USB_DT_HID_SIZE 9
/* Endpoints */
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
/* USB Packet IDs (PIDs) */
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
#define USB_PID_UNDEF_4 0xb4
#define USB_PID_SOF 0xa5
#define USB_PID_UNDEF_6 0x96
#define USB_PID_UNDEF_7 0x87
#define USB_PID_UNDEF_8 0x78
#define USB_PID_IN 0x69
#define USB_PID_NAK 0x5a
#define USB_PID_DATA1 0x4b
#define USB_PID_PREAMBLE 0x3c
#define USB_PID_SETUP 0x2d
#define USB_PID_STALL 0x1e
#define USB_PID_UNDEF_F 0x0f
/* Standard requests */
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
/* HID requests */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_GET_IDLE 0x02
#define USB_REQ_GET_PROTOCOL 0x03
#define USB_REQ_SET_REPORT 0x09
#define USB_REQ_SET_IDLE 0x0A
#define USB_REQ_SET_PROTOCOL 0x0B
/* "pipe" definitions */
#define PIPE_ISOCHRONOUS 0
#define PIPE_INTERRUPT 1
#define PIPE_CONTROL 2
#define PIPE_BULK 3
#define PIPE_DEVEP_MASK 0x0007ff00
#define USB_ISOCHRONOUS 0
#define USB_INTERRUPT 1
#define USB_CONTROL 2
#define USB_BULK 3
/* USB-status codes: */
#define USB_ST_ACTIVE 0x1 /* TD is active */
#define USB_ST_STALLED 0x2 /* TD is stalled */
#define USB_ST_BUF_ERR 0x4 /* buffer error */
#define USB_ST_BABBLE_DET 0x8 /* Babble detected */
#define USB_ST_NAK_REC 0x10 /* NAK Received*/
#define USB_ST_CRC_ERR 0x20 /* CRC/timeout Error */
#define USB_ST_BIT_ERR 0x40 /* Bitstuff error */
#define USB_ST_NOT_PROC 0x80000000L /* Not yet processed */
/*************************************************************************
* Hub defines
*/
/*
* Hub request types
*/
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
/*
* Hub Class feature numbers
*/
#define C_HUB_LOCAL_POWER 0
#define C_HUB_OVER_CURRENT 1
/*
* Port feature numbers
*/
#define USB_PORT_FEAT_CONNECTION 0
#define USB_PORT_FEAT_ENABLE 1
#define USB_PORT_FEAT_SUSPEND 2
#define USB_PORT_FEAT_OVER_CURRENT 3
#define USB_PORT_FEAT_RESET 4
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9
#define USB_PORT_FEAT_HIGHSPEED 10
#define USB_PORT_FEAT_C_CONNECTION 16
#define USB_PORT_FEAT_C_ENABLE 17
#define USB_PORT_FEAT_C_SUSPEND 18
#define USB_PORT_FEAT_C_OVER_CURRENT 19
#define USB_PORT_FEAT_C_RESET 20
/* wPortStatus bits */
#define USB_PORT_STAT_CONNECTION 0x0001
#define USB_PORT_STAT_ENABLE 0x0002
#define USB_PORT_STAT_SUSPEND 0x0004
#define USB_PORT_STAT_OVERCURRENT 0x0008
#define USB_PORT_STAT_RESET 0x0010
#define USB_PORT_STAT_POWER 0x0100
#define USB_PORT_STAT_LOW_SPEED 0x0200
#define USB_PORT_STAT_HIGH_SPEED 0x0400 /* support for EHCI */
#define USB_PORT_STAT_SPEED \
(USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED)
/* wPortChange bits */
#define USB_PORT_STAT_C_CONNECTION 0x0001
#define USB_PORT_STAT_C_ENABLE 0x0002
#define USB_PORT_STAT_C_SUSPEND 0x0004
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
#define USB_PORT_STAT_C_RESET 0x0010
/* wHubCharacteristics (masks) */
#define HUB_CHAR_LPSM 0x0003
#define HUB_CHAR_COMPOUND 0x0004
#define HUB_CHAR_OCPM 0x0018
/*
*Hub Status & Hub Change bit masks
*/
#define HUB_STATUS_LOCAL_POWER 0x0001
#define HUB_STATUS_OVERCURRENT 0x0002
#define HUB_CHANGE_LOCAL_POWER 0x0001
#define HUB_CHANGE_OVERCURRENT 0x0002
#endif /*_USB_DEFS_H_ */