// usb_client.c // BCD -- Ben Hutton, Chris Leary, Devrin Talen // 100-column width #include "usb_client.h" #define debug(string) sprintf(print_buffer, string); send_debug() // --------------------- // - STANDARD REQUESTS - // --------------------- STANDARD_REQUEST_T *StandardRequest(DESCRIPTOR_TYPE_T request_target, REQUEST_TYPE_T request, uint8_t valueHi, uint8_t valueLo, uint16_t index, uint16_t length) /* * Constructor. Returns a pointer to a newly created standard request with the specified * parameters. * * request_target DEVICE, INTERFACE, or ENDP -- used to determine bmRequestType * request function to perform -- GET_STATUS, GET_DESCRIPTOR, etc. * valueHi for GET_DESCRIPTOR and SET_DESCRIPTOR, contains descriptor type, otherwise 0 * valueLo contains various variables * index contains endp or interface number, if applicable * length if data is to be returned, contains the maximum allowable bytes of data */ { STANDARD_REQUEST_T *new_standard_request; uint8_t requestType_temp; new_standard_request = malloc(sizeof(STANDARD_REQUEST_T)); if (request_target == HID) { if (request == GET_REPORT || request == GET_IDLE || request == GET_PROTOCOL) requestType_temp = 0xa1; else requestType_temp = 0x21; } else { // Set up the bmRequestType field to be a bitmap as follows: // 7: Data transfer direction (0 = Host-to-Device; 1 = Device-to-Host) // 6..5: Type (0 = Standard; 1 = Class; 2 = Vendor; 3 = Reserved) // 4..0: Recipient (0 = Device; 1 = Interface; 2 = Endpoint; 3 = Other; 4..31 Reserved) if (request == GET_STATUS || request == GET_DESCRIPTOR || request == GET_CONFIGURATION || request == GET_INTERFACE || request == SYNCH_FRAME) requestType_temp = 0x80; //Set data transfer direction to Device-to-Host else requestType_temp = 0x00; //Set data transfer direction to Host-to-Device if (request_target == INTERFACE) requestType_temp |= 0x01; else if (request_target == ENDP) requestType_temp |= 0x02; } new_standard_request->bmRequestType = requestType_temp; new_standard_request->bRequest = request; new_standard_request->wValueHi = valueHi; new_standard_request->wValueLo = valueLo; new_standard_request->wIndex = index; new_standard_request->wLength = length; return new_standard_request; } void DestroyStandardRequest(STANDARD_REQUEST_T *standard_request) /* * Destructor. Simply frees the memory allocated for the standard request. */ { free(standard_request); } STANDARD_REQUEST_T *standard_request_from_template(REQUEST_TYPE_T request_type, DESCRIPTOR_TYPE_T request_target) { uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = 0x0; uint16_t length = 0x0; switch (request_type) { case GET_STATUS : case SYNCH_FRAME : length = 0x2; break; case GET_CONFIGURATION : case GET_INTERFACE : case SET_INTERFACE : length = 0x1; break; } return StandardRequest(request_target, request_type, valueHi, valueLo, index, length); } STANDARD_REQUEST_T *hid_request_from_template(HID_REQUEST_TYPE_T request_type) { uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = 0x0; uint16_t length = 0x0; DESCRIPTOR_TYPE_T request_target = HID; switch (request_type) { case GET_IDLE : case GET_PROTOCOL : length = 0x1; break; } return StandardRequest(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T *make_standard_request_data_packet(STANDARD_REQUEST_T *request) { DATA_PACKET_T *dp; dp = DataPacket(DATA0, 8); dp->data[7] = request->bmRequestType; dp->data[6] = request->bRequest; dp->data[5] = request->wValueLo; dp->data[4] = request->wValueHi; dp->data[3] = request->wIndex & 0xff; dp->data[2] = request->wIndex >> 8; dp->data[1] = request->wLength & 0xff; dp->data[0] = request->wLength >> 8; sprintf(print_buffer, "datapacket: 0x%x %x %x %x %x %x %x %x \n", dp->data[7], dp->data[6], dp->data[5], dp->data[4], dp->data[3], dp->data[2], dp->data[1], dp->data[0]); send_debug(); return dp; } DATA_PACKET_T *make_standard_request(DESCRIPTOR_TYPE_T request_target, REQUEST_TYPE_T request_type, uint8_t valueHi, uint8_t valueLo, uint16_t index, uint16_t length) /* * Makes a data packet containing a standard request as a payload. Used in control transfers. * request_target: either DEVICE, INTERFACE, or ENDP * length: the number of bytes of data you expect to receive. * valueLo and valueHi: should be set to request-specific values * index: if an INTERFACE or ENDP request, put the interface or endpoint number here */ { STANDARD_REQUEST_T *new_request; new_request = StandardRequest(request_target, request_type, valueHi, valueLo, index, length); return make_standard_request_data_packet(new_request); } void execute_standard_request(STANDARD_REQUEST_T *request, SIE_T *sie, HC_T *hc, uint8_t addr, uint8_t endp, DATA_PACKET_T *payload, uint8_t reset_after) //Takes in a request and a properly bound host controller //Determines if it needs any, and how many, IN packets //Puts together and executes the appropriate transaction { uint8_t iter; uint8_t iter2; uint8_t packet_length; PID_T datatype = DATA0; uint8_t transaction_count = 0; // transaction-specific variables TRANSACTION_T *setup; TRANSACTION_T *ins; TRANSACTION_T *status; TOKEN_PACKET_T *tp; DATA_PACKET_T *dp; // create a setup transaction tp = TokenPacket(SETUP, addr, endp); dp = make_standard_request_data_packet(request); // create the control transaction with the new token packet setup = Transaction(CONTROL, tp, dp); debug("pushing a SETUP\n"); hc_push_transaction(hc, setup); transaction_count++; // if we're GETting data, we need to issue some INs... if (request->bRequest == GET_STATUS || request->bRequest == GET_DESCRIPTOR || request->bRequest == GET_CONFIGURATION || request->bRequest == GET_INTERFACE || request->bRequest == SYNCH_FRAME || request->bRequest == GET_REPORT) { //wLength holds the max # of bytes that the function can return //IN packets can contain 8 bytes in low-speed devices //So send 1 IN packet for every 8 bytes that you want to receive for (iter = 0; iter < request->wLength; iter+=8) { tp = TokenPacket(IN, addr, endp); // this is a data in, so PID and size don't matter dp = DataPacket(DATA0, 0); ins = Transaction(CONTROL, tp, dp); // push the transaction on the HC queue debug("pushing an IN\n"); hc_push_transaction(hc, ins); transaction_count++; //handle the reset... if(reset_after != NULL) { debug("doing transactions...\n"); for (iter = 0; iter < transaction_count; iter++) hc_do_transaction(hc); debug("resetting...\n"); sie_reset(sie); for (iter = 0; iter < 100; iter++) _delay_ms(10); debug("idling...\n"); sie_idle(sie); return; } } debug("sending status. \n"); // and then put together the STATUS packet (acknowledge by sending a zero-length data packet) tp = TokenPacket(OUT, addr, endp); dp = DataPacket(DATA1, 0); status = Transaction(CONTROL, tp, dp); hc_push_transaction(hc, status); transaction_count++; } // if we're doing a SET_DESCRIPTOR request, we have to send the new data... else if (request->bRequest == SET_DESCRIPTOR) { for (iter = 0; iter < request->wLength; iter+=8) { tp = TokenPacket(OUT, addr, endp); packet_length = request->wLength - iter; // how many bytes should be sent this time... if(packet_length > 8) packet_length = 8; dp = DataPacket(datatype, packet_length); // if wLength is greater than payload->payload_size, then just put in empty bytes at the end for(iter2 = iter; iter2 < iter + packet_length; iter++) { if(iter2 < payload->payload_size) dp->data[iter2] = payload->data[iter2]; } //tick-tock between the two DATA packet types datatype = (datatype == DATA0) ? DATA1 : DATA0; ins = Transaction(CONTROL, tp, dp); // push the transaction on the HC queue hc_push_transaction(hc, ins); transaction_count++; } debug("sending status. \n"); // and then put together the STATUS packet (expect to see a zero-length data packet) tp = TokenPacket(IN, addr, endp); dp = DataPacket(DATA0, 0); status = Transaction(CONTROL, tp, dp); hc_push_transaction(hc, status); transaction_count++; } else //no data packets, but we still need to do the status packet { debug("sending status. \n"); // and then put together the STATUS packet (expect to see a zero-length data packet) tp = TokenPacket(IN, addr, endp); dp = DataPacket(DATA0, 0); status = Transaction(CONTROL, tp, dp); hc_push_transaction(hc, status); transaction_count++; debug("sending status. \n"); // and then put together the STATUS packet (expect to see a zero-length data packet) tp = TokenPacket(IN, addr, endp); dp = DataPacket(DATA0, 0); status = Transaction(CONTROL, tp, dp); hc_push_transaction(hc, status); transaction_count++; debug("sending status. \n"); // and then put together the STATUS packet (expect to see a zero-length data packet) tp = TokenPacket(IN, addr, endp); dp = DataPacket(DATA0, 0); status = Transaction(CONTROL, tp, dp); hc_push_transaction(hc, status); transaction_count++; } debug("doing transactions...\n"); // do the transactions for (iter = 0; iter < transaction_count; iter++) hc_do_transaction(hc); DestroyStandardRequest(request); } /* probably not needed anymore DATA_PACKET_T make_GET_DEVICE_STATUS() { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = GET_STATUS; uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = 0x0; uint16_t length = 0x2; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_GET_INTERFACE_STATUS(uint8_t interface) { DESCRIPTOR_TYPE_T request_target = INTERFACE; REQUEST_TYPE_T request_type = GET_STATUS; uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = interface; uint16_t length = 0x2; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_GET_ENDPOINT_STATUS(uint8_t endpoint) { DESCRIPTOR_TYPE_T request_target = ENDP; REQUEST_TYPE_T request_type = GET_STATUS; uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = endpoint; uint16_t length = 0x2; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_CLEAR_DEVICE_FEATURE(FEATURE_SELECTOR_T feature) { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = CLEAR_FEATURE; uint8_t valueHi = 0x0; uint8_t valueLo = feature; uint16_t index = 0x0; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_CLEAR_ENDPOINT_FEATURE(FEATURE_SELECTOR_T feature, uint8_t endpoint) { DESCRIPTOR_TYPE_T request_target = ENDP; REQUEST_TYPE_T request_type = CLEAR_FEATURE; uint8_t valueHi = 0x0; uint8_t valueLo = feature; uint16_t index = endpoint; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_SET_DEVICE_FEATURE(FEATURE_SELECTOR_T feature) { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = SET_FEATURE; uint8_t valueHi = 0x0; uint8_t valueLo = feature; uint16_t index = 0x0; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_SET_ENDPOINT_FEATURE(FEATURE_SELECTOR_T feature, uint8_t endpoint) { DESCRIPTOR_TYPE_T request_target = ENDP; REQUEST_TYPE_T request_type = SET_FEATURE; uint8_t valueHi = 0x0; uint8_t valueLo = feature; uint16_t index = endpoint; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_SET_ADDRESS(uint8_t address) { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = SET_ADDRESS; uint8_t valueHi = 0x0; uint8_t valueLo = address; uint16_t index = 0x0; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_GET_DESCRIPTOR(uint8_t desc_index, REQUEST_TYPE_T type, uint16_t length) { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = GET_DESCRIPTOR; uint8_t valueHi = type; uint8_t valueLo = desc_index; uint16_t index = 0x0; uint16_t length = length; if(valueLo == STRING) index = 0x0409; // Language code for English (United States) return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_GET_DEVICE_DESCRIPTOR(uint16_t length) { return make_GET_DESCRIPTOR(0, DEVICE, length); } DATA_PACKET_T make_SET_DESCRIPTOR(uint8_t index, REQUEST_TYPE_T type, uint16_t length) { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = SET_DESCRIPTOR; uint8_t valueHi = type; uint8_t valueLo = desc_index; uint16_t index = 0x0; uint16_t length = length; if(valueLo == STRING) index = 0x0409; // Language code for English (United States) return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_GET_CONFIGURATION() { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = GET_CONFIGURATION; uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = 0x0; uint16_t length = 0x1; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_SET_CONFIGURATION(uint8_t configuration) { DESCRIPTOR_TYPE_T request_target = DEVICE; REQUEST_TYPE_T request_type = SET_CONFIGURATION; uint8_t valueHi = 0x0; uint8_t valueLo = configuration; uint16_t index = 0x0; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_GET_INTERFACE(uint8_t interface) { DESCRIPTOR_TYPE_T request_target = INTERFACE; REQUEST_TYPE_T request_type = GET_INTERFACE; uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = interface; uint16_t length = 0x1; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_SET_INTERFACE(uint8_t interface, uint8_t new_interface) { DESCRIPTOR_TYPE_T request_target = INTERFACE; REQUEST_TYPE_T request_type = SET_INTERFACE; uint8_t valueHi = 0x0; uint8_t valueLo = new_interface; uint16_t index = interface; uint16_t length = 0x0; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } DATA_PACKET_T make_SYNCH_FRAME(uint8_t endpoint) { DESCRIPTOR_TYPE_T request_target = ENDP; REQUEST_TYPE_T request_type = SYNCH_FRAME; uint8_t valueHi = 0x0; uint8_t valueLo = 0x0; uint16_t index = endpoint; uint16_t length = 0x2; return make_standard_request(request_target, request_type, valueHi, valueLo, index, length); } */