/*
* 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
* SUCH DAMAGE.
*/
+//#define USB_DEBUG
+
#include <libpayload.h>
#include "uhci.h"
+#include "uhci_private.h"
typedef struct {
int port[2];
hci_t *controller = dev->controller;
if (port == 1)
port = PORTSC1;
- else
+ else if (port == 2)
port = PORTSC2;
- uhci_reg_mask16 (controller, port, ~(1 << 12), 0); /* wakeup */
+ else {
+ debug("Invalid port %d\n", port);
+ return;
+ }
+
+ uhci_reg_write16(controller, port,
+ uhci_reg_read16(controller, port) & ~(1 << 12)); /* wakeup */
- uhci_reg_mask16 (controller, port, ~0, 1 << 9); /* reset */
+ uhci_reg_write16(controller, port,
+ uhci_reg_read16(controller, port) | 1 << 9); /* reset */
mdelay (30); // >10ms
- uhci_reg_mask16 (controller, port, ~(1 << 9), 0);
+ uhci_reg_write16(controller, port,
+ uhci_reg_read16(controller, port) & ~(1 << 9));
mdelay (1); // >5.3us per spec, <3ms because some devices make trouble
- uhci_reg_mask16 (controller, port, ~0, 1 << 2); /* enable */
+ uhci_reg_write16(controller, port,
+ uhci_reg_read16(controller, port) | 1 << 2); /* enable */
do {
value = uhci_reg_read16 (controller, port);
mdelay (1);
port = PORTSC2;
if (port == 1)
port = PORTSC1;
- uhci_reg_mask16 (controller, port, ~4, 0);
+ uhci_reg_write16(controller, port,
+ uhci_reg_read16(controller, port) & ~4);
int value;
do {
value = uhci_reg_read16 (controller, port);
} else if (port == 2) {
portsc = PORTSC2;
offset = 1;
- } else
+ } else {
+ debug("Invalid port %d\n", port);
return;
+ }
int devno = RH_INST (dev)->port[offset];
- if (devno != -1) {
- dev->controller->devices[devno].destroy (&dev->controller->
- devices[devno]);
- init_device_entry (dev->controller, devno);
+ if ((dev->controller->devices[devno] != 0) && (devno != -1)) {
+ usb_detach_device(dev->controller, devno);
RH_INST (dev)->port[offset] = -1;
}
- uhci_reg_mask16 (dev->controller, portsc, ~0, (1 << 3) | (1 << 2)); // clear port state change, enable port
+ uhci_reg_write16(dev->controller, portsc,
+ uhci_reg_read16(dev->controller, portsc) | (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) {
- int newdev;
- usbdev_t *newdev_t;
// device attached
uhci_rh_disable_port (dev, port);
uhci_rh_enable_port (dev, port);
- int lowspeed =
- (uhci_reg_read16 (dev->controller, portsc) >> 8) & 1;
- printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
-
- newdev = set_address (dev->controller, lowspeed);
- if (newdev == -1)
- return;
- newdev_t = &dev->controller->devices[newdev];
- RH_INST (dev)->port[offset] = newdev;
- newdev_t->address = newdev;
- newdev_t->hub = dev->address;
- newdev_t->port = portsc;
- // determine responsible driver
- newdev_t->init (newdev_t);
+ int speed = ((uhci_reg_read16 (dev->controller, portsc) >> 8) & 1);
+
+ RH_INST (dev)->port[offset] = usb_attach_device(dev->controller, dev->address, portsc, speed);
}
}
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?
-// maybe detach+attach happened between two scans?
- if ((uhci_reg_read16 (dev->controller, PORTSC1) & 2) > 0)
+ 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;
}
uhci_rh_enable_port (dev, 1);
uhci_rh_enable_port (dev, 2);
dev->data = malloc (sizeof (rh_inst_t));
+ if (!dev->data)
+ fatal("Not enough memory for UHCI RH.\n");
+
RH_INST (dev)->port[0] = -1;
RH_INST (dev)->port[1] = -1;