void usb_handle_StandardInterfaceRequest(BDentry *bdp) { unsigned char *packet = bdp->BDADDR; switch (packet[USB_bRequest]) { case USB_REQUEST_GET_STATUS: rbdp->BDADDR[0] = 0x00; rbdp->BDADDR[1] = 0x00; usb_ack_dat1(rbdp, 2); // JTR common addition for STD and CLASS ACK // rbdp->BDCNT = 2; // rbdp->BDSTAT = UOWN + DTS + DTSEN; break; case USB_REQUEST_GET_INTERFACE: if (USB_NUM_INTERFACES > packet[USB_bInterface]) { // TODO: Implement alternative interfaces, or move responsibility to class/vendor functions. rbdp->BDADDR[0] = 0; usb_ack_dat1(rbdp, 1); // JTR common addition for STD and CLASS ACK } else usb_RequestError(); break; case USB_REQUEST_SET_INTERFACE: if (USB_NUM_INTERFACES > packet[USB_bInterface] && 0u == packet[USB_wValue]) { // TODO: Implement alternative interfaces... usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK } else usb_RequestError(); break; case USB_REQUEST_CLEAR_FEATURE: // JTR N/A for interface case USB_REQUEST_SET_FEATURE: // This is correct and finished code. default: usb_RequestError(); } }
void usb_handle_StandardInterfaceRequest(BDentry *bdp) { BYTE *packet = bdp->BDADDR; switch (packet[USB_bRequest]) { case USB_REQUEST_GET_STATUS: EP0_Inbdp->BDADDR[0] = 0x00; EP0_Inbdp->BDADDR[1] = 0x00; usb_ack_dat1(2); break; case USB_REQUEST_GET_INTERFACE: if (USB_NUM_INTERFACES > packet[USB_bInterface]) { // TODO: Implement alternative interfaces, or move responsibility to class/vendor functions. EP0_Inbdp->BDADDR[0] = 0; usb_ack_dat1(1); } else usb_RequestError(); break; case USB_REQUEST_SET_INTERFACE: if (USB_NUM_INTERFACES > packet[USB_bInterface] && 0u == packet[USB_wValue]) { // TODO: Implement alternative interfaces... usb_ack_dat1(0); } else usb_RequestError(); break; case USB_REQUEST_CLEAR_FEATURE: // JTR N/A for interface case USB_REQUEST_SET_FEATURE: // This is correct and finished code. default: usb_RequestError(); } }
void cdc_setup(void) { BYTE *packet; size_t reply_len; packet = EP0_Outbdp->BDADDR; switch (packet[USB_bmRequestType] & (USB_bmRequestType_TypeMask | USB_bmRequestType_RecipientMask)) { case (USB_bmRequestType_Class | USB_bmRequestType_Interface): switch (packet[USB_bRequest]) { //JTR This is just a dummy, nothing defined to do for CDC ACM case CDC_SEND_ENCAPSULATED_COMMAND: usb_ack_dat1(0); break; //JTR This is just a dummy, nothing defined to do for CDC ACM case CDC_GET_ENCAPSULATED_RESPONSE: //usb_ack_zero(rbdp); usb_ack_dat1(0); break; case CDC_SET_COMM_FEATURE: // Optional case CDC_GET_COMM_FEATURE: // Optional case CDC_CLEAR_COMM_FEATURE: // Optional usb_RequestError(); // Not advertised in ACM functional descriptor break; case CDC_SET_LINE_CODING: // Optional, strongly recomended usb_set_out_handler(0, cdc_set_line_coding_data); // Register out handler function break; case CDC_GET_LINE_CODING: // Optional, strongly recomended // JTR reply length (7) is always going to be less than minimum EP0 size (8) reply_len = *((unsigned int *) &packet[USB_wLength]); if (sizeof (struct cdc_LineCodeing) < reply_len) { reply_len = sizeof (struct cdc_LineCodeing); } memcpy(EP0_Inbdp->BDADDR, (const void *) &linecodeing, reply_len); usb_ack_dat1(reply_len); // JTR common addition for STD and CLASS ACK usb_set_in_handler(0, cdc_get_line_coding); break; case CDC_SET_CONTROL_LINE_STATE: // Optional cls = *((struct _cdc_ControlLineState *) &packet[USB_wValue]); usb_set_in_handler(0, cdc_set_control_line_state_status); // JTR why bother? usb_ack_dat1(0); // JTR common addition for STD and CLASS ACK LineStateUpdated = 1; break; case CDC_SEND_BREAK: // Optional default: usb_RequestError(); } break; default: usb_RequestError(); } }
void cdc_set_line_coding_data(void) { // JTR handling an OUT token In the CDC stack this is the only function that handles an OUT data stage. unsigned long dwBaud, dwBaudrem; memcpy(&linecodeing, (const void *) EP0_Outbdp->BDADDR, sizeof (struct cdc_LineCodeing)); dwBaud = BAUDCLOCK_FREQ / linecodeing.dwDTERate; dwBaudrem = BAUDCLOCK_FREQ % linecodeing.dwDTERate; if (linecodeing.dwDTERate > (dwBaudrem << 1)) dwBaud--; UART_BAUD_setup(dwBaud); usb_unset_out_handler(0); // Unregister OUT handler; JTR serious bug fix in macro! usb_set_in_handler(0, cdc_set_line_coding_status); // JTR why bother? usb_ack_dat1(0); // JTR common addition for STD and CLASS ACK // JTR This part of the USB-CDC stack is worth highlighting // This is the only place that we have an OUT DATA packet on // EP0. At this point it has been completed. This stack unlike // the microchip stack does not have a common IN or OUT data // packet complete tail and therefore it is the responsibility // of each section to ensure that EP0 is set-up correctly for // the next setup packet. // Force EP0 OUT to the DAT0 state // after we have all our data packets. EP0_Outbdp->BDCNT = USB_EP0_BUFFER_SIZE; EP0_Outbdp->BDSTAT = UOWN | DTSEN; }
void cdc_set_line_coding_data(void) { // JTR handling an OUT token In the CDC stack this is the only function that handles an OUT data stage. memcpy(&linecodeing, (const void *) bdp->BDADDR, sizeof (struct cdc_LineCodeing)); usb_unset_out_handler(0); // Unregister OUT handler; JTR serious bug fix in macro! usb_set_in_handler(0, cdc_set_line_coding_status); // JTR why bother? usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK // JTR This part of the USB-CDC stack is worth highlighting // This is the only place that we have an OUT DATA packet on // EP0. At this point it has been completed. This stack unlike // the microchip stack does not have a common IN or OUT data // packet complete tail and therefore it is the responsibility // of each section to ensure that EP0 is set-up correctly for // the next setup packet. // This next line inverts the DTS so that it is now ready for // a DAT0 packet. However it only works because we had one data // packet. For any amount of EVEN data packets it would not be // correct. // usb_ack_out(bdp); // JTR N/A Good for only odd number of data packets. // The correct thing to do is to force EP0 OUT to the DAT0 state // after we have all our data packets. bdp->BDCNT = USB_EP0_BUFFER_SIZE; bdp->BDSTAT = UOWN | DTSEN; }
void usb_handle_StandardEndpointRequest(BDentry *bdp) { unsigned char *packet; unsigned char epnum; unsigned char dir; BDentry *epbd; packet = bdp->BDADDR; switch (packet[USB_bRequest]) { case USB_REQUEST_GET_STATUS: rbdp->BDADDR[0] = 0x00; // Assume no stall rbdp->BDADDR[1] = 0x00; // Same for stall or not epnum = packet[USB_wIndex] & 0x0F; dir = packet[USB_wIndex] >> 7; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_EVEN)]; if (epbd->BDSTAT &= ~BSTALL) rbdp->BDADDR[0] = 0x01; // EVEN BD is stall flag set? epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_ODD)]; if (epbd->BDSTAT &= ~BSTALL) rbdp->BDADDR[0] = 0x01; // ODD BD is stall flag set? usb_ack_dat1(rbdp, 2); // JTR common addition for STD and CLASS ACK break; case USB_REQUEST_CLEAR_FEATURE: epnum = packet[USB_wIndex] & 0x0F; dir = packet[USB_wIndex] >> 7; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_EVEN)]; epbd->BDSTAT &= ~BSTALL; if (dir) epbd->BDSTAT |= DTS; // JTR added IN EP set DTS as it will be toggled to zero next transfer if (0 == dir) epbd->BDSTAT &= ~DTS; // JTR added // JTR this pointless ATM. If ping-pong is enabled then you need to track PPBI // and set up ODD and EVEN BDs in respect to this. See complicated system in // microchip stack >= 2.8 // epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_ODD)]; // epbd->BDSTAT &= ~BSTALL; // if (dir) epbd->BDSTAT |= DTS; // JTR added // if (0 == dir) epbd->BDSTAT &= ~DTS; // JTR added usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK // rbdp->BDCNT = 0; // rbdp->BDSTAT = UOWN + DTS + DTSEN; break; case USB_REQUEST_SET_FEATURE: epnum = packet[USB_wIndex] & 0x0F; dir = packet[USB_wIndex] >> 7; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_EVEN)]; epbd->BDSTAT |= BSTALL; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_ODD)]; epbd->BDSTAT |= BSTALL; usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK // rbdp->BDCNT = 0; // rbdp->BDSTAT = UOWN + DTS + DTSEN; break; case USB_REQUEST_SYNCH_FRAME: default: usb_RequestError(); } }
void usb_handle_StandardDeviceRequest(BDentry *bdp) { unsigned char *packet = bdp->BDADDR; int i; switch (packet[USB_bRequest]) { case USB_REQUEST_GET_STATUS: rbdp->BDADDR[0] = usb_device_status & 0xFF; rbdp->BDADDR[1] = usb_device_status >> 8; // JTR I added usb_ack_dat1() simply so that the handling // of STANDARD and CLASS requests (in cdc.c) were consistant // rather than have the same thing done in two different ways. usb_ack_dat1(rbdp, 2); // JTR common addition for STD and CLASS ACK break; case USB_REQUEST_CLEAR_FEATURE: if (0x01u == packet[USB_wValue]) { // TODO: Remove magic (REMOTE_WAKEUP_FEATURE) usb_device_status &= ~0x0002; usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK } else usb_RequestError(); break; case USB_REQUEST_SET_FEATURE: if (0x01u == packet[USB_wValue]) { // TODO: Remove magic (REMOTE_WAKEUP_FEATURE) usb_device_status |= 0x0002; usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK } else usb_RequestError(); break; case USB_REQUEST_SET_ADDRESS: if (0x00u == packet[USB_wValueHigh] && 0x7Fu >= packet[USB_wValue]) { usb_addr_pending = packet[USB_wValue]; usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK usb_set_in_handler(0, usb_set_address); } else usb_RequestError(); break; case USB_REQUEST_GET_DESCRIPTOR: switch (packet[USB_bDescriptorType]) { case USB_DEVICE_DESCRIPTOR_TYPE: usb_desc_ptr = usb_device_descriptor; usb_desc_len = usb_device_descriptor[0]; if ((0 == packet[USB_wLengthHigh] && packet[USB_wLength] < usb_desc_ptr[0])) usb_desc_len = packet[USB_wLength]; break; case USB_CONFIGURATION_DESCRIPTOR_TYPE: if (packet[USB_bDescriptorIndex] >= usb_device_descriptor[17]) // TODO: remove magic usb_RequestError(); usb_desc_ptr = usb_config_descriptor; usb_desc_len = usb_desc_ptr[2] + usb_desc_ptr[3] * 256; for (i = 0; i < packet[USB_bDescriptorIndex]; i++) { // Implicit linked list traversal until requested configuration usb_desc_ptr += usb_desc_len; usb_desc_len = usb_desc_ptr[2] + usb_desc_ptr[3] * 256; } if ((packet[USB_wLengthHigh] < usb_desc_ptr[3]) || (packet[USB_wLengthHigh] == usb_desc_ptr[3] && packet[USB_wLength] < usb_desc_ptr[2])) usb_desc_len = packet[USB_wLength] + packet[USB_wLengthHigh] * 256; break; case USB_STRING_DESCRIPTOR_TYPE: // TODO: Handle language request. For now return standard language. if (packet[USB_bDescriptorIndex] >= usb_num_string_descriptors) usb_RequestError(); usb_desc_ptr = usb_string_descriptor; usb_desc_len = usb_desc_ptr[0]; for (i = 0; i < packet[USB_bDescriptorIndex]; i++) { // Implicit linked list traversal until requested configuration usb_desc_ptr += usb_desc_len; usb_desc_len = usb_desc_ptr[0]; } if ((0 == packet[USB_wLengthHigh] && packet[USB_wLength] < usb_desc_ptr[0])) usb_desc_len = packet[USB_wLength]; break; case USB_INTERFACE_DESCRIPTOR_TYPE: case USB_ENDPOINT_DESCRIPTOR_TYPE: default: usb_RequestError(); } usb_send_descriptor(); // Send first part of packet right away usb_set_in_handler(0, usb_send_descriptor); break; case USB_REQUEST_GET_CONFIGURATION: rbdp->BDADDR[0] = usb_current_cfg; usb_ack_dat1(rbdp, 1); // JTR common addition for STD and CLASS ACK // rbdp->BDCNT = 1; // rbdp->BDSTAT = UOWN + DTS + DTSEN; break; case USB_REQUEST_SET_CONFIGURATION: if (USB_NUM_CONFIGURATIONS >= packet[USB_wValue]) { // TODO: Support multiple configurations /* Configure endpoints (USB_UEPn - registers) */ usb_current_cfg = packet[USB_wValue]; if (usb_current_cfg != 0) { // JTR user_configured_init major addition. This is a CALLBACK to the USER when the device is enumerated. // This is when we setup non EP0 endpoints. // TODO: This really could be a function pointer usb_device_state = CONFIGURED_STATE; user_configured_init(); } else { usb_device_state = ADDRESS_STATE; } usb_ack_dat1(rbdp, 0); // JTR common addition for STD and CLASS ACK } else usb_RequestError(); break; case USB_REQUEST_SET_DESCRIPTOR: default: usb_RequestError(); } }
void usb_handle_StandardEndpointRequest(BDentry *bdp) { BYTE *packet; BYTE epnum; BYTE dir; BDentry *epbd; usb_uep_t *pUEP; packet = bdp->BDADDR; switch (packet[USB_bRequest]) { case USB_REQUEST_GET_STATUS: EP0_Inbdp->BDADDR[0] = 0x00; // Assume no stall EP0_Inbdp->BDADDR[1] = 0x00; // Same for stall or not epnum = packet[USB_wIndex] & 0x0F; dir = packet[USB_wIndex] >> 7; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_EVEN)]; if (epbd->BDSTAT &= ~BSTALL) EP0_Inbdp->BDADDR[0] = 0x01; // EVEN BD is stall flag set? //epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_ODD)]; //if (epbd->BDSTAT &= ~BSTALL) // rbdp->BDADDR[0] = 0x01; // ODD BD is stall flag set? usb_ack_dat1(2); break; case USB_REQUEST_CLEAR_FEATURE: // As this is really is an application event and there // should be a call back and protocol for handling the // possible lost of a data packet. // TODO: ping-ping support. epnum = packet[USB_wIndex] & 0x0F; // JTR Added V0.2 after microchip stuff up with their documentation. pUEP = USB_UEP; pUEP += epnum; *pUEP &= ~USB_UEP_EPSTALL; dir = packet[USB_wIndex] >> 7; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_EVEN)]; epbd->BDSTAT &= ~BSTALL; if (dir) epbd->BDSTAT |= DTS; // JTR added IN EP set DTS as it will be toggled to zero next transfer if (0 == dir) epbd->BDSTAT &= ~DTS; // JTR added // JTR this pointless ATM. If ping-pong is enabled then you need to track PPBI // and set up ODD and EVEN BDs in respect to this. See complicated system in // microchip stack >= 2.8 // epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_ODD)]; // epbd->BDSTAT &= ~BSTALL; // if (dir) epbd->BDSTAT |= DTS; // JTR added // if (0 == dir) epbd->BDSTAT &= ~DTS; // JTR added usb_ack_dat1(0); break; case USB_REQUEST_SET_FEATURE: epnum = packet[USB_wIndex] & 0x0F; dir = packet[USB_wIndex] >> 7; epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_EVEN)]; epbd->BDSTAT |= BSTALL; //epbd = &usb_bdt[USB_CALC_BD(epnum, dir, USB_PP_ODD)]; //epbd->BDSTAT |= BSTALL; usb_ack_dat1(0); break; case USB_REQUEST_SYNCH_FRAME: default: usb_RequestError(); } }
void usb_handle_StandardDeviceRequest(BDentry *bdp) { BYTE *packet = bdp->BDADDR; int i; switch (packet[USB_bRequest]) { case USB_REQUEST_GET_STATUS: EP0_Inbdp->BDADDR[0] = usb_device_status & 0xFF; EP0_Inbdp->BDADDR[1] = usb_device_status >> 8; usb_ack_dat1(2); break; case USB_REQUEST_CLEAR_FEATURE: if (0x01u == packet[USB_wValue]) { // TODO: Remove magic (REMOTE_WAKEUP_FEATURE) usb_device_status &= ~0x0002; usb_ack_dat1(0); } else usb_RequestError(); break; case USB_REQUEST_SET_FEATURE: if (0x01u == packet[USB_wValue]) { // TODO: Remove magic (REMOTE_WAKEUP_FEATURE) usb_device_status |= 0x0002; usb_ack_dat1(0); } else usb_RequestError(); break; case USB_REQUEST_SET_ADDRESS: if (0x00u == packet[USB_wValueHigh] && 0x7Fu >= packet[USB_wValue]) { usb_addr_pending = packet[USB_wValue]; usb_set_in_handler(0, usb_set_address); usb_ack_dat1(0); } else usb_RequestError(); break; case USB_REQUEST_GET_DESCRIPTOR: switch (packet[USB_bDescriptorType]) { case USB_DEVICE_DESCRIPTOR_TYPE: // There is only every one in pratice. usb_rom_ptr = usb_device_descriptor; usb_rom_len = usb_device_descriptor[0]; // Get BYTE length from descriptor always at byte [0] if ((0 == packet[USB_wLengthHigh] && packet[USB_wLength] < usb_rom_ptr[0])) usb_rom_len = packet[USB_wLength]; // If the HOST asked for LESS then must adjust count to the smaller number break; case USB_CONFIGURATION_DESCRIPTOR_TYPE: if (packet[USB_bDescriptorIndex] >= usb_device_descriptor[17]) { flag_usb_RequestError(); break; } usb_rom_ptr = usb_config_descriptor; usb_rom_len = usb_rom_ptr[2] + usb_rom_ptr[3] * 256; // Get WORD length from descriptor always at bytes 2&3 (Low-High) for (i = 0; i < packet[USB_bDescriptorIndex]; i++) { // Implicit linked list traversal until requested configuration usb_rom_ptr += usb_rom_len; usb_rom_len = usb_rom_ptr[2] + usb_rom_ptr[3] * 256; // Get (next) WORD length from descriptor always at bytes 2&3 (Low-High) } if ((packet[USB_wLengthHigh] < usb_rom_ptr[3]) || (packet[USB_wLengthHigh] == usb_rom_ptr[3] && packet[USB_wLength] < usb_rom_ptr[2])) usb_rom_len = packet[USB_wLength] + packet[USB_wLengthHigh] * 256; // If the HOST asked for LESS then must adjust count to the smaller number break; case USB_STRING_DESCRIPTOR_TYPE: // TODO: Handle language request. For now return standard language. if (packet[USB_bDescriptorIndex] >= usb_num_string_descriptors) { flag_usb_RequestError(); break; } usb_rom_ptr = usb_string_descriptor; usb_rom_len = usb_rom_ptr[0]; // Get BYTE length from descriptor always at byte [0] for (i = 0; i < packet[USB_bDescriptorIndex]; i++) { // Implicit linked list traversal until requested configuration usb_rom_ptr += usb_rom_len; usb_rom_len = usb_rom_ptr[0]; } if ((0 == packet[USB_wLengthHigh] && packet[USB_wLength] < usb_rom_ptr[0])) usb_rom_len = packet[USB_wLength]; break; case USB_INTERFACE_DESCRIPTOR_TYPE: case USB_ENDPOINT_DESCRIPTOR_TYPE: default: flag_usb_RequestError(); } if (0 == usbrequesterrorflag) { usb_send_rom(); // Send first part of packet right away, the rest is handled by the EP0 IN handler. usb_set_in_handler(0, usb_send_rom); } else { usb_RequestError(); } break; case USB_REQUEST_GET_CONFIGURATION: EP0_Inbdp->BDADDR[0] = usb_current_cfg; usb_ack_dat1(1); break; case USB_REQUEST_SET_CONFIGURATION: if (USB_NUM_CONFIGURATIONS >= packet[USB_wValue]) { // TODO: Support multiple configurations /* Configure endpoints (USB_UEPn - registers) */ usb_current_cfg = packet[USB_wValue]; if (usb_current_cfg != 0) { // JTR user_configured_init major addition. This is a CALLBACK to the USER when the device is enumerated. // This is when we setup non EP0 endpoints. // TODO: This really could be a function pointer usb_device_state = CONFIGURED_STATE; user_configured_init(); } else { usb_device_state = ADDRESS_STATE; } usb_ack_dat1(0); } else usb_RequestError(); break; case USB_REQUEST_SET_DESCRIPTOR: default: usb_RequestError(); } }