[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cdi-devel] [PATCH 2/2] [usb] No memory error, remove STALL
From: Max Reitz <max@xxxxxxxxxx>
* This is a REALLY ugly patch, though it works. At startup, the
driver allocates about 1 MB of memory per UHC and uses that for the
queue heads, the transfer descriptors and the packet buffer maximum
packet size: 1 kB).
+ STALL is now removed via the ClearEndpointFeature(ENDPOINT_STALL)
request.
Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
usb/include/uhci.h | 24 ++++++---
usb/include/usb.h | 1 -
usb/main.c | 18 +++----
usb/msd.c | 45 +++++++++++------
usb/uhci.c | 143 ++++++++++++++++++++++++++++-----------------------
5 files changed, 131 insertions(+), 100 deletions(-)
diff --git a/usb/include/uhci.h b/usb/include/uhci.h
index 240619b..d1a7c61 100644
--- a/usb/include/uhci.h
+++ b/usb/include/uhci.h
@@ -53,17 +53,10 @@
#define RPORT_DEVICE 0x0001
-struct uhci {
- struct hci gen_hci;
- uint16_t pbase;
- uintptr_t phys_frame_list;
- uint32_t* frame_list;
- int root_ports;
-};
-
struct uhci_qh {
volatile uint32_t next;
volatile uint32_t transfer;
+ uint32_t align[2]; //Fürs korrekte Alignment (an 16 Bytes)
} __attribute__((packed));
struct uhci_td {
@@ -103,4 +96,19 @@ struct transfer {
volatile int error;
};
+struct uhci {
+ struct hci gen_hci;
+ uint16_t pbase;
+ uintptr_t phys_frame_list;
+ uint32_t* frame_list;
+ int root_ports;
+ struct uhci_qh* queue_heads;
+ struct uhci_qh* phys_queue_heads;
+ struct uhci_td* transfer_descs;
+ struct uhci_td* phys_transfer_descs;
+ //FIXME Das tut einfach nur weh.
+ void** data_buffers;
+ uintptr_t* phys_data_buffers;
+};
+
#endif
diff --git a/usb/include/usb.h b/usb/include/usb.h
index 9a94b2e..459a340 100644
--- a/usb/include/usb.h
+++ b/usb/include/usb.h
@@ -251,7 +251,6 @@ struct usb_device {
struct config_desc* config;
struct interface_desc* interface;
struct class_data* classd;
- int stalled;
int locked;
int expects;
int data_toggle;
diff --git a/usb/main.c b/usb/main.c
index 7250092..b09bfba 100644
--- a/usb/main.c
+++ b/usb/main.c
@@ -52,6 +52,9 @@ static int usb_dev_ids = 1;
static void usb_init(void);
static void enumerate_hub(struct usb_device* usbdev);
+static void* do_control(struct usb_device* device, int direction, void* buffer,
+ int length, int rtype, int recipient, int request, int value,
+ int index);
#ifdef CDI_STANDALONE
int main(void)
@@ -119,11 +122,6 @@ int usb_do_packet(struct usb_device* device, struct usb_packet* packet)
//dprintf("TOD: %s\n", tod_name[tod_short]);
device->expects = next_data_type[tod_short];
packet->type &= 0xFF;
- if (device->stalled) {
- //TODO: Irgendwie entstallen, evtl.? oO
- dprintf("Zugriff auf stalled-Gerät verweigert.\n");
- return USB_STALLED;
- }
struct usb_packet send_packet = {
.type = packet->type,
@@ -152,10 +150,9 @@ int usb_do_packet(struct usb_device* device, struct usb_packet* packet)
printf("[usb] ENDPOINT %i DES GERÃ?TS %i STALLED!\n",
packet->endpoint->endpoint_address,
device->id);
- for (;;) {
- }
- device->stalled = 1;
- break;
+ do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
+ REC_ENDPOINT, CLEAR_FEATURE, 0,
+ packet->endpoint->endpoint_address);
}
}
return error;
@@ -171,9 +168,11 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
no_data = direction & NO_DATA;
direction &= 0x80;
+
if ((direction != HOST_TO_DEV) || !length || (buffer == NULL)) {
buffer = malloc(length);
}
+
setup->request_type = direction | (rtype & 0x60) | (recipient & 0x1F);
setup->request = request;
setup->value = value;
@@ -315,7 +314,6 @@ static void enum_device(struct usb_device* usbdev)
int i, id;
//Gerät und EP0 initialisieren
- usbdev->stalled = 0;
usbdev->locked = 0;
usbdev->expects = USB_TOD_SETUP | USB_TOD_COMMAND;
usbdev->data_toggle = 0;
diff --git a/usb/msd.c b/usb/msd.c
index 6fb8a42..415657e 100644
--- a/usb/msd.c
+++ b/usb/msd.c
@@ -366,6 +366,8 @@ static inline int tsl(volatile int* variable)
return rval;
}
+#define MAX_ACCESS_BLOCKS 32
+
static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
uint16_t sectors, void* buffer,
size_t length);
@@ -379,6 +381,7 @@ static int msd_cdi_read(struct cdi_storage_device* strgdev, uint64_t start,
int i;
#endif
struct usb_device* usbdev = ((struct cdi_msd*) strgdev)->usb_device;
+ int j, bbs;
fdprintf("read(%i, %i)\n", (int) start, (int) count);
start += ((struct cdi_msd*) strgdev)->offset;
@@ -392,17 +395,23 @@ static int msd_cdi_read(struct cdi_storage_device* strgdev, uint64_t start,
__asm__ __volatile__ ("hlt");
#endif
}
+ for (j = 0; j < count; j += MAX_ACCESS_BLOCKS) {
#ifdef WAIT_FOR_MSD_READY
- for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
- cdi_sleep_ms(20);
- }
+ for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
+ cdi_sleep_ms(20);
+ }
#endif
- error = msd_read(usbdev, start, count, buffer, count * bs);
- if (error != USB_NO_ERROR) {
- dprintf("Lesefehler 0x%X bei Block %lld.\n", error, start);
- usbdev->locked = 0;
- return -1;
+ bbs = (count - j > MAX_ACCESS_BLOCKS) ? MAX_ACCESS_BLOCKS : count - j;
+ _dprintf("/");
+ error = msd_read(usbdev, start + j, bbs, buffer + j * bs, bbs * bs);
+ _dprintf("\\");
+ if (error != USB_NO_ERROR) {
+ dprintf("Lesefehler 0x%X bei Block %lld.\n", error, start + j);
+ usbdev->locked = 0;
+ return -1;
+ }
}
+ _dprintf("\n");
usbdev->locked = 0;
return 0;
}
@@ -476,6 +485,7 @@ static int msd_cdi_write(struct cdi_storage_device* strgdev, uint64_t start,
int i;
#endif
struct usb_device* usbdev = ((struct cdi_msd*) strgdev)->usb_device;
+ int j, bbs;
fdprintf("write(%i, %i)\n", (int) start, (int) count);
start += ((struct cdi_msd*) strgdev)->offset;
@@ -489,16 +499,19 @@ static int msd_cdi_write(struct cdi_storage_device* strgdev, uint64_t start,
__asm__ __volatile__ ("hlt");
#endif
}
+ for (j = 0; j < count; j += MAX_ACCESS_BLOCKS) {
#ifdef WAIT_FOR_MSD_READY
- for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
- cdi_sleep_ms(20);
- }
+ for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
+ cdi_sleep_ms(20);
+ }
#endif
- error = msd_write(usbdev, start, count, buffer, count * bs);
- if (error != USB_NO_ERROR) {
- dprintf("Schreibfehler 0x%X bei Block %i.\n", error, start);
- usbdev->locked = 0;
- return -1;
+ bbs = (count - j > MAX_ACCESS_BLOCKS) ? MAX_ACCESS_BLOCKS : count - j;
+ error = msd_write(usbdev, start + j, bbs, buffer + j * bs, bbs * bs);
+ if (error != USB_NO_ERROR) {
+ dprintf("Schreibfehler 0x%X bei Block %i.\n", error, start + j);
+ usbdev->locked = 0;
+ return -1;
+ }
}
usbdev->locked = 0;
return 0;
diff --git a/usb/uhci.c b/usb/uhci.c
index d302364..fb1fdb3 100644
--- a/usb/uhci.c
+++ b/usb/uhci.c
@@ -95,7 +95,6 @@ void uhci_init(struct cdi_device* cdi_hci)
struct cdi_pci_resource* res;
int i, size = 0x14;
- //cdi_pci_alloc_ioports(gen_hci->pcidev);
uhci->pbase = 0;
for (i = 0; (res = cdi_list_get(gen_hci->pcidev->resources, i)) != NULL;
i++)
@@ -120,16 +119,45 @@ void uhci_init(struct cdi_device* cdi_hci)
dprintf("Frame List konnte nicht allociert werden!\n");
return;
}
+ if (cdi_alloc_phys_mem(sizeof(*uhci->queue_heads) * 1024,
+ (void**) &uhci->queue_heads,
+ (void**) &uhci->phys_queue_heads) == -1)
+ {
+ dprintf("QH-Speicher konnte nicht allociert werden!\n");
+ return;
+ }
+ if (cdi_alloc_phys_mem(sizeof(*uhci->transfer_descs) * 1024,
+ (void**) &uhci->transfer_descs,
+ (void**) &uhci->phys_transfer_descs) == -1)
+ {
+ dprintf("TD-Speicher konnte nicht allociert werden!\n");
+ return;
+ }
+ //FIXME Das tut dermaÃ?en weh.
+ uhci->data_buffers = malloc(sizeof(void*) * 1024);
+ uhci->phys_data_buffers = malloc(sizeof(uintptr_t) * 1024);
+ for (i = 0; i < 1024; i++) {
+ if (cdi_alloc_phys_mem(1024, &uhci->data_buffers[i],
+ (void**) &uhci->phys_data_buffers[i]) == -1)
+ {
+ dprintf("Paketspeicher konnte nicht allociert werden!\n");
+ return;
+ }
+ }
cdi_register_irq(gen_hci->pcidev->irq, &uhci_handler, cdi_hci);
uhci->root_ports = (size - 0x10) >> 1;
- if (uhci->root_ports > 7) { //Laut Linuxkernel ist das so "weird", dass da was nicht stimmen kann...
+ if (uhci->root_ports > 7) { //Laut Linuxkernel ist das so "weird", dass da was nicht stimmen kann...
uhci->root_ports = 2;
}
dprintf("UHC mit I/O 0x%04X (%i Ports) und IRQ %i\n", uhci->pbase,
uhci->root_ports,
gen_hci->pcidev->irq);
for (i = 0; i < 1024; i++) {
- uhci->frame_list[i] = 1; //Invalid
+ uhci->queue_heads[i].next = 1; //Invalid
+ uhci->queue_heads[i].transfer = 1; //Invalid
+ }
+ for (i = 0; i < 1024; i++) {
+ uhci->frame_list[i] = (uintptr_t) &uhci->phys_queue_heads[i] | 2;
}
dprintf("Resetten...\n");
//HC zurücksetzen
@@ -229,80 +257,65 @@ static volatile int locked = 0;
static int uhci_do_packet(struct usb_device* usbdev, struct usb_packet* packet)
{
struct uhci* uhci = (struct uhci*) usbdev->hci;
- struct uhci_td* td;
- struct uhci_qh* qh;
- uintptr_t ptd, pqh;
- struct transfer* addr;
- int timeout;
- void* data;
- uintptr_t phys_data;
-
- int frame = (usbdev->hci->get_frame(usbdev->hci) + 3) & 0x3FF;
-
- if (cdi_alloc_phys_mem(sizeof(struct uhci_td), (void**) &td,
- (void**) &ptd) == -1)
- {
- return USB_TRIVIAL_ERROR;
+ struct uhci_td td;
+ struct transfer addr;
+ int timeout, frame;
+
+ memset(&td, 0, sizeof(td));
+ td.next = 1; //Invalid
+ td.active = 1;
+ td.ioc = 1;
+ td.data_toggle = usbdev->data_toggle;
+ td.low_speed = usbdev->low_speed;
+ td.errors = 1;
+ td.pid = packet->type;
+ td.device = usbdev->id;
+ td.endpoint = packet->endpoint->endpoint_address & 0x07;
+ td.maxlen = packet->length ? packet->length - 1 : 0x7FF;
+ while (tsl(&locked)) {
+#ifndef CDI_STANDALONE
+ __asm__ __volatile__ ("hlt");
+#endif
}
- if (cdi_alloc_phys_mem(sizeof(struct uhci_qh), (void**) &qh,
- (void**) &pqh) == -1)
- {
- return USB_TRIVIAL_ERROR;
+ frame = (cdi_inw(uhci->pbase + UHCI_FRNUM) + 5) & 0x3FF;
+ while (!(uhci->queue_heads[frame].transfer & 1)) {
+ frame++;
+ frame &= 0x3FF;
}
-
- if (packet->length == 0) {
- data = NULL;
- phys_data = 0;
+ if (!packet->length) {
+ td.buffer = 0;
} else {
- if (cdi_alloc_phys_mem(packet->length, &data,
- (void**) &phys_data) == -1)
- {
- return USB_TRIVIAL_ERROR;
- }
+ td.buffer = uhci->phys_data_buffers[frame];
if (packet->type != PACKET_IN) {
- memcpy(data, packet->data, packet->length);
+ memcpy(uhci->data_buffers[frame], packet->data, packet->length);
}
}
-
- while (tsl(&locked)) {
-#ifndef CDI_STANDALONE
- __asm__ __volatile__ ("hlt");
-#endif
- }
- qh->next = 1; //Invalid
- qh->transfer = ptd;
- memset(td, 0, sizeof(struct uhci_td));
- td->next = 1; //Invalid
- td->active = 1;
- td->ioc = 1;
- td->data_toggle = usbdev->data_toggle;
- td->low_speed = usbdev->low_speed;
- td->errors = 1;
- td->pid = packet->type;
- td->device = usbdev->id;
- td->endpoint = packet->endpoint->endpoint_address & 0x07;
- td->maxlen = packet->length ? packet->length - 1 : 0x7FF;
- td->buffer = phys_data;
- addr = malloc(sizeof(struct transfer));
- addr->virt = td;
- addr->phys = ptd;
- addr->error = 0xFFFF;
- cdi_list_push(active_transfers, addr);
- uhci->frame_list[frame] = pqh | 2;
- for (timeout = 0; !(qh->transfer & 1) && (timeout < 1000); timeout++) {
+ memcpy(&uhci->transfer_descs[frame], &td, sizeof(td));
+ uhci->queue_heads[frame].transfer =
+ (uintptr_t) &uhci->phys_transfer_descs[frame];
+ addr.virt = &uhci->transfer_descs[frame];
+ addr.phys = (uintptr_t) &uhci->phys_transfer_descs[frame];
+ addr.error = 0xFFFF;
+ cdi_list_push(active_transfers, &addr);
+ locked = 0;
+ for (timeout = 0;
+ !(uhci->queue_heads[frame].transfer & 1) && (timeout < 1000);
+ timeout++)
+ {
cdi_sleep_ms(1);
}
- while ((timeout < 1000) && (addr->error == 0xFFFF)) {
+ while ((timeout < 1000) && (addr.error == 0xFFFF)) {
#ifndef CDI_STANDALONE
__asm__ __volatile__ ("hlt");
#endif
}
- uhci->frame_list[frame] = 1;
- locked = 0;
if (packet->type == PACKET_IN) {
- memcpy(packet->data, data, packet->length);
+ memcpy(packet->data, uhci->data_buffers[frame], packet->length);
+ }
+ if (addr.error == 0xFFFF) {
+ addr.error = USB_TIMEOUT;
}
- return addr->error;
+ return addr.error;
}
static void uhci_handler(struct cdi_device* cdi_hci)
@@ -312,7 +325,7 @@ static void uhci_handler(struct cdi_device* cdi_hci)
struct transfer* addr;
struct uhci_td* td;
- if (!status) { //Also, von hier kommt der IRQ nicht.
+ if (!status) { //Also, von hier kommt der IRQ nicht.
return;
}
if (status & ~0x0001) {
@@ -320,7 +333,7 @@ static void uhci_handler(struct cdi_device* cdi_hci)
}
if (status & 0x10) {
printf("[uhci] SCHWERWIEGENDER FEHLER - HC WIRD ANGEHALTEN\n");
- cdi_outw(uhci->pbase + UHCI_USBCMD, MAXP | HCRESET); //FU!
+ cdi_outw(uhci->pbase + UHCI_USBCMD, MAXP | HCRESET); //FU!
} else {
for (i = 0; (addr = cdi_list_get(active_transfers, i)) != NULL; i++) {
td = addr->virt;
--
1.6.3.3