1
0
mirror of https://github.com/gdsports/USBHost_t36 synced 2024-11-21 08:35:03 -05:00

Add halt qTD and race-free qTD queuing method

This commit is contained in:
PaulStoffregen 2017-02-05 07:24:58 -08:00
parent f4d60b7594
commit 897cf23bf3
2 changed files with 38 additions and 73 deletions

35
host.h
View File

@ -49,7 +49,6 @@ struct Pipe_struct {
Device_t *device;
uint8_t type; // 0=control, 1=isochronous, 2=bulk, 3=interrupt
uint8_t direction; // 0=out, 1=in
//uint8_t endpoint; // 0 to 15
//uint8_t data01; // next packet DATA0 or DATA1
uint8_t unusedbyte[2];
uint32_t unused[2];
@ -70,40 +69,6 @@ struct Transfer_struct {
uint32_t unused[5];
};
#if 0
#define EHCI_QH_CAPABILITIES1( \
nak_count_reload, \
control_endpoint_flag, \
max_packet_length, \
head_of_list, \
data_toggle_control, \
speed, \
endpoint_number, \
inactivate, \
address) \
( ((nak_count_reload) << 28) | \
((control_endpoint_flag) << 27) | \
((max_packet_length) << 16) | \
((head_of_list) << 15) | \
((data_toggle_control) << 14) | \
((speed) << 12) | \
((endpoint_number) << 8) | \
((inactivate) << 7) | \
((address) << 0) )
#define EHCI_QH_CAPABILITIES2( \
high_bw_mult, \
hub_port_number, \
hub_address, \
split_completion_mask, \
interrupt_schedule_mask) \
( ((high_bw_mult) << 30) | \
((hub_port_number) << 23) | \
((hub_address) << 16) | \
((split_completion_mask) << 8) | \
((interrupt_schedule_mask) << 0) )
#endif
Device_t * allocate_Device(void);
void free_Device(Device_t *q);
Pipe_t * allocate_Pipe(void);

View File

@ -279,9 +279,7 @@ Device_t * new_Device(uint32_t speed, uint32_t hub_addr, uint32_t hub_port)
dev->setup.wValue = 0x0100;
dev->setup.wIndex = 0x0000;
dev->setup.wLength = 8;
Transfer_t *transfer = new_Transfer(dev->control_pipe, buffer, 8);
//print(dev->control_pipe);
if (transfer) queue_Transfer(transfer);
new_Transfer(dev->control_pipe, buffer, 8);
return dev;
}
@ -309,21 +307,24 @@ Pipe_t * new_Pipe(Device_t *dev, uint32_t type, uint32_t endpoint, uint32_t dire
uint32_t max_packet_len)
{
Pipe_t *pipe;
Transfer_t *halt;
uint32_t c=0, dtc=0;
Serial.println("new_Pipe");
pipe = allocate_Pipe();
if (!pipe) return NULL;
halt = allocate_Transfer();
if (!halt) {
free_Pipe(pipe);
return NULL;
}
memset(pipe, 0, sizeof(Pipe_t));
memset(halt, 0, sizeof(Transfer_t));
halt->qtd.next = 1;
halt->qtd.token = 0x40;
pipe->device = dev;
pipe->qh.current = 0;
pipe->qh.next = 1;
pipe->qh.next = (uint32_t)halt;
pipe->qh.alt_next = 1;
pipe->qh.token = 0;
pipe->qh.buffer[0] = 0;
pipe->qh.buffer[1] = 0;
pipe->qh.buffer[2] = 0;
pipe->qh.buffer[3] = 0;
pipe->qh.buffer[4] = 0;
pipe->direction = direction;
pipe->type = type;
if (type == 0) {
@ -339,7 +340,7 @@ Pipe_t * new_Pipe(Device_t *dev, uint32_t type, uint32_t endpoint, uint32_t dire
dtc, dev->speed, endpoint, 0, dev->address);
pipe->qh.capabilities[1] = QH_capabilities2(1, dev->hub_port,
dev->hub_address, 0, 0);
#if 1
if (type == 0 || type == 2) {
// control or bulk: add to async queue
Pipe_t *list = (Pipe_t *)USBHS_ASYNCLISTADDR;
@ -359,7 +360,6 @@ Pipe_t * new_Pipe(Device_t *dev, uint32_t type, uint32_t endpoint, uint32_t dire
// interrupt: add to periodic schedule
// TODO: link it into the periodic table
}
#endif
return pipe;
}
@ -388,13 +388,13 @@ void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len,
t->qtd.buffer[4] = addr + 0x4000;
}
// Create a list of Transfers
// Create a Transfer and queue it
//
Transfer_t * new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len)
bool new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len)
{
Serial.println("new_Transfer");
Transfer_t *transfer = allocate_Transfer();
if (!transfer) return NULL;
if (!transfer) return false;
transfer->pipe = pipe;
if (pipe->type == 0) {
// control transfer
@ -402,19 +402,19 @@ Transfer_t * new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len)
uint32_t status_direction;
if (len > 16384) {
free_Transfer(transfer);
return NULL;
return false;
}
status = allocate_Transfer();
if (!status) {
free_Transfer(transfer);
return NULL;
return false;
}
if (len > 0) {
data = allocate_Transfer();
if (!data) {
free_Transfer(transfer);
free_Transfer(status);
return NULL;
return false;
}
init_qTD(data, buffer, len, pipe->direction, 1, false);
transfer->qtd.next = (uint32_t)data;
@ -434,26 +434,26 @@ Transfer_t * new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len)
} else {
// bulk, interrupt or isochronous transfer
free_Transfer(transfer);
return NULL;
}
return transfer;
}
void queue_Transfer(Transfer_t *transfer)
{
Serial.println("queue_Transfer");
Pipe_t *pipe = transfer->pipe;
Transfer_t *last = (Transfer_t *)(pipe->qh.next);
if ((uint32_t)last & 1) {
pipe->qh.next = (uint32_t)transfer;
Serial.println(" first on QH");
} else {
while ((last->qtd.next & 1) == 0) last = (Transfer_t *)(last->qtd.next);
// TODO: what happens if qTD is completed before we write to it?
last->qtd.next = (uint32_t)transfer;
Serial.println(" added to qTD list");
return false;
}
Transfer_t *halt = (Transfer_t *)(pipe->qh.next);
while (!(halt->qtd.token & 0x40)) halt = (Transfer_t *)(halt->qtd.next);
uint32_t token = transfer->qtd.token;
transfer->qtd.token = 0x40; // transfer becomes new halt qTD
halt->qtd.next = transfer->qtd.next;
halt->qtd.alt_next = transfer->qtd.alt_next;
halt->qtd.buffer[0] = transfer->qtd.buffer[0];
halt->qtd.buffer[1] = transfer->qtd.buffer[1];
halt->qtd.buffer[2] = transfer->qtd.buffer[2];
halt->qtd.buffer[3] = transfer->qtd.buffer[3];
halt->qtd.buffer[4] = transfer->qtd.buffer[4];
halt->pipe = pipe;
Transfer_t *last = transfer;
while ((uint32_t)(last->qtd.next) != 1) last = (Transfer_t *)(last->qtd.next);
last->qtd.next = (uint32_t)transfer;
transfer->qtd.next = 1;
halt->qtd.token = token; // old halt becomes new transfer
return true;
}