USB updates from our internal tree
- support MMC2 devices - make usb stack more solid - drop some unused functions - fix lowspeed/speed naming - add support for "quirks" - improve usbhid driver Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Joseph Smith <joe@settoplinux.org> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5299 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
e5d30b78b7
commit
b56f2d0ad4
|
@ -56,6 +56,7 @@ TARGETS-$(CONFIG_COREBOOT_VIDEO_CONSOLE) += drivers/video/font8x16.o
|
|||
TARGETS-$(CONFIG_USB) += drivers/usb/usbinit.o
|
||||
TARGETS-$(CONFIG_USB) += drivers/usb/usb.o
|
||||
TARGETS-$(CONFIG_USB) += drivers/usb/usb_dev.o
|
||||
TARGETS-$(CONFIG_USB) += drivers/usb/quirks.o
|
||||
TARGETS-$(CONFIG_USB_HUB) += drivers/usb/usbhub.o
|
||||
TARGETS-$(CONFIG_USB_UHCI) += drivers/usb/uhci.o
|
||||
TARGETS-$(CONFIG_USB_UHCI) += drivers/usb/uhci_rh.o
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
//#define USB_DEBUG
|
||||
|
||||
#include <libpayload-config.h>
|
||||
#include <usb/usb.h>
|
||||
|
||||
typedef struct {
|
||||
u16 vendor, device;
|
||||
u32 quirks;
|
||||
int interface;
|
||||
} usb_quirks_t;
|
||||
|
||||
// IDs without a quirk don't need to be mentioned in this list
|
||||
// but some are here for easier testing.
|
||||
|
||||
usb_quirks_t usb_quirks[] = {
|
||||
/* Working chips,... remove before next release */
|
||||
{ 0x3538, 0x0054, USB_QUIRK_NONE, 0 }, // PQI 1GB
|
||||
{ 0x13fd, 0x0841, USB_QUIRK_NONE, 0 }, // Samsung SE-S084
|
||||
|
||||
/* Silence the warning for known devices with more
|
||||
* than one interface
|
||||
*/
|
||||
{ 0x1267, 0x0103, USB_QUIRK_NONE, 1 }, // Keyboard Trust KB-1800S
|
||||
{ 0x0a12, 0x0001, USB_QUIRK_NONE, 1 }, // Bluetooth Allnet ALL1575
|
||||
|
||||
/* Currently unsupported, possibly interesting devices:
|
||||
* FTDI serial: device 0x0403:0x6001 is USB 1.10 (class ff)
|
||||
* UPEK TouchChip: device 0x147e:0x2016 is USB 1.0 (class ff)
|
||||
*/
|
||||
};
|
||||
|
||||
u32 usb_quirk_check(u16 vendor, u16 device)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(usb_quirks); i++) {
|
||||
if ((usb_quirks[i].vendor == vendor) &&
|
||||
(usb_quirks[i].device == device)) {
|
||||
debug("USB quirks enabled: %08x\n",
|
||||
usb_quirks[i].quirks);
|
||||
return usb_quirks[i].quirks;
|
||||
}
|
||||
}
|
||||
|
||||
return USB_QUIRK_NONE;
|
||||
}
|
||||
|
||||
int usb_interface_check(u16 vendor, u16 device)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(usb_quirks); i++) {
|
||||
if ((usb_quirks[i].vendor == vendor) &&
|
||||
(usb_quirks[i].device == device)) {
|
||||
return usb_quirks[i].interface;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -27,6 +27,8 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
//#define USB_DEBUG
|
||||
|
||||
#include <usb/usb.h>
|
||||
#include "uhci.h"
|
||||
#include <arch/virtual.h>
|
||||
|
@ -35,8 +37,6 @@ static void uhci_start (hci_t *controller);
|
|||
static void uhci_stop (hci_t *controller);
|
||||
static void uhci_reset (hci_t *controller);
|
||||
static void uhci_shutdown (hci_t *controller);
|
||||
static int uhci_packet (usbdev_t *dev, int endp, int pid, int toggle,
|
||||
int length, u8 *data);
|
||||
static int uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize);
|
||||
static int uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq,
|
||||
int dalen, u8 *data);
|
||||
|
@ -128,6 +128,8 @@ hci_t *
|
|||
uhci_init (pcidev_t addr)
|
||||
{
|
||||
int i;
|
||||
u16 reg16;
|
||||
|
||||
hci_t *controller = new_controller ();
|
||||
|
||||
if (!controller)
|
||||
|
@ -141,7 +143,6 @@ uhci_init (pcidev_t addr)
|
|||
controller->stop = uhci_stop;
|
||||
controller->reset = uhci_reset;
|
||||
controller->shutdown = uhci_shutdown;
|
||||
controller->packet = uhci_packet;
|
||||
controller->bulk = uhci_bulk;
|
||||
controller->control = uhci_control;
|
||||
controller->create_intr_queue = uhci_create_intr_queue;
|
||||
|
@ -160,7 +161,9 @@ uhci_init (pcidev_t addr)
|
|||
uhci_stop (controller);
|
||||
mdelay (1);
|
||||
uhci_reg_write16 (controller, USBSTS, 0x3f);
|
||||
pci_write_config32 (controller->bus_address, 0xc0, 0x8f00);
|
||||
reg16 = pci_read_config16(controller->bus_address, 0xc0);
|
||||
reg16 &= 0xdf80;
|
||||
pci_write_config16 (controller->bus_address, 0xc0, reg16);
|
||||
|
||||
UHCI_INST (controller)->framelistptr = memalign (0x1000, 1024 * sizeof (flistp_t *)); /* 4kb aligned to 4kb */
|
||||
if (! UHCI_INST (controller)->framelistptr)
|
||||
|
@ -277,18 +280,6 @@ wait_for_completed_qh (hci_t *controller, qh_t *qh)
|
|||
0) ? 0 : GET_TD (phys_to_virt (qh->elementlinkptr.ptr));
|
||||
}
|
||||
|
||||
static void
|
||||
wait_for_completed_td (hci_t *controller, td_t *td)
|
||||
{
|
||||
int timeout = 10000;
|
||||
while ((td->status_active == 1)
|
||||
&& ((uhci_reg_read16 (controller, USBSTS) & 2) == 0)
|
||||
&& (timeout-- > 0)) {
|
||||
uhci_reg_mask16 (controller, USBSTS, ~0, 0); // clear resettable registers
|
||||
udelay (10);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
maxlen (int size)
|
||||
{
|
||||
|
@ -331,7 +322,7 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
|
|||
tds[0].maxlen = maxlen (drlen);
|
||||
tds[0].counter = 3;
|
||||
tds[0].data_toggle = 0;
|
||||
tds[0].lowspeed = dev->lowspeed;
|
||||
tds[0].lowspeed = dev->speed;
|
||||
tds[0].bufptr = virt_to_phys (devreq);
|
||||
tds[0].status_active = 1;
|
||||
|
||||
|
@ -343,7 +334,7 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
|
|||
tds[i].maxlen = maxlen (min (mlen, dalen));
|
||||
tds[i].counter = 3;
|
||||
tds[i].data_toggle = toggle;
|
||||
tds[i].lowspeed = dev->lowspeed;
|
||||
tds[i].lowspeed = dev->speed;
|
||||
tds[i].bufptr = virt_to_phys (data);
|
||||
tds[i].status_active = 1;
|
||||
toggle ^= 1;
|
||||
|
@ -357,7 +348,8 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
|
|||
tds[count].maxlen = maxlen (0);
|
||||
tds[count].counter = 0; /* as per linux 2.4.10 */
|
||||
tds[count].data_toggle = 1;
|
||||
tds[count].lowspeed = dev->lowspeed, tds[count].bufptr = 0;
|
||||
tds[count].lowspeed = dev->speed;
|
||||
tds[count].bufptr = 0;
|
||||
tds[count].status_active = 1;
|
||||
UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
|
||||
virt_to_phys (tds);
|
||||
|
@ -378,48 +370,6 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
|
|||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
uhci_packet (usbdev_t *dev, int endp, int pid, int toggle, int length,
|
||||
unsigned char *data)
|
||||
{
|
||||
static td_t *td = 0;
|
||||
if (td == 0)
|
||||
td = memalign (16, sizeof (td_t));
|
||||
|
||||
memset (td, 0, sizeof (td_t));
|
||||
td->ptr = 0;
|
||||
td->terminate = 1;
|
||||
td->queue_head = 0;
|
||||
|
||||
td->pid = pid;
|
||||
td->dev_addr = dev->address;
|
||||
td->endp = endp & 0xf;
|
||||
td->maxlen = maxlen (length);
|
||||
if (pid == SETUP)
|
||||
td->counter = 3;
|
||||
else
|
||||
td->counter = 0;
|
||||
td->data_toggle = toggle & 1;
|
||||
td->lowspeed = dev->lowspeed;
|
||||
td->bufptr = virt_to_phys (data);
|
||||
|
||||
td->status_active = 1;
|
||||
|
||||
UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
|
||||
virt_to_phys (td);
|
||||
UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
|
||||
UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
|
||||
wait_for_completed_td (dev->controller, td);
|
||||
if ((td->status & 0x7f) == 0) {
|
||||
//printf("successfully sent a %x packet to %x.%x\n",pid, dev->address,endp);
|
||||
// success
|
||||
return 0;
|
||||
} else {
|
||||
td_dump (td);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static td_t *
|
||||
create_schedule (int numpackets)
|
||||
{
|
||||
|
@ -454,7 +404,7 @@ fill_schedule (td_t *td, endpoint_t *ep, int length, unsigned char *data,
|
|||
else
|
||||
td->counter = 0;
|
||||
td->data_toggle = *toggle & 1;
|
||||
td->lowspeed = ep->dev->lowspeed;
|
||||
td->lowspeed = ep->dev->speed;
|
||||
td->bufptr = virt_to_phys (data);
|
||||
|
||||
td->status_active = 1;
|
||||
|
@ -484,7 +434,7 @@ uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
|
|||
{
|
||||
int maxpsize = ep->maxpacketsize;
|
||||
if (maxpsize == 0)
|
||||
fatal ("MaxPacketSize == 0!!!");
|
||||
usb_fatal ("MaxPacketSize == 0!!!");
|
||||
int numpackets = (size + maxpsize - 1 + finalize) / maxpsize;
|
||||
if (numpackets == 0)
|
||||
return 0;
|
||||
|
@ -498,6 +448,7 @@ uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
|
|||
size -= maxpsize;
|
||||
}
|
||||
if (run_schedule (ep->dev, tds) == 1) {
|
||||
debug("Stalled. Trying to clean up.\n");
|
||||
clear_stall (ep);
|
||||
free (tds);
|
||||
return 1;
|
||||
|
@ -557,7 +508,7 @@ uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming
|
|||
tds[i].maxlen = maxlen (reqsize);
|
||||
tds[i].counter = 0;
|
||||
tds[i].data_toggle = ep->toggle & 1;
|
||||
tds[i].lowspeed = ep->dev->lowspeed;
|
||||
tds[i].lowspeed = ep->dev->speed;
|
||||
tds[i].bufptr = virt_to_phys (data);
|
||||
tds[i].status_active = 1;
|
||||
ep->toggle ^= 1;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -27,6 +27,8 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
//#define USB_DEBUG
|
||||
|
||||
#include <libpayload.h>
|
||||
#include "uhci.h"
|
||||
|
||||
|
@ -43,8 +45,13 @@ uhci_rh_enable_port (usbdev_t *dev, int port)
|
|||
hci_t *controller = dev->controller;
|
||||
if (port == 1)
|
||||
port = PORTSC1;
|
||||
else
|
||||
else if (port == 2)
|
||||
port = PORTSC2;
|
||||
else {
|
||||
printf("Invalid port %d\n", port);
|
||||
return;
|
||||
}
|
||||
|
||||
uhci_reg_mask16 (controller, port, ~(1 << 12), 0); /* wakeup */
|
||||
|
||||
uhci_reg_mask16 (controller, port, ~0, 1 << 9); /* reset */
|
||||
|
@ -85,8 +92,10 @@ uhci_rh_scanport (usbdev_t *dev, int port)
|
|||
} else if (port == 2) {
|
||||
portsc = PORTSC2;
|
||||
offset = 1;
|
||||
} else
|
||||
} else {
|
||||
printf("Invalid port %d\n", port);
|
||||
return;
|
||||
}
|
||||
int devno = RH_INST (dev)->port[offset];
|
||||
if ((dev->controller->devices[devno] != 0) && (devno != -1)) {
|
||||
usb_detach_device(dev->controller, devno);
|
||||
|
@ -94,16 +103,17 @@ uhci_rh_scanport (usbdev_t *dev, int port)
|
|||
}
|
||||
uhci_reg_mask16 (dev->controller, portsc, ~0, (1 << 3) | (1 << 2)); // clear port state change, enable port
|
||||
|
||||
mdelay(100); // wait for signal to stabilize
|
||||
|
||||
if ((uhci_reg_read16 (dev->controller, portsc) & 1) != 0) {
|
||||
// device attached
|
||||
|
||||
uhci_rh_disable_port (dev, port);
|
||||
uhci_rh_enable_port (dev, port);
|
||||
|
||||
int lowspeed =
|
||||
(uhci_reg_read16 (dev->controller, portsc) >> 8) & 1;
|
||||
int speed = ((uhci_reg_read16 (dev->controller, portsc) >> 8) & 1);
|
||||
|
||||
RH_INST (dev)->port[offset] = usb_attach_device(dev->controller, dev->address, portsc, lowspeed);
|
||||
RH_INST (dev)->port[offset] = usb_attach_device(dev->controller, dev->address, portsc, speed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,21 +124,30 @@ uhci_rh_report_port_changes (usbdev_t *dev)
|
|||
|
||||
stored = (RH_INST (dev)->port[0] == -1);
|
||||
real = ((uhci_reg_read16 (dev->controller, PORTSC1) & 1) == 0);
|
||||
if (stored != real)
|
||||
if (stored != real) {
|
||||
debug("change on port 1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stored = (RH_INST (dev)->port[1] == -1);
|
||||
real = ((uhci_reg_read16 (dev->controller, PORTSC2) & 1) == 0);
|
||||
if (stored != real)
|
||||
if (stored != real) {
|
||||
debug("change on port 2\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// maybe detach+attach happened between two scans?
|
||||
if ((uhci_reg_read16 (dev->controller, PORTSC1) & 2) > 0)
|
||||
// maybe detach+attach happened between two scans?
|
||||
|
||||
if ((uhci_reg_read16 (dev->controller, PORTSC1) & 2) > 0) {
|
||||
debug("possibly re-attached on port 1\n");
|
||||
return 1;
|
||||
if ((uhci_reg_read16 (dev->controller, PORTSC2) & 2) > 0)
|
||||
}
|
||||
if ((uhci_reg_read16 (dev->controller, PORTSC2) & 2) > 0) {
|
||||
debug("possibly re-attached on port 2\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// no change
|
||||
// no change
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -27,6 +27,8 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
//#define USB_DEBUG
|
||||
|
||||
#include <libpayload-config.h>
|
||||
#include <usb/usb.h>
|
||||
|
||||
|
@ -69,7 +71,7 @@ detach_controller (hci_t *controller)
|
|||
* Polls all hubs on all USB controllers, to find out about device changes
|
||||
*/
|
||||
void
|
||||
usb_poll ()
|
||||
usb_poll (void)
|
||||
{
|
||||
if (usb_hcs == 0)
|
||||
return;
|
||||
|
@ -78,8 +80,7 @@ usb_poll ()
|
|||
int i;
|
||||
for (i = 0; i < 128; i++) {
|
||||
if (controller->devices[i] != 0) {
|
||||
controller->devices[i]->poll (controller->
|
||||
devices[i]);
|
||||
controller->devices[i]->poll (controller->devices[i]);
|
||||
}
|
||||
}
|
||||
controller = controller->next;
|
||||
|
@ -150,7 +151,7 @@ get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
|
|||
|
||||
if (descType == 1) {
|
||||
device_descriptor_t *dd = (device_descriptor_t *) buf;
|
||||
printf ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
|
||||
debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
|
||||
if (dd->bMaxPacketSize0 != 0)
|
||||
dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
|
||||
}
|
||||
|
@ -204,6 +205,7 @@ clear_stall (endpoint_t *ep)
|
|||
dr.wIndex = endp;
|
||||
dr.wLength = 0;
|
||||
dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
|
||||
ep->toggle = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -221,7 +223,7 @@ get_free_address (hci_t *controller)
|
|||
}
|
||||
|
||||
int
|
||||
set_address (hci_t *controller, int lowspeed)
|
||||
set_address (hci_t *controller, int speed)
|
||||
{
|
||||
int adr = get_free_address (controller); // address to set
|
||||
dev_req_t dr;
|
||||
|
@ -241,7 +243,7 @@ set_address (hci_t *controller, int lowspeed)
|
|||
usbdev_t *dev = controller->devices[adr];
|
||||
// dummy values for registering the address
|
||||
dev->address = 0;
|
||||
dev->lowspeed = lowspeed;
|
||||
dev->speed = speed;
|
||||
dev->endpoints[0].dev = dev;
|
||||
dev->endpoints[0].endpoint = 0;
|
||||
dev->endpoints[0].maxpacketsize = 8;
|
||||
|
@ -254,26 +256,25 @@ set_address (hci_t *controller, int lowspeed)
|
|||
}
|
||||
mdelay (50);
|
||||
dev->address = adr;
|
||||
dev->descriptor =
|
||||
get_descriptor (dev,
|
||||
gen_bmRequestType (device_to_host,
|
||||
standard_type, dev_recp),
|
||||
1, 0, 0);
|
||||
dev->descriptor = get_descriptor (dev, gen_bmRequestType
|
||||
(device_to_host, standard_type, dev_recp), 1, 0, 0);
|
||||
dd = (device_descriptor_t *) dev->descriptor;
|
||||
printf ("device version: %x.%x\n", dd->bcdUSB >> 8,
|
||||
dd->bcdUSB & 0xff);
|
||||
printf ("device has %x configurations\n", dd->bNumConfigurations);
|
||||
|
||||
printf ("device 0x%04x:0x%04x is USB %x.%x ",
|
||||
dd->idVendor, dd->idProduct,
|
||||
dd->bcdUSB >> 8, dd->bcdUSB & 0xff);
|
||||
dev->quirks = usb_quirk_check(dd->idVendor, dd->idProduct);
|
||||
|
||||
debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
|
||||
if (dd->bNumConfigurations == 0) {
|
||||
/* device isn't usable */
|
||||
printf ("no usable configuration!\n");
|
||||
printf ("... no usable configuration!\n");
|
||||
dev->address = 0;
|
||||
return -1;
|
||||
}
|
||||
dev->configuration =
|
||||
get_descriptor (dev,
|
||||
gen_bmRequestType (device_to_host,
|
||||
standard_type, dev_recp),
|
||||
2, 0, 0);
|
||||
|
||||
dev->configuration = get_descriptor (dev, gen_bmRequestType
|
||||
(device_to_host, standard_type, dev_recp), 2, 0, 0);
|
||||
cd = (configuration_descriptor_t *) dev->configuration;
|
||||
set_configuration (dev);
|
||||
interface_descriptor_t *interface =
|
||||
|
@ -282,24 +283,33 @@ set_address (hci_t *controller, int lowspeed)
|
|||
int i;
|
||||
int num = cd->bNumInterfaces;
|
||||
interface_descriptor_t *current = interface;
|
||||
printf ("device has %x interfaces\n", num);
|
||||
if (num>1)
|
||||
printf ("NOTICE: This driver defaults to using the first interface.\n"
|
||||
"This might be the wrong choice and lead to limited functionality\n"
|
||||
"of the device. Please report such a case to coreboot@coreboot.org\n"
|
||||
"as you might be the first.\n");
|
||||
/* we limit to the first interface, as there was no need to
|
||||
implement something else for the time being. If you need
|
||||
it, see the SetInterface and GetInterface functions in
|
||||
the USB specification, and adapt appropriately. */
|
||||
num = (num > 1) ? 1 : num;
|
||||
debug ("device has %x interfaces\n", num);
|
||||
if (num > 1) {
|
||||
int interfaces = usb_interface_check(dd->idVendor, dd->idProduct);
|
||||
if (interfaces) {
|
||||
/* Well known device, don't warn */
|
||||
num = interfaces;
|
||||
} else {
|
||||
|
||||
printf ("\nNOTICE: This driver defaults to using the first interface.\n"
|
||||
"This might be the wrong choice and lead to limited functionality\n"
|
||||
"of the device. Please report such a case to coreboot@coreboot.org\n"
|
||||
"as you might be the first.\n");
|
||||
/* we limit to the first interface, as there was no need to
|
||||
* implement something else for the time being. If you need
|
||||
* it, see the SetInterface and GetInterface functions in
|
||||
* the USB specification, and adapt appropriately.
|
||||
*/
|
||||
num = (num > 1) ? 1 : num;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < num; i++) {
|
||||
int j;
|
||||
printf (" #%x has %x endpoints, interface %x:%x, protocol %x\n", current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
|
||||
debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
|
||||
current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
|
||||
endpoint_descriptor_t *endp =
|
||||
(endpoint_descriptor_t *) (((char *) current)
|
||||
+
|
||||
current->bLength);
|
||||
+ current->bLength);
|
||||
if (interface->bInterfaceClass == 0x3)
|
||||
endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]); // ignore HID descriptor
|
||||
memset (dev->endpoints, 0, sizeof (dev->endpoints));
|
||||
|
@ -309,11 +319,12 @@ set_address (hci_t *controller, int lowspeed)
|
|||
dev->endpoints[0].direction = SETUP;
|
||||
dev->endpoints[0].type = CONTROL;
|
||||
for (j = 1; j <= current->bNumEndpoints; j++) {
|
||||
static const char *transfertypes[4] =
|
||||
{ "control", "isochronous", "bulk",
|
||||
"interrupt"
|
||||
#ifdef USB_DEBUG
|
||||
static const char *transfertypes[4] = {
|
||||
"control", "isochronous", "bulk", "interrupt"
|
||||
};
|
||||
printf (" #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", endp->wMaxPacketSize, transfertypes[endp->bmAttributes]);
|
||||
debug (" #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", endp->wMaxPacketSize, transfertypes[endp->bmAttributes]);
|
||||
#endif
|
||||
endpoint_t *ep =
|
||||
&dev->endpoints[dev->num_endp++];
|
||||
ep->dev = dev;
|
||||
|
@ -330,36 +341,94 @@ set_address (hci_t *controller, int lowspeed)
|
|||
current = (interface_descriptor_t *) endp;
|
||||
}
|
||||
}
|
||||
|
||||
int class = dd->bDeviceClass;
|
||||
if (class == 0)
|
||||
class = interface->bInterfaceClass;
|
||||
|
||||
enum { hid_device = 0x3, msc_device = 0x8, hub_device = 0x9 };
|
||||
enum {
|
||||
audio_device = 0x01,
|
||||
comm_device = 0x02,
|
||||
hid_device = 0x03,
|
||||
physical_device = 0x05,
|
||||
imaging_device = 0x06,
|
||||
printer_device = 0x07,
|
||||
msc_device = 0x08,
|
||||
hub_device = 0x09,
|
||||
cdc_device = 0x0a,
|
||||
ccid_device = 0x0b,
|
||||
security_device = 0x0d,
|
||||
video_device = 0x0e,
|
||||
healthcare_device = 0x0f,
|
||||
diagnostic_device = 0xdc,
|
||||
wireless_device = 0xe0,
|
||||
misc_device = 0xef,
|
||||
};
|
||||
|
||||
printf ("device of class %x found\n", class);
|
||||
if (class == hub_device) {
|
||||
printf ("hub found\n");
|
||||
#ifdef CONFIG_USB_HUB
|
||||
controller->devices[adr]->init = usb_hub_init;
|
||||
#else
|
||||
printf ("support not compiled in\n");
|
||||
#endif
|
||||
}
|
||||
if (class == hid_device) {
|
||||
printf ("HID found\n");
|
||||
switch (class) {
|
||||
case audio_device:
|
||||
printf("(Audio)\n");
|
||||
break;
|
||||
case comm_device:
|
||||
printf("(Communication)\n");
|
||||
break;
|
||||
case hid_device:
|
||||
printf ("(HID)\n");
|
||||
#ifdef CONFIG_USB_HID
|
||||
controller->devices[adr]->init = usb_hid_init;
|
||||
#else
|
||||
printf ("support not compiled in\n");
|
||||
printf ("NOTICE: USB HID support not compiled in\n");
|
||||
#endif
|
||||
}
|
||||
if (class == msc_device) {
|
||||
printf ("MSC found\n");
|
||||
break;
|
||||
case physical_device:
|
||||
printf("(Physical)\n");
|
||||
break;
|
||||
case imaging_device:
|
||||
printf("(Camera)\n");
|
||||
break;
|
||||
case printer_device:
|
||||
printf("(Printer)\n");
|
||||
break;
|
||||
case msc_device:
|
||||
printf ("(MSC)\n");
|
||||
#ifdef CONFIG_USB_MSC
|
||||
controller->devices[adr]->init = usb_msc_init;
|
||||
#else
|
||||
printf ("support not compiled in\n");
|
||||
printf ("NOTICE: USB MSC support not compiled in\n");
|
||||
#endif
|
||||
break;
|
||||
case hub_device:
|
||||
printf ("(Hub)\n");
|
||||
#ifdef CONFIG_USB_HUB
|
||||
controller->devices[adr]->init = usb_hub_init;
|
||||
#else
|
||||
printf ("NOTICE: USB hub support not compiled in.\n");
|
||||
#endif
|
||||
break;
|
||||
case cdc_device:
|
||||
printf("(CDC)\n");
|
||||
break;
|
||||
case ccid_device:
|
||||
printf ("(Smart Card / CCID)\n");
|
||||
break;
|
||||
case security_device:
|
||||
printf("(Content Security)\n");
|
||||
break;
|
||||
case video_device:
|
||||
printf("(Video)\n");
|
||||
break;
|
||||
case healthcare_device:
|
||||
printf("(Healthcare)\n");
|
||||
break;
|
||||
case diagnostic_device:
|
||||
printf("(Diagnostic)\n");
|
||||
break;
|
||||
case wireless_device:
|
||||
printf("(Wireless)\n");
|
||||
break;
|
||||
default:
|
||||
printf ("(unsupported class %x)\n", class);
|
||||
break;
|
||||
}
|
||||
return adr;
|
||||
}
|
||||
|
@ -373,10 +442,11 @@ usb_detach_device(hci_t *controller, int devno)
|
|||
}
|
||||
|
||||
int
|
||||
usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed)
|
||||
usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
|
||||
{
|
||||
printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
|
||||
int newdev = set_address (controller, lowspeed);
|
||||
static const char* speeds[] = { "full", "low", "high" };
|
||||
printf ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
|
||||
int newdev = set_address (controller, speed);
|
||||
if (newdev == -1)
|
||||
return -1;
|
||||
usbdev_t *newdev_t = controller->devices[newdev];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -27,6 +27,8 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// #define USB_DEBUG
|
||||
|
||||
#include <usb/usb.h>
|
||||
#include <curses.h>
|
||||
|
||||
|
@ -35,7 +37,9 @@ typedef enum { hid_proto_boot = 0, hid_proto_report = 1 } hid_proto;
|
|||
enum { hid_boot_proto_none = 0, hid_boot_proto_keyboard =
|
||||
1, hid_boot_proto_mouse = 2
|
||||
};
|
||||
#ifdef USB_DEBUG
|
||||
static const char *boot_protos[3] = { "(none)", "keyboard", "mouse" };
|
||||
#endif
|
||||
enum { GET_REPORT = 0x1, GET_IDLE = 0x2, GET_PROTOCOL = 0x3, SET_REPORT =
|
||||
0x9, SET_IDLE = 0xa, SET_PROTOCOL = 0xb
|
||||
};
|
||||
|
@ -48,72 +52,295 @@ usb_hid_destroy (usbdev_t *dev)
|
|||
|
||||
typedef struct {
|
||||
void* queue;
|
||||
hid_descriptor_t *descriptor;
|
||||
} usbhid_inst_t;
|
||||
|
||||
#define HID_INST(dev) ((usbhid_inst_t*)(dev)->data)
|
||||
|
||||
/* buffer is global to all keyboard drivers */
|
||||
int count;
|
||||
short keybuffer[16];
|
||||
/* keybuffer is global to all USB keyboards */
|
||||
static int keycount;
|
||||
#define KEYBOARD_BUFFER_SIZE 16
|
||||
static short keybuffer[KEYBOARD_BUFFER_SIZE];
|
||||
|
||||
int keypress;
|
||||
short keymap[256] = {
|
||||
-1, -1, -1, -1, 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
|
||||
|
||||
'3', '4', '5', '6', '7', '8', '9', '0',
|
||||
'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
|
||||
|
||||
']', '\\', -1, ';', '\'', '`', ',', '.',
|
||||
'/', -1, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
|
||||
|
||||
KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/* 50 */
|
||||
-1, -1, -1, -1, -1, '*', '-', '+',
|
||||
-1, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
|
||||
|
||||
KEY_UP, KEY_PPAGE, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
char *countries[36][2] = {
|
||||
{ "not supported", "us" },
|
||||
{ "Arabic", "ae" },
|
||||
{ "Belgian", "be" },
|
||||
{ "Canadian-Bilingual", "ca" },
|
||||
{ "Canadian-French", "ca" },
|
||||
{ "Czech Republic", "cz" },
|
||||
{ "Danish", "dk" },
|
||||
{ "Finnish", "fi" },
|
||||
{ "French", "fr" },
|
||||
{ "German", "de" },
|
||||
{ "Greek", "gr" },
|
||||
{ "Hebrew", "il" },
|
||||
{ "Hungary", "hu" },
|
||||
{ "International (ISO)", "iso" },
|
||||
{ "Italian", "it" },
|
||||
{ "Japan (Katakana)", "jp" },
|
||||
{ "Korean", "us" },
|
||||
{ "Latin American", "us" },
|
||||
{ "Netherlands/Dutch", "nl" },
|
||||
{ "Norwegian", "no" },
|
||||
{ "Persian (Farsi)", "ir" },
|
||||
{ "Poland", "pl" },
|
||||
{ "Portuguese", "pt" },
|
||||
{ "Russia", "ru" },
|
||||
{ "Slovakia", "sl" },
|
||||
{ "Spanish", "es" },
|
||||
{ "Swedish", "se" },
|
||||
{ "Swiss/French", "ch" },
|
||||
{ "Swiss/German", "ch" },
|
||||
{ "Switzerland", "ch" },
|
||||
{ "Taiwan", "tw" },
|
||||
{ "Turkish-Q", "tr" },
|
||||
{ "UK", "uk" },
|
||||
{ "US", "us" },
|
||||
{ "Yugoslavia", "yu" },
|
||||
{ "Turkish-F", "tr" },
|
||||
/* 36 - 255: Reserved */
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct layout_maps {
|
||||
char *country;
|
||||
short map[4][0x80];
|
||||
};
|
||||
|
||||
static struct layout_maps *map;
|
||||
|
||||
static struct layout_maps keyboard_layouts[] = {
|
||||
// #ifdef CONFIG_PC_KEYBOARD_LAYOUT_US
|
||||
{ .country = "us", .map = {
|
||||
{ /* No modifier */
|
||||
-1, -1, -1, -1, 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
/* 0x10 */
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
|
||||
/* 0x20 */
|
||||
'3', '4', '5', '6', '7', '8', '9', '0',
|
||||
'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
|
||||
/* 0x30 */
|
||||
']', '\\', -1, ';', '\'', '`', ',', '.',
|
||||
'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
|
||||
/* 0x40 */
|
||||
KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
|
||||
KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
|
||||
/* 50 */
|
||||
KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
|
||||
KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
|
||||
/* 60 */
|
||||
KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/* 70 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
},
|
||||
{ /* Shift modifier */
|
||||
-1, -1, -1, -1, 'A', 'B', 'C', 'D',
|
||||
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
||||
/* 0x10 */
|
||||
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
|
||||
/* 0x20 */
|
||||
'#', '$', '%', '^', '&', '*', '(', ')',
|
||||
'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
|
||||
/* 0x30 */
|
||||
']', '\\', -1, ':', '\'', '`', ',', '.',
|
||||
'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
|
||||
/* 0x40 */
|
||||
KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
|
||||
KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
|
||||
/* 50 */
|
||||
KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
|
||||
KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
|
||||
/* 60 */
|
||||
KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/* 70 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
},
|
||||
{ /* Alt */
|
||||
-1, -1, -1, -1, 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
/* 0x10 */
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
|
||||
/* 0x20 */
|
||||
'3', '4', '5', '6', '7', '8', '9', '0',
|
||||
'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
|
||||
/* 0x30 */
|
||||
']', '\\', -1, ';', '\'', '`', ',', '.',
|
||||
'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
|
||||
/* 0x40 */
|
||||
KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
|
||||
KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
|
||||
/* 50 */
|
||||
KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
|
||||
KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
|
||||
/* 60 */
|
||||
KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/* 70 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
},
|
||||
{ /* Shift+Alt modifier */
|
||||
-1, -1, -1, -1, 'A', 'B', 'C', 'D',
|
||||
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
||||
/* 0x10 */
|
||||
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
|
||||
/* 0x20 */
|
||||
'#', '$', '%', '^', '&', '*', '(', ')',
|
||||
'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
|
||||
/* 0x30 */
|
||||
']', '\\', -1, ':', '\'', '`', ',', '.',
|
||||
'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
|
||||
/* 0x40 */
|
||||
KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
|
||||
KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
|
||||
/* 50 */
|
||||
KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
|
||||
KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
|
||||
/* 60 */
|
||||
KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/* 70 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
}
|
||||
}},
|
||||
//#endif
|
||||
};
|
||||
|
||||
#define MOD_SHIFT (1 << 0)
|
||||
#define MOD_ALT (1 << 1)
|
||||
#define MOD_CTRL (1 << 2)
|
||||
|
||||
static void usb_hid_keyboard_queue(int ch) {
|
||||
/* ignore key presses if buffer full */
|
||||
if (keycount < KEYBOARD_BUFFER_SIZE)
|
||||
keybuffer[keycount++] = ch;
|
||||
}
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
u8 modifiers;
|
||||
u8 repeats;
|
||||
u8 keys[6];
|
||||
};
|
||||
u8 buffer[8];
|
||||
} usb_hid_keyboard_event_t;
|
||||
|
||||
#define KEYBOARD_REPEAT_MS 30
|
||||
#define INITIAL_REPEAT_DELAY 10
|
||||
#define REPEAT_DELAY 2
|
||||
|
||||
static void
|
||||
usb_hid_process_keyboard_event(usb_hid_keyboard_event_t *current,
|
||||
usb_hid_keyboard_event_t *previous)
|
||||
{
|
||||
int i, keypress = 0, modifiers = 0;
|
||||
static int lastkeypress = 0, repeat_delay = INITIAL_REPEAT_DELAY;
|
||||
|
||||
if (current->modifiers & 0x01) /* Left-Ctrl */ modifiers |= MOD_CTRL;
|
||||
if (current->modifiers & 0x02) /* Left-Shift */ modifiers |= MOD_SHIFT;
|
||||
if (current->modifiers & 0x04) /* Left-Alt */ modifiers |= MOD_ALT;
|
||||
if (current->modifiers & 0x08) /* Left-GUI */ ;
|
||||
if (current->modifiers & 0x10) /* Right-Ctrl */ modifiers |= MOD_CTRL;
|
||||
if (current->modifiers & 0x20) /* Right-Shift */ modifiers |= MOD_SHIFT;
|
||||
if (current->modifiers & 0x40) /* Right-AltGr */ modifiers |= MOD_ALT;
|
||||
if (current->modifiers & 0x80) /* Right-GUI */ ;
|
||||
|
||||
if ((current->modifiers & 0x05) && ((current->keys[0] == 0x4c) ||
|
||||
(current->keys[0]==0x63))) {
|
||||
/* vulcan nerve pinch */
|
||||
if (reset_handler)
|
||||
reset_handler();
|
||||
}
|
||||
|
||||
/* Did the event change at all? */
|
||||
if (lastkeypress && !memcmp(current, previous, sizeof(usb_hid_keyboard_event_t))) {
|
||||
/* No. Then it's a key repeat event. */
|
||||
if (repeat_delay) {
|
||||
repeat_delay--;
|
||||
} else {
|
||||
usb_hid_keyboard_queue(lastkeypress);
|
||||
repeat_delay = REPEAT_DELAY;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lastkeypress = 0;
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
int j;
|
||||
int skip = 0;
|
||||
// No more keys? skip
|
||||
if (current->keys[i] == 0)
|
||||
return;
|
||||
|
||||
for (j=0; j<6; j++) {
|
||||
if (current->keys[i] == previous->keys[j]) {
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
|
||||
/* Mask off MOD_CTRL */
|
||||
keypress = map->map[modifiers & 0x03][current->keys[i]];
|
||||
|
||||
if (modifiers & MOD_CTRL) {
|
||||
switch (keypress) {
|
||||
case 'a' ... 'z':
|
||||
keypress &= 0x1f;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (keypress == -1) {
|
||||
/* Debug: Print unknown keys */
|
||||
debug ("usbhid: <%x> %x [ %x %x %x %x %x %x ] %d\n",
|
||||
current->modifiers, current->repeats,
|
||||
current->keys[0], current->keys[1],
|
||||
current->keys[2], current->keys[3],
|
||||
current->keys[4], current->keys[5], i);
|
||||
|
||||
/* Unknown key? Try next one in the queue */
|
||||
continue;
|
||||
}
|
||||
|
||||
usb_hid_keyboard_queue(keypress);
|
||||
|
||||
/* Remember for authentic key repeat */
|
||||
lastkeypress = keypress;
|
||||
repeat_delay = INITIAL_REPEAT_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usb_hid_poll (usbdev_t *dev)
|
||||
{
|
||||
usb_hid_keyboard_event_t current;
|
||||
static usb_hid_keyboard_event_t previous = {
|
||||
.buffer = { 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
u8* buf;
|
||||
while ((buf=dev->controller->poll_intr_queue (HID_INST(dev)->queue))) {
|
||||
// FIXME: manage buf[0]=special keys, too
|
||||
int i;
|
||||
keypress = 0;
|
||||
for (i=2; i<9; i++) {
|
||||
if (buf[i] != 0)
|
||||
keypress = keymap[buf[i]];
|
||||
else
|
||||
break;
|
||||
}
|
||||
if ((keypress == -1) && (buf[2] != 0)) {
|
||||
printf ("%x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2],
|
||||
buf[3], buf[4], buf[5], buf[6], buf[7]);
|
||||
}
|
||||
if (keypress != -1) {
|
||||
/* ignore key presses if buffer full */
|
||||
if (count < 16)
|
||||
keybuffer[count++] = keypress;
|
||||
}
|
||||
memcpy(¤t.buffer, buf, 8);
|
||||
usb_hid_process_keyboard_event(¤t, &previous);
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +377,30 @@ static struct console_input_driver cons = {
|
|||
.getchar = usbhid_getchar
|
||||
};
|
||||
|
||||
|
||||
int usb_hid_set_layout (char *country)
|
||||
{
|
||||
/* FIXME should be per keyboard */
|
||||
int i;
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(keyboard_layouts); i++) {
|
||||
if (strncmp(keyboard_layouts[i].country, country,
|
||||
strlen(keyboard_layouts[i].country)))
|
||||
continue;
|
||||
|
||||
/* Found, changing keyboard layout */
|
||||
map = &keyboard_layouts[i];
|
||||
printf(" Keyboard layout '%s'\n", map->country);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Keyboard layout '%s' not found, using '%s'\n",
|
||||
country, map->country);
|
||||
|
||||
/* Nothing found, not changed */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
usb_hid_init (usbdev_t *dev)
|
||||
{
|
||||
|
@ -164,17 +415,34 @@ usb_hid_init (usbdev_t *dev)
|
|||
interface_descriptor_t *interface = (interface_descriptor_t*)(((char *) cd) + cd->bLength);
|
||||
|
||||
if (interface->bInterfaceSubClass == hid_subclass_boot) {
|
||||
printf (" supports boot interface..\n");
|
||||
printf (" it's a %s\n",
|
||||
u8 countrycode;
|
||||
debug (" supports boot interface..\n");
|
||||
debug (" it's a %s\n",
|
||||
boot_protos[interface->bInterfaceProtocol]);
|
||||
if (interface->bInterfaceProtocol == hid_boot_proto_keyboard) {
|
||||
switch (interface->bInterfaceProtocol) {
|
||||
case hid_boot_proto_keyboard:
|
||||
dev->data = malloc (sizeof (usbhid_inst_t));
|
||||
if (!dev->data)
|
||||
usb_fatal("Not enough memory for USB HID device.\n");
|
||||
printf (" configuring...\n");
|
||||
debug (" configuring...\n");
|
||||
usb_hid_set_protocol(dev, interface, hid_proto_boot);
|
||||
usb_hid_set_idle(dev, interface, 0);
|
||||
printf (" activating...\n");
|
||||
usb_hid_set_idle(dev, interface, KEYBOARD_REPEAT_MS);
|
||||
debug (" activating...\n");
|
||||
|
||||
HID_INST (dev)->descriptor =
|
||||
(hid_descriptor_t *)
|
||||
get_descriptor(dev, gen_bmRequestType
|
||||
(device_to_host, standard_type, iface_recp),
|
||||
0x21, 0, 0);
|
||||
countrycode = HID_INST(dev)->descriptor->bCountryCode;
|
||||
/* 35 countries defined: */
|
||||
if (countrycode > 35)
|
||||
countrycode = 0;
|
||||
printf (" Keyboard has %s layout (country code %02x)\n",
|
||||
countries[countrycode][0], countrycode);
|
||||
|
||||
/* Set keyboard layout accordingly */
|
||||
usb_hid_set_layout(countries[countrycode][1]);
|
||||
|
||||
// only add here, because we only support boot-keyboard HID devices
|
||||
dev->destroy = usb_hid_destroy;
|
||||
|
@ -189,24 +457,33 @@ usb_hid_init (usbdev_t *dev)
|
|||
continue;
|
||||
break;
|
||||
}
|
||||
printf (" found endpoint %x for interrupt-in\n", i);
|
||||
debug (" found endpoint %x for interrupt-in\n", i);
|
||||
/* 20 buffers of 8 bytes, for every 10 msecs */
|
||||
HID_INST(dev)->queue = dev->controller->create_intr_queue (&dev->endpoints[i], 8, 20, 10);
|
||||
count = 0;
|
||||
printf (" configuration done.\n");
|
||||
keycount = 0;
|
||||
debug (" configuration done.\n");
|
||||
break;
|
||||
case hid_boot_proto_mouse:
|
||||
printf("NOTICE: USB mice are not supported.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int usbhid_havechar (void)
|
||||
{
|
||||
return (count != 0);
|
||||
return (keycount != 0);
|
||||
}
|
||||
|
||||
int usbhid_getchar (void)
|
||||
{
|
||||
if (count == 0) return 0;
|
||||
short ret = keybuffer[0];
|
||||
memmove (keybuffer, keybuffer+1, --count);
|
||||
return ret;
|
||||
short ret;
|
||||
|
||||
if (keycount == 0)
|
||||
return 0;
|
||||
ret = keybuffer[0];
|
||||
memmove(keybuffer, keybuffer + 1, --keycount);
|
||||
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -74,9 +74,15 @@ usb_hub_scanport (usbdev_t *dev, int port)
|
|||
mdelay (20);
|
||||
|
||||
get_status (dev, port, DR_PORT, 4, buf);
|
||||
int lowspeed = (buf[0] >> 9) & 1;
|
||||
|
||||
HUB_INST (dev)->ports[port] = usb_attach_device(dev->controller, dev->address, port, lowspeed);
|
||||
/* bit 10 9
|
||||
* 0 0 full speed
|
||||
* 0 1 low speed
|
||||
* 1 0 high speed
|
||||
*/
|
||||
int speed = ((buf[0] >> 9) & 3) ;
|
||||
|
||||
HUB_INST (dev)->ports[port] = usb_attach_device(dev->controller, dev->address, port, speed);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -93,7 +99,7 @@ usb_hub_report_port_changes (usbdev_t *dev)
|
|||
return port;
|
||||
}
|
||||
|
||||
// no change
|
||||
// no change
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -131,12 +137,8 @@ usb_hub_init (usbdev_t *dev)
|
|||
if (!dev->data)
|
||||
usb_fatal("Not enough memory for USB hub.\n");
|
||||
|
||||
HUB_INST (dev)->descriptor =
|
||||
(hub_descriptor_t *) get_descriptor (dev,
|
||||
gen_bmRequestType
|
||||
(device_to_host,
|
||||
class_type, dev_recp),
|
||||
0x29, 0, 0);
|
||||
HUB_INST (dev)->descriptor = (hub_descriptor_t *) get_descriptor(dev,
|
||||
gen_bmRequestType(device_to_host, class_type, dev_recp), 0x29, 0, 0);
|
||||
HUB_INST (dev)->num_ports = HUB_INST (dev)->descriptor->bNbrPorts;
|
||||
HUB_INST (dev)->ports =
|
||||
malloc (sizeof (int) * (HUB_INST (dev)->num_ports + 1));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -30,6 +30,9 @@
|
|||
#include <libpayload-config.h>
|
||||
#include <usb/usb.h>
|
||||
#include "uhci.h"
|
||||
//#include "ohci.h"
|
||||
//#include "ehci.h"
|
||||
//#include "xhci.h"
|
||||
#include <usb/usbdisk.h>
|
||||
|
||||
/**
|
||||
|
@ -58,20 +61,19 @@ usb_controller_initialize (int bus, int dev, int func)
|
|||
/* enable busmaster */
|
||||
#define PCI_COMMAND 4
|
||||
#define PCI_COMMAND_MASTER 4
|
||||
pci_write_config32 (addr, PCI_COMMAND,
|
||||
pci_read_config32 (addr,
|
||||
PCI_COMMAND) |
|
||||
PCI_COMMAND_MASTER);
|
||||
|
||||
if (devclass == 0xc03) {
|
||||
u32 pci_command;
|
||||
|
||||
pci_command =pci_read_config32(addr, PCI_COMMAND);
|
||||
pci_command |= PCI_COMMAND_MASTER;
|
||||
pci_write_config32(addr, PCI_COMMAND, pci_command);
|
||||
|
||||
printf ("%02x:%02x.%x %04x:%04x.%d ", 0, dev, func,
|
||||
pciid >> 16, pciid & 0xFFFF, func);
|
||||
if (prog_if == 0) {
|
||||
printf ("UHCI controller\n");
|
||||
#ifdef CONFIG_USB_UHCI
|
||||
uhci_init (addr);
|
||||
usb_poll ();
|
||||
usb_poll ();
|
||||
#else
|
||||
printf ("Not supported.\n");
|
||||
#endif
|
||||
|
@ -79,7 +81,8 @@ usb_controller_initialize (int bus, int dev, int func)
|
|||
if (prog_if == 0x10) {
|
||||
printf ("OHCI controller\n");
|
||||
#ifdef CONFIG_USB_OHCI
|
||||
// ohci_init(addr);
|
||||
//ohci_init(addr);
|
||||
printf ("Not supported.\n");
|
||||
#else
|
||||
printf ("Not supported.\n");
|
||||
#endif
|
||||
|
@ -88,7 +91,18 @@ usb_controller_initialize (int bus, int dev, int func)
|
|||
if (prog_if == 0x20) {
|
||||
printf ("EHCI controller\n");
|
||||
#ifdef CONFIG_USB_EHCI
|
||||
// ehci_init(addr);
|
||||
//ehci_init(addr);
|
||||
printf ("Not supported.\n");
|
||||
#else
|
||||
printf ("Not supported.\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
if (prog_if == 0x30) {
|
||||
printf ("XHCI controller\n");
|
||||
#ifdef CONFIG_USB_XHCI
|
||||
//xhci_init(addr);
|
||||
printf ("Not supported.\n");
|
||||
#else
|
||||
printf ("Not supported.\n");
|
||||
#endif
|
||||
|
@ -106,10 +120,17 @@ int
|
|||
usb_initialize (void)
|
||||
{
|
||||
int bus, dev, func;
|
||||
/* EHCI is defined by standards to be at a
|
||||
* higher function than the USB1 controllers.
|
||||
* We don't want to init USB1 + devices just to
|
||||
* "steal" those for USB2, so make sure USB2
|
||||
* comes first.
|
||||
*/
|
||||
for (bus = 0; bus < 256; bus++)
|
||||
for (dev = 0; dev < 32; dev++)
|
||||
for (func = 0; func < 8; func++)
|
||||
for (func = 7; func >= 0 ; func--)
|
||||
usb_controller_initialize (bus, dev, func);
|
||||
usb_poll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ enum {
|
|||
msc_subclass_sff8070i = 0x5,
|
||||
msc_subclass_scsitrans = 0x6
|
||||
};
|
||||
|
||||
static const char *msc_subclass_strings[7] = {
|
||||
"(none)",
|
||||
"RBC",
|
||||
|
@ -96,19 +97,20 @@ typedef struct {
|
|||
unsigned long bCBWCBLength:5;
|
||||
unsigned long:3;
|
||||
unsigned char CBWCB[31 - 15];
|
||||
} __attribute__ ((packed))
|
||||
cbw_t;
|
||||
} __attribute__ ((packed)) cbw_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int dCSWSignature;
|
||||
unsigned int dCSWTag;
|
||||
unsigned int dCSWDataResidue;
|
||||
unsigned char bCSWStatus;
|
||||
} __attribute__ ((packed))
|
||||
csw_t;
|
||||
typedef struct {
|
||||
unsigned int dCSWSignature;
|
||||
unsigned int dCSWTag;
|
||||
unsigned int dCSWDataResidue;
|
||||
unsigned char bCSWStatus;
|
||||
} __attribute__ ((packed)) csw_t;
|
||||
|
||||
static void
|
||||
reset_transport (usbdev_t *dev)
|
||||
static int
|
||||
request_sense (usbdev_t *dev);
|
||||
|
||||
static void
|
||||
reset_transport (usbdev_t *dev)
|
||||
{
|
||||
dev_req_t dr;
|
||||
memset (&dr, 0, sizeof (dr));
|
||||
|
@ -171,7 +173,8 @@ wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
|
|||
static void
|
||||
get_csw (endpoint_t *ep, csw_t *csw)
|
||||
{
|
||||
ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1);
|
||||
if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1))
|
||||
clear_stall (ep);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -188,21 +191,23 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
|
|||
wrap_cbw (&cbw, buflen, dir, cb, cblen);
|
||||
if (dev->controller->
|
||||
bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
|
||||
clear_stall (MSC_INST (dev)->bulk_out);
|
||||
reset_transport (dev);
|
||||
return 1;
|
||||
}
|
||||
mdelay (10);
|
||||
if (dir == cbw_direction_data_in) {
|
||||
if (dev->controller->
|
||||
bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
|
||||
clear_stall (MSC_INST (dev)->bulk_in);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (dev->controller->
|
||||
bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
|
||||
clear_stall (MSC_INST (dev)->bulk_out);
|
||||
return 1;
|
||||
if (buflen > 0) {
|
||||
if (dir == cbw_direction_data_in) {
|
||||
if (dev->controller->
|
||||
bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
|
||||
clear_stall (MSC_INST (dev)->bulk_in);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (dev->controller->
|
||||
bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
|
||||
clear_stall (MSC_INST (dev)->bulk_out);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
get_csw (MSC_INST (dev)->bulk_in, &csw);
|
||||
|
@ -220,6 +225,7 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
|
|||
return 0;
|
||||
}
|
||||
// error "check condition" or reserved error
|
||||
request_sense (dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -241,6 +247,27 @@ typedef struct {
|
|||
unsigned char res4; //5
|
||||
} __attribute__ ((packed)) cmdblock6_t;
|
||||
|
||||
/**
|
||||
* Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
|
||||
* start and count from 512b units.
|
||||
* Start and count must be aligned so that they match the native
|
||||
* sector size.
|
||||
*
|
||||
* @param dev device to access
|
||||
* @param start first sector to access
|
||||
* @param n number of sectors to access
|
||||
* @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
|
||||
* @param buf buffer to read into or write from. Must be at least n*512 bytes
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
int
|
||||
readwrite_blocks_512 (usbdev_t *dev, int start, int n,
|
||||
cbw_direction dir, u8 *buf)
|
||||
{
|
||||
int blocksize_divider = MSC_INST(dev)->blocksize / 512;
|
||||
return readwrite_blocks (dev, start / blocksize_divider,
|
||||
n / blocksize_divider, dir, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads or writes a number of sequential blocks on a USB storage device.
|
||||
|
@ -251,7 +278,7 @@ typedef struct {
|
|||
* @param start first sector to access
|
||||
* @param n number of sectors to access
|
||||
* @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
|
||||
* @param buf buffer to read into or write from. Must be at least n*512 bytes
|
||||
* @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
int
|
||||
|
@ -266,10 +293,26 @@ readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
|
|||
// write
|
||||
cb.command = 0x2a;
|
||||
}
|
||||
cb.block = ntohl (start);
|
||||
cb.numblocks = ntohw (n);
|
||||
cb.block = htonl (start);
|
||||
cb.numblocks = htonw (n);
|
||||
|
||||
return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
|
||||
n * 512);
|
||||
n * MSC_INST(dev)->blocksize);
|
||||
}
|
||||
|
||||
/* Only request it, we don't interpret it.
|
||||
On certain errors, that's necessary to get devices out of
|
||||
a special state called "Contingent Allegiance Condition" */
|
||||
static int
|
||||
request_sense (usbdev_t *dev)
|
||||
{
|
||||
u8 buf[19];
|
||||
cmdblock6_t cb;
|
||||
memset (&cb, 0, sizeof (cb));
|
||||
cb.command = 0x3;
|
||||
|
||||
return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
|
||||
sizeof (cb), buf, 19);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -338,17 +381,25 @@ usb_msc_init (usbdev_t *dev)
|
|||
printf (" it uses %s protocol\n",
|
||||
msc_protocol_strings[interface->bInterfaceProtocol]);
|
||||
|
||||
if ((interface->bInterfaceProtocol != 0x50)
|
||||
|| (interface->bInterfaceSubClass != 6)) {
|
||||
|
||||
if (interface->bInterfaceProtocol != 0x50) {
|
||||
printf (" Protocol not supported.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((interface->bInterfaceSubClass != 2) && // ATAPI 8020
|
||||
(interface->bInterfaceSubClass != 5) && // ATAPI 8070
|
||||
(interface->bInterfaceSubClass != 6)) { // SCSI
|
||||
/* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
|
||||
printf (" Only SCSI over Bulk is supported.\n");
|
||||
printf (" Interface SubClass not supported.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->data = malloc (sizeof (usbmsc_inst_t));
|
||||
if (!dev->data)
|
||||
usb_fatal("Not enough memory for USB MSC device.\n");
|
||||
usb_fatal ("Not enough memory for USB MSC device.\n");
|
||||
|
||||
MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
|
||||
MSC_INST (dev)->bulk_in = 0;
|
||||
MSC_INST (dev)->bulk_out = 0;
|
||||
|
||||
|
@ -376,10 +427,11 @@ usb_msc_init (usbdev_t *dev)
|
|||
printf (" has %d luns\n", get_max_luns (dev) + 1);
|
||||
|
||||
printf (" Waiting for device to become ready... ");
|
||||
timeout = 10;
|
||||
timeout = 30 * 10; /* SCSI/ATA specs say we have to wait up to 30s. Ugh */
|
||||
while (test_unit_ready (dev) && --timeout) {
|
||||
mdelay (100);
|
||||
printf (".");
|
||||
if (!(timeout % 10))
|
||||
printf (".");
|
||||
}
|
||||
if (test_unit_ready (dev)) {
|
||||
printf ("timeout. Device not ready. Still trying...\n");
|
||||
|
|
|
@ -101,7 +101,8 @@ struct usbdev {
|
|||
int address; // usb address
|
||||
int hub; // hub, device is attached to
|
||||
int port; // port where device is attached
|
||||
int lowspeed; // 1 if lowspeed device
|
||||
int speed; // 1: lowspeed, 0: fullspeed, 2: highspeed
|
||||
u32 quirks; // quirks field. got to love usb
|
||||
void *data;
|
||||
u8 *descriptor;
|
||||
u8 *configuration;
|
||||
|
@ -119,8 +120,6 @@ struct usbdev_hc {
|
|||
void (*stop) (hci_t *controller);
|
||||
void (*reset) (hci_t *controller);
|
||||
void (*shutdown) (hci_t *controller);
|
||||
int (*packet) (usbdev_t *dev, int endp, int pid, int toggle,
|
||||
int length, u8 *data);
|
||||
int (*bulk) (endpoint_t *ep, int size, u8 *data, int finalize);
|
||||
int (*control) (usbdev_t *dev, pid_t pid, int dr_length,
|
||||
void *devreq, int data_length, u8 *data);
|
||||
|
@ -199,6 +198,16 @@ typedef struct {
|
|||
unsigned char bInterval;
|
||||
} __attribute__ ((packed)) endpoint_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned short bcdHID;
|
||||
unsigned char bCountryCode;
|
||||
unsigned char bNumDescriptors;
|
||||
unsigned char bReportDescriptorType;
|
||||
unsigned short wReportDescriptorLength;
|
||||
} __attribute__ ((packed)) hid_descriptor_t;
|
||||
|
||||
hci_t *new_controller (void);
|
||||
void detach_controller (hci_t *controller);
|
||||
void usb_poll (void);
|
||||
|
@ -213,7 +222,7 @@ void usb_hub_init (usbdev_t *dev);
|
|||
void usb_hid_init (usbdev_t *dev);
|
||||
void usb_msc_init (usbdev_t *dev);
|
||||
|
||||
int set_address (hci_t *controller, int lowspeed);
|
||||
int set_address (hci_t *controller, int speed);
|
||||
|
||||
u8 *get_descriptor (usbdev_t *dev, unsigned char bmRequestType,
|
||||
int descType, int descIdx, int langID);
|
||||
|
@ -225,7 +234,28 @@ gen_bmRequestType (dev_req_dir dir, dev_req_type type, dev_req_recp recp)
|
|||
}
|
||||
|
||||
void usb_detach_device(hci_t *controller, int devno);
|
||||
int usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed);
|
||||
int usb_attach_device(hci_t *controller, int hubaddress, int port, int speed);
|
||||
|
||||
u32 usb_quirk_check(u16 vendor, u16 device);
|
||||
int usb_interface_check(u16 vendor, u16 device);
|
||||
|
||||
#define USB_QUIRK_MSC_FORCE_PROTO_SCSI (1 << 0)
|
||||
#define USB_QUIRK_MSC_FORCE_PROTO_ATAPI (1 << 1)
|
||||
#define USB_QUIRK_MSC_FORCE_PROTO_UFI (1 << 2)
|
||||
#define USB_QUIRK_MSC_FORCE_PROTO_RBC (1 << 3)
|
||||
#define USB_QUIRK_MSC_FORCE_TRANS_BBB (1 << 4)
|
||||
#define USB_QUIRK_MSC_FORCE_TRANS_CBI (1 << 5)
|
||||
#define USB_QUIRK_MSC_FORCE_TRANS_CBI_I (1 << 6)
|
||||
#define USB_QUIRK_MSC_NO_TEST_UNIT_READY (1 << 7)
|
||||
#define USB_QUIRK_MSC_SHORT_INQUIRY (1 << 8)
|
||||
#define USB_QUIRK_TEST (1 << 31)
|
||||
#define USB_QUIRK_NONE 0
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define debug(x...) printf(x);
|
||||
#else
|
||||
#define debug(x...)
|
||||
#endif
|
||||
|
||||
void usb_fatal(const char *message) __attribute__ ((noreturn));
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the libpayload project.
|
||||
*
|
||||
* Copyright (C) 2008 coresystems GmbH
|
||||
* Copyright (C) 2008-2010 coresystems GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -32,6 +32,7 @@
|
|||
typedef struct {
|
||||
unsigned int blocksize;
|
||||
unsigned int numblocks;
|
||||
unsigned int protocol;
|
||||
endpoint_t *bulk_in;
|
||||
endpoint_t *bulk_out;
|
||||
} usbmsc_inst_t;
|
||||
|
@ -41,7 +42,7 @@ typedef struct {
|
|||
typedef enum { cbw_direction_data_in = 0x80, cbw_direction_data_out = 0
|
||||
} cbw_direction;
|
||||
|
||||
int readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir,
|
||||
u8 *buf);
|
||||
int readwrite_blocks_512 (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf);
|
||||
int readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue