# HG changeset patch # User Paul Boddie # Date 1362181134 0 # Node ID 26c62ea1aef90455d8da5375dcae620290f4bf76 # Parent d64ec78641fc4f380abd424aff6b96eea7452a11 Added device address setting and retrieval of the languages string descriptor. Made an inbound payload control request convenience function and added a descriptor type macro for setup packet initialisation. diff -r d64ec78641fc -r 26c62ea1aef9 test.c --- a/test.c Sun Feb 24 01:18:13 2013 +0000 +++ b/test.c Fri Mar 01 23:38:54 2013 +0000 @@ -46,8 +46,11 @@ { bool in_toggle, out_toggle; struct usb_device_descriptor desc; + uint8_t address; } max_device; +static uint16_t next_address = 1; + /* Pin assignments: * * Sniffer UBB Shield @@ -157,6 +160,8 @@ #define max_reg_read(n) (max_reg(n) | MAX_REG_READ) #define max_reg_write(n) (max_reg(n) | MAX_REG_WRITE) +#define usb_descriptor_type(n) ((uint16_t) (n << 8)) + void spi_begin() { CLR(MAX_SS); @@ -329,48 +334,6 @@ } /** - * Send a control request consisting of the given setup data. - */ -uint8_t max_control(uint8_t *setup) -{ - uint8_t status, hrsl; - - max_write_fifo(0, setup, 8); - - /* Initiate the transfer. */ - - do - { - status = max_write(MAX_REG_HXFR, MAX_HXFR_SETUP); - status = max_wait_transfer(status); - hrsl = max_read(MAX_REG_HRSL, &status); - } - while (hrsl & MAX_HRSL_HRSLT); - - return status; -} - -/** - * Perform a status transaction as part of a larger control transaction. - * The out parameter is used to indicate the kind of status transfer to be - * performed and should be the inverse of the control transfer direction. - */ -uint8_t max_control_status(bool out) -{ - uint8_t status, hrsl; - - do - { - status = max_write(MAX_REG_HXFR, MAX_HXFR_HS | (out ? MAX_HXFR_OUTNIN : 0)); - status = max_wait_transfer(status); - hrsl = max_read(MAX_REG_HRSL, &status); - } - while (hrsl & MAX_HRSL_HRSLT); - - return status; -} - -/** * Send a request to the given endpoint, using the supplied data payload with * the given length, indicating the preserved toggle state of the endpoint * (which will be updated). @@ -457,6 +420,54 @@ return true; } +/** + * Send a control request consisting of the given setup data. + */ +uint8_t max_control(uint8_t *setup) +{ + uint8_t status, hrsl; + + max_write_fifo(0, setup, 8); + + /* Initiate the transfer. */ + + do + { + status = max_write(MAX_REG_HXFR, MAX_HXFR_SETUP); + status = max_wait_transfer(status); + hrsl = max_read(MAX_REG_HRSL, &status); + } + while (hrsl & MAX_HRSL_HRSLT); + + return status; +} + +bool max_control_input(uint8_t *data, uint8_t *len, max_device *device) +{ + device->in_toggle = true; + return max_recv(0, data, len, &device->in_toggle); +} + +/** + * Perform a status transaction as part of a larger control transaction. + * The out parameter is used to indicate the kind of status transfer to be + * performed and should be the inverse of the control transfer direction. + */ +uint8_t max_control_status(bool out) +{ + uint8_t status, hrsl; + + do + { + status = max_write(MAX_REG_HXFR, MAX_HXFR_HS | (out ? MAX_HXFR_OUTNIN : 0)); + status = max_wait_transfer(status); + hrsl = max_read(MAX_REG_HRSL, &status); + } + while (hrsl & MAX_HRSL_HRSLT); + + return status; +} + void chipreset() { printf("Resetting...\n"); @@ -560,6 +571,9 @@ return false; } +/** + * Initialise a USB control request setup payload. + */ 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; @@ -572,6 +586,11 @@ setup[7] = length >> 8; } +/** + * Perform initialisation on a device, obtaining the device details and storing + * this information in the device structure, returning true if successful and + * false otherwise. + */ bool max_init_device(max_device *device) { uint8_t data[64], len = 64, setup[8]; @@ -579,10 +598,12 @@ printf("Sending control request to address 0, endpoint 0...\n"); max_write(MAX_REG_PERADDR, 0); - setup_packet(setup, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, USB_DT_DEVICE << 8, 0, USB_DT_DEVICE_SIZE); + + /* Send a "get descriptor" request for the device descriptor. */ + + setup_packet(setup, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, usb_descriptor_type(USB_DT_DEVICE), 0, USB_DT_DEVICE_SIZE); max_control(setup); - device->in_toggle = true; - if (!max_recv(0, data, &len, &device->in_toggle)) + if (!max_control_input(data, &len, device)) return false; max_control_status(true); @@ -618,6 +639,61 @@ return false; } +/** + * Assign a new address to the given device. + */ +void max_set_address(max_device *device) +{ + uint8_t setup[8]; + + max_write(MAX_REG_PERADDR, 0); + + device->address = next_address++; + + printf("Setting device address to %d...\n", device->address); + + setup_packet(setup, USB_ENDPOINT_OUT, USB_REQ_SET_ADDRESS, device->address, 0, 0); + max_control(setup); + max_control_status(false); +} + + +void max_get_descriptor(max_device *device) +{ + uint8_t data[64], len = 64, setup[8]; + struct usb_string_descriptor *desc; + uint16_t *lang; + + printf("Sending descriptor request to address %d, endpoint 0...\n", device->address); + + max_write(MAX_REG_PERADDR, device->address); + + setup_packet(setup, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, usb_descriptor_type(USB_DT_STRING), 0, 64); + max_control(setup); + if (!max_control_input(data, &len, device)) + { + printf("Failed.\n"); + return; + } + max_control_status(true); + + if (len >= sizeof(struct usb_string_descriptor)) + { + desc = (struct usb_string_descriptor *) data; + + printf("bLength: %d\n", desc->bLength); + printf("bDescriptorType: %d\n", desc->bDescriptorType); + + for (lang = desc->wData; lang < (uint16_t *) (data + desc->bLength); lang++) + { + printf("wLangId: %04x\n", le16toh(*lang)); + } + } +} + +/** + * Handle termination of the process. + */ void shutdown(int signum) { printf("Closing...\n"); @@ -772,7 +848,10 @@ printf("FAILED: RESET -> INSPECTED\n"); } - /* Handle the second device reset initiation. */ + /* Handle the second device reset initiation. This is arguably + superfluous, since the second reset is typically done because + Windows aborts the device descriptor acquisition after 8 bytes + because it was only interested in the maximum packet size. */ else if ((devstate == MAX_DEVSTATE_INSPECTED) && bus_event) { @@ -785,7 +864,9 @@ else if ((devstate == MAX_DEVSTATE_RESET_AGAIN) && frame_event && max_can_send(&status)) { max_write(MAX_REG_MODE, max_read(MAX_REG_MODE, NULL) & ~MAX_MODE_SOFKAENAB); + max_set_address(&device); devstate = MAX_DEVSTATE_READY; + max_get_descriptor(&device); printf("READY\n"); }