# HG changeset patch # User Paul Boddie # Date 1360713977 0 # Node ID 7a07c599c9e9b78e6842072e4c6db49990b5e714 # Parent a601518213673755678e362d9e88dd904aea08c1 Added tentative data transfer functionality. diff -r a60151821367 -r 7a07c599c9e9 test.c --- a/test.c Mon Feb 11 23:01:39 2013 +0000 +++ b/test.c Wed Feb 13 00:06:17 2013 +0000 @@ -17,6 +17,13 @@ #include #include #include +#include + +/* Found in Python's asdl.h. */ + +#ifndef __cplusplus +typedef enum {false, true} bool; +#endif /* Pin assignments: * @@ -45,6 +52,11 @@ #define MAX_REG_READ 0x00 #define MAX_REG_WRITE 0x02 +#define MAX_REG_RCVFIFO 1 +#define MAX_REG_SNDFIFO 2 +#define MAX_REG_SUDFIFO 4 +#define MAX_REG_RCVBC 6 +#define MAX_REG_SNDBC 7 #define MAX_REG_USBIRQ 13 #define MAX_REG_USBIEN 14 #define MAX_REG_USBCTL 15 @@ -54,7 +66,9 @@ #define MAX_REG_HIRQ 25 #define MAX_REG_HIEN 26 #define MAX_REG_MODE 27 +#define MAX_REG_PERADDR 28 #define MAX_REG_HCTL 29 +#define MAX_REG_HXFR 30 #define MAX_REG_HRSL 31 #define MAX_USBIRQ_OSCOKIRQ 1 @@ -98,9 +112,20 @@ #define MAX_MODE_HOST_LOWSPEED MAX_MODE_HOST_ENABLED | MAX_MODE_LOWSPEED #define MAX_HCTL_SAMPLEBUS 4 +#define MAX_HCTL_RCVTOG0 16 +#define MAX_HCTL_RCVTOG1 32 +#define MAX_HCTL_SNDTOG0 64 +#define MAX_HCTL_SNDTOG1 128 + +#define MAX_HXFR_SETUP 16 +#define MAX_HXFR_OUTNIN 32 +#define MAX_HXFR_HS 128 #define MAX_HRSL_JSTATUS 128 #define MAX_HRSL_KSTATUS 64 +#define MAX_HRSL_SNDTOGRD 32 +#define MAX_HRSL_RCVTOGRD 16 +#define MAX_HRSL_HRSLT 15 #define max_reg(n) ((uint8_t) (n << 3)) #define max_reg_read(n) (max_reg(n) | MAX_REG_READ) @@ -188,6 +213,193 @@ return status; } +/** + * Return whether data can be sent. + */ +bool max_can_send() +{ + uint8_t status = max_read(MAX_REG_HIRQ, NULL); + + return !(status & MAX_HIRQ_SNDBAVIRQ); +} + +/** + * Set the sending data toggle. + */ +void max_set_send_toggle(bool toggle) +{ + max_write(MAX_REG_HCTL, toggle ? MAX_HCTL_SNDTOG1 : MAX_HCTL_SNDTOG0); +} + +/** + * Return the sending data toggle. + */ +bool max_get_send_toggle() +{ + return (max_read(MAX_REG_HRSL, NULL) & MAX_HRSL_SNDTOGRD) != 0; +} + +/** + * Set the receiving data toggle. + */ +void max_set_recv_toggle(bool toggle) +{ + max_write(MAX_REG_HCTL, toggle ? MAX_HCTL_RCVTOG1 : MAX_HCTL_RCVTOG0); +} + +/** + * Return the receiving data toggle. + */ +bool max_get_recv_toggle() +{ + return (max_read(MAX_REG_HRSL, NULL) & MAX_HRSL_RCVTOGRD) != 0; +} + +/** + * Wait for handshake/timeout after a transfer. + */ +uint8_t max_wait_transfer(uint8_t status) +{ + while (!(status & MAX_HIRQ_HXFRDNIRQ)) + { + status = max_read(MAX_REG_HIRQ, NULL); + } + + return status; +} + +/** + * Send HS payload for control transfers. + */ +uint8_t max_send_hs() +{ + uint8_t status = max_write(MAX_REG_HXFR, MAX_HXFR_HS); + return max_wait_transfer(status); +} + +/** + * Write the given data to the FIFO. + */ +void max_write_fifo(uint8_t endpoint, uint8_t *data, uint8_t len) +{ + uint8_t count; + + for (count = 0; count < len; count++) + { + max_write(endpoint ? MAX_REG_SNDFIFO : MAX_REG_SUDFIFO, data[count]); + } + + if (endpoint) + max_write(MAX_REG_SNDBC, len); +} + +/** + * Read the data from the FIFO. + */ +void max_read_fifo(uint8_t *data, uint8_t *len, uint8_t *datalimit) +{ + uint8_t count, received = max_read(MAX_REG_RCVBC, NULL); + + *len += received; + + for (count = 0; (count < received) && (data < datalimit); count++) + { + *data++ = max_read(MAX_REG_RCVFIFO, NULL); + } +} + +/** + * Send a request to the given address and endpoint, using the supplied data + * payload with the given length, indicating the preserved toggle state of the + * endpoint (which will be updated). + */ +uint8_t max_send(uint8_t address, uint8_t endpoint, uint8_t *data, uint8_t len, bool *toggle) +{ + uint8_t status, hrsl = 0; + + max_write_fifo(endpoint, data, len); + + max_set_send_toggle(*toggle); + + /* Set the address. */ + + max_write(MAX_REG_PERADDR, address); + + /* Initiate the transfer. */ + + do + { + status = max_write(MAX_REG_HXFR, endpoint | MAX_HXFR_OUTNIN | (endpoint ? 0 : MAX_HXFR_SETUP)); + status = max_wait_transfer(status); + + /* Test for usable data. */ + + if (!(status & MAX_HIRQ_SNDBAVIRQ)) + continue; + + hrsl = max_read(MAX_REG_HRSL, &status); + } + while ((hrsl & MAX_HRSL_HRSLT) != 0); + + *toggle = max_get_send_toggle(); + + return status; +} + +/** + * Make a request for data from the given address and endpoint, collecting it in + * the supplied buffer with the given length, indicating the preserved toggle + * state of the endpoint (which will be updated), and providing optional setup + * data (for control transfers). The length will be updated to indicate the + * total length of the received data. + */ +uint8_t max_recv(uint8_t address, uint8_t endpoint, uint8_t *data, uint8_t *len, bool *toggle, uint8_t *setup) +{ + uint8_t *datalimit = data + *len; + uint8_t status, hrsl = 0; + + /* Write control transfer information, if appropriate. */ + + if (!endpoint) + max_write_fifo(endpoint, setup, 8); + + max_set_send_toggle(*toggle); + + /* Set the address. */ + + max_write(MAX_REG_PERADDR, address); + + /* Initiate the transfer. */ + + do + { + status = max_write(MAX_REG_HXFR, endpoint); + status = max_wait_transfer(status); + + /* Test for usable data. */ + + if (!(status & MAX_HIRQ_RCVDAVIRQ)) + continue; + + hrsl = max_read(MAX_REG_HRSL, &status); + } + while ((hrsl & MAX_HRSL_HRSLT) != 0); + + do + { + max_read_fifo(data, len, datalimit); + + /* Indicate that all data has been read. */ + + status = max_write(MAX_REG_HIRQ, MAX_HIRQ_RCVDAVIRQ); + } + while (status & MAX_HIRQ_RCVDAVIRQ); + + *toggle = max_get_send_toggle(); + + return status; +} + void chipreset() { printf("Resetting...\n"); @@ -239,7 +451,11 @@ while (!samplebusready()); } -void devicechanged() +/** + * Handle the connection or disconnection of a device, returning true if the + * device is now connected or false otherwise. + */ +bool devicechanged() { uint8_t hrsl, mode; @@ -273,7 +489,23 @@ printf("Device is full speed.\n"); max_write(MAX_REG_MODE, MAX_MODE_HOST_FULLSPEED); } + + return true; } + + return false; +} + +void setup_packet(uint8_t *setup, uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, uint16_t length) +{ + setup[0] = request_type; + setup[1] = request; + setup[2] = value & 0xff; + setup[3] = value >> 8; + setup[4] = index & 0xff; + setup[5] = index >> 8; + setup[6] = length & 0xff; + setup[7] = length >> 8; } void shutdown(int signum) @@ -287,6 +519,8 @@ { uint8_t status = 0, revision = 0; uint16_t count; + bool in_toggle = 0; + uint8_t data[64], len = 64, setup[8]; signal(SIGINT, &shutdown); @@ -361,8 +595,12 @@ { status = max_read(MAX_REG_HIRQ, NULL); - if (status & MAX_HIRQ_CONDETIRQ) - devicechanged(); + if ((status & MAX_HIRQ_CONDETIRQ) && devicechanged() && max_can_send()) + { + printf("Sending control request to address 0, endpoint 0...\n"); + setup_packet(setup, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, USB_DT_DEVICE, 0, USB_DT_DEVICE_SIZE); + max_recv(0, 0, data, &len, &in_toggle, setup); + } if (status & MAX_HIRQ_SUSDNIRQ) printf("Suspend done.\n"); if (status & MAX_HIRQ_BUSEVENTIRQ)