[U-Boot-Users] [PATCH 2/4][RFC] Add ehci core functionality
michael
trimarchi at gandalf.sssup.it
Mon Jun 23 14:59:37 CEST 2008
Hi,
Tor Krill wrote:
> +static uint16_t portreset;
> +static struct QH qh_list __attribute__ ((aligned (32)));
> +
> +static struct {
> + uint8_t hub[8];
> + uint8_t device[18];
> + uint8_t config[9];
> + uint8_t interface[9];
> + uint8_t endpoint[7];
> +} descr = {
> + { /* HUB */
> + sizeof (descr.hub), /* bDescLength */
> + 0x29, /* bDescriptorType: hub descriptor */
> + 2, /* bNrPorts -- runtime modified */
> + 0, 0, /* wHubCharacteristics -- runtime modified */
> + 0xff, /* bPwrOn2PwrGood */
> + 0, /* bHubCntrCurrent */
> + 0 /* DeviceRemovable XXX at most 7 ports! XXX */
> + }
> + , { /* DEVICE */
> + sizeof (descr.device), /* bLength */
> + 1, /* bDescriptorType: UDESC_DEVICE */
> + 0x00, 0x02, /* bcdUSB: v2.0 */
> + 9, /* bDeviceClass: UDCLASS_HUB */
> + 0, /* bDeviceSubClass: UDSUBCLASS_HUB */
> + 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
> + 64, /* bMaxPacketSize: 64 bytes */
> + 0x00, 0x00, /* idVendor */
> + 0x00, 0x00, /* idProduct */
> + 0x00, 0x01, /* bcdDevice */
> + 1, /* iManufacturer */
> + 2, /* iProduct */
> + 0, /* iSerialNumber */
> + 1 /* bNumConfigurations: 1 */
> + }
> + , { /* CONFIG */
> + sizeof (descr.config), /* bLength */
> + 2, /* bDescriptorType: UDESC_CONFIG */
> + sizeof (descr.config) + sizeof (descr.interface) +
> + sizeof (descr.endpoint), 0,
> + /* wTotalLength */
> + 1, /* bNumInterface */
> + 1, /* bConfigurationValue */
> + 0, /* iConfiguration */
> + 0x40, /* bmAttributes: UC_SELF_POWERED */
> + 0 /* bMaxPower */
> + }
> + , { /* INTERFACE */
> + sizeof (descr.interface), /* 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 */
> + }
> + , { /* ENDPOINT */
> + sizeof (descr.endpoint), /* bLength */
> + 5, /* bDescriptorType: UDESC_ENDPOINT */
> + 0x81, /* bEndpointAddress: UE_DIR_IN | EHCI_INTR_ENDPT */
> + 3, /* bmAttributes: UE_INTERRUPT */
> + 8, 0, /* wMaxPacketSize */
> + 255 /* bInterval */
> + }
> +};
> +
>
I prefer using:
struct usb_device_descriptor device = {
sizeof(struct usb_device_descriptor), /* 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 */
};
struct usb_interface_descriptor interface = {
sizeof(struct usb_interface_descriptor), /* 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 */
};
struct usb_endpoint_descriptor endpoint = {
sizeof(struct usb_endpoint_descriptor), /* bLength */
5, /* bDescriptorType: UDESC_ENDPOINT */
0x81, /* bEndpointAddress: UE_DIR_IN | EHCI_INTR_ENDPT */
3, /* bmAttributes: UE_INTERRUPT */
8, 0, /* wMaxPacketSize */
255 /* bInterval */
};
struct usb_hub_descriptor hub = {
sizeof(struct usb_hub_descriptor), /* bDescLength */
0x29, /* bDescriptorType: hub
descriptor */
2, /* bNrPorts -- runtime modified */
0, 0, /* wHubCharacteristics */
0xff, /* bPwrOn2PwrGood */
{}, /* bHubCntrCurrent */
{} /* at most 7 ports! XXX */
};
Why don't use somenthing like this? (see up)
> +static int
> +ehci_submit_root (struct usb_device *dev, unsigned long pipe, void *buffer,
> + int length, struct devrequest *req)
> +{
> + uint8_t tmpbuf[4];
> + void *srcptr;
> + int len, srclen;
> + uint32_t reg;
> +
> + srclen = 0;
> + srcptr = NULL;
> +
> + debug ("req=%u (%#x), type=%u (%#x), value=%u, index=%u",
> + req->request, req->request,
> + req->requesttype, req->requesttype,
> + le16_to_cpu (req->value), le16_to_cpu (req->index));
> +
> +#define C(a,b) (((b) << 8) | (a))
> +
> + switch (C (req->request, req->requesttype)) {
> + case C (USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RECIP_DEVICE):
> + switch (le16_to_cpu (req->value) >> 8) {
> + case USB_DT_DEVICE:
> + srcptr = descr.device;
> + srclen = sizeof (descr.device);
> + break;
> + case USB_DT_CONFIG:
> + srcptr = descr.config;
> + srclen = sizeof (descr.config) +
> + sizeof (descr.interface) + sizeof (descr.endpoint);
> + break;
> + case USB_DT_STRING:
> + 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:
> + goto unknown;
> + }
> + break;
> + default:
> + debug ("unknown value %x", le16_to_cpu (req->value));
> + goto unknown;
> + }
> + break;
> + case C (USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB):
> + switch (le16_to_cpu (req->value) >> 8) {
> + case USB_DT_HUB:
> + srcptr = descr.hub;
> + srclen = sizeof (descr.hub);
> + break;
> + default:
> + debug ("unknown value %x", le16_to_cpu (req->value));
> + goto unknown;
> + }
> + break;
> + case C (USB_REQ_SET_ADDRESS, USB_RECIP_DEVICE):
> + rootdev = le16_to_cpu (req->value);
> + break;
> + case C (USB_REQ_SET_CONFIGURATION, USB_RECIP_DEVICE):
> + /* Nothing to do */
> + break;
> + case C (USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB):
> + tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */
> + tmpbuf[1] = 0;
> + srcptr = tmpbuf;
> + srclen = 2;
> + break;
> + case C (USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT):
> + memset (tmpbuf, 0, 4);
> + reg = le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> + 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)
> + tmpbuf[0] |= USB_PORT_STAT_RESET;
> + if (reg & EHCI_PS_PP)
> + tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
> + 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 C (USB_REQ_SET_FEATURE, USB_DIR_OUT | USB_RT_PORT):
> + reg = le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> + reg &= ~EHCI_PS_CLEAR;
> + switch (le16_to_cpu (req->value)) {
> + case USB_PORT_FEAT_POWER:
> + reg |= EHCI_PS_PP;
> + break;
> + case USB_PORT_FEAT_RESET:
> + if (EHCI_PS_IS_LOWSPEED (reg)) {
> + /* Low speed device, give up ownership. */
> + reg |= EHCI_PS_PO;
> + break;
> + }
> + /* Start reset sequence. */
> + reg &= ~EHCI_PS_PE;
> + reg |= EHCI_PS_PR;
> + hcor->or_portsc[le16_to_cpu (req->index) - 1] =
> + cpu_to_le32 (reg);
> + /* Wait for reset to complete. */
> + udelay (500000);
> + /* Terminate reset sequence. */
> + reg &= ~EHCI_PS_PR;
> + /* TODO: is it only fsl chip that requires this
> + * manual setting of port enable?
> + */
> + reg |= EHCI_PS_PE;
> + hcor->or_portsc[le16_to_cpu (req->index) - 1] =
> + cpu_to_le32 (reg);
> + /* Wait for HC to complete reset. */
> + udelay (2000);
> + reg =
> + le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> + reg &= ~EHCI_PS_CLEAR;
> + if ((reg & EHCI_PS_PE) == 0) {
> + /* Not a high speed device, give up ownership. */
> + reg |= EHCI_PS_PO;
> + break;
> + }
> + portreset |= 1 << le16_to_cpu (req->index);
> + break;
> + default:
> + debug ("unknown feature %x", le16_to_cpu (req->value));
> + goto unknown;
> + }
> + hcor->or_portsc[le16_to_cpu (req->index) - 1] = cpu_to_le32 (reg);
> + break;
> + case C (USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RT_PORT):
> + reg = le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> + reg &= ~EHCI_PS_CLEAR;
> + switch (le16_to_cpu (req->value)) {
> + case USB_PORT_FEAT_ENABLE:
> + reg &= ~EHCI_PS_PE;
> + break;
> + case USB_PORT_FEAT_C_CONNECTION:
> + reg |= EHCI_PS_CSC;
> + break;
> + case USB_PORT_FEAT_C_RESET:
> + portreset &= ~(1 << le16_to_cpu (req->index));
> + break;
> + default:
> + debug ("unknown feature %x", le16_to_cpu (req->value));
> + goto unknown;
> + }
> + hcor->or_portsc[le16_to_cpu (req->index) - 1] = cpu_to_le32 (reg);
> + break;
> + default:
> + debug ("Unknown request %x",
> + C (req->request, req->requesttype));
> + goto unknown;
> + }
> +
> +#undef C
> +
> + len = min3 (srclen, le16_to_cpu (req->length), length);
> + if (srcptr != NULL && len > 0)
> + memcpy (buffer, srcptr, len);
> + dev->act_len = len;
> + dev->status = 0;
> + return (0);
> +
> + unknown:
> + debug ("requesttype=%x, request=%x, value=%x, index=%x, length=%x",
> + 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);
> +}
> +
>
This code can be change according with this one.
static 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;
int len, srclen;
uint32_t reg;
srclen = 0;
srcptr = NULL;
DBG("req=%u (%#x), type=%u (%#x), value=%u, index=%u",
req->request, req->request,
req->requesttype, req->requesttype,
swap_16(req->value), swap_16(req->index));
typeReq = req->request << 8 | req->requesttype;
switch (typeReq) {
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch(swap_16(req->value) >> 8) {
case USB_DT_DEVICE:
srcptr = &device;
srclen = sizeof(struct usb_device_descriptor);
break;
case USB_DT_CONFIG:
srcptr = &config;
srclen = sizeof(config) +
sizeof(struct usb_interface_descriptor) +
sizeof(struct usb_hub_descriptor);
break;
case USB_DT_STRING:
switch (swap_16(req->value) & 0xff) {
case 0: /* Language */
srcptr = "\4\3\1\0";
srclen = 4;
break;
case 1: /* Vendor */
srcptr = "\20\3P\0h\0i\0l\0i\0p\0s\0";
srclen = 16;
break;
case 2: /* Product */
srcptr = "\12\3E\0H\0C\0I\0";
srclen = 10;
break;
default:
goto unknown;
}
break;
default:
DBG("unknown value %x", swap_16(req->value));
goto unknown;
}
break;
case USB_REQ_GET_DESCRIPTOR | (( USB_DIR_IN | USB_RT_HUB) << 8):
switch (swap_16(req->value) >> 8) {
case USB_DT_HUB:
srcptr = &hub;
srclen = sizeof(hub);
break;
default:
DBG("unknown value %x", swap_16(req->value));
goto unknown;
}
break;
case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
rootdev = swap_16(req->value);
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
/* 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 DeviceRequest | USB_REQ_GET_STATUS:
memset(tmpbuf, 0, 4);
reg = swap_32(hcor->or_portsc[swap_16(req->index) - 1]);
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)
tmpbuf[0] |= USB_PORT_STAT_RESET;
if (reg & EHCI_PS_PP)
...
All the struct are defined in u-boot and you can reuse that one, I think.
Regards Michael
More information about the U-Boot
mailing list