pic_usb.h File Reference
Pic USB routines.
More...
Go to the source code of this file.
Data Structures |
struct | buffer_descriptor |
struct | CDC_ACM_functional_descriptor |
struct | CDC_call_mgt_functional_descriptor |
struct | CDC_header_functional_descriptor |
struct | CDC_union_functional_descriptor |
struct | configuration_descriptor |
struct | device_descriptor |
struct | endpoint_descriptor |
struct | hid_descriptor |
struct | interface_descriptor |
struct | setup_data_packet |
Defines |
#define | BC8 0 |
#define | BC9 1 |
#define | BSTALL 2 |
#define | DATA_STAGE_DIR 7 |
#define | dt_CONFIGURATION 0x02 |
#define | dt_CS_INTERFACE 0x24 |
#define | dt_DEBUG 0x0a |
#define | dt_DEVICE 0x01 |
#define | dt_DEVICE_QUALIFIER 0x06 |
#define | dt_ENDPOINT 0x05 |
#define | dt_HID 0x21 |
#define | dt_HID_REPORT 0x22 |
#define | dt_INTERFACE 0x04 |
#define | dt_INTERFACE_ASSOC 0x0b |
#define | dt_INTERFACE_POWER 0x08 |
#define | dt_OTG 0x09 |
#define | dt_OTHER_SPEED_CONFIG 0x07 |
#define | dt_STRING 0x03 |
#define | DTS 6 |
#define | DTSEN 3 |
#define | INCDIS 4 |
#define | KEN 5 |
#define | PID0 2 |
#define | PID1 3 |
#define | PID2 4 |
#define | PID3 5 |
#define | pid_ACK 0b00000010 |
#define | pid_DATA0 0b00000011 |
#define | pid_DATA1 0b00001011 |
#define | pid_DATA2 0b00000111 |
#define | pid_IN 0b00001001 |
#define | pid_MDATA 0b00001111 |
#define | pid_NAK 0b00001010 |
#define | pid_NYET 0b00000110 |
#define | pid_OUT 0b00000001 |
#define | pid_SETUP 0b00001101 |
#define | pid_SOF 0b00000101 |
#define | pid_STALL 0b00001110 |
#define | req_Clear_Feature 0x01 |
#define | req_Get_Configuration 0x08 |
#define | req_Get_Descriptor 0x06 |
#define | req_Get_Interface 0x0a |
#define | req_Get_Status 0x00 |
#define | req_Set_Address 0x05 |
#define | req_Set_Configuration 0x09 |
#define | req_Set_Descriptor 0x07 |
#define | req_Set_Feature 0x03 |
#define | req_Set_Interface 0x0b |
#define | req_Synch_Frame 0x0c |
#define | REQUEST_TYPE0 5 |
#define | REQUEST_TYPE1 6 |
#define | UOWN 7 |
#define | usb_send_status_ack() usb_send_empty_data_pkt() |
Enumerations |
enum | control_mode_type {
cm_IDLE,
cm_CTRL_WRITE_DATA_STAGE,
cm_CTRL_WRITE_DATA_STAGE_CLASS,
cm_CTRL_READ_DATA_STAGE,
cm_CTRL_READ_DATA_STAGE_CLASS,
cm_CTRL_READ_AWAITING_STATUS,
cm_CTRL_WRITE_SENDING_STATUS
} |
enum | usb_state_type { st_POWERED,
st_DEFAULT,
st_ADDRESS,
st_CONFIGURED
} |
enum | usb_status_type { us_IDLE,
us_SET_ADDRESS
} |
Functions |
void | turn_usb_ints_on () |
| Turn on USB interrupts.
|
void | usb_device_configured_callback () |
| Callback routine triggered when a successful intial USB negotiation has completed.
|
void | usb_enable_module () |
| Enables the USB hardware and starts USB negotiations.
|
void | usb_ep_data_in_callback (uns8 end_point, uns16 byte_count) |
| Callback routine triggered when data has been sent to the host.
|
void | usb_ep_data_out_callback (uns8 end_point, uns8 *buffer_location, uns16 byte_count) |
| Callback routine triggered when data has been sent to the device.
|
void | usb_get_descriptor_callback (uns8 descriptor_type, uns8 descriptor_num, uns8 **rtn_descriptor_ptr, uns16 *rtn_descriptor_size) |
| Callback routine triggered when the descriptor is requested by the host.
|
usb_state_type | usb_get_state () |
| Query the current state of the USB connection.
|
void | usb_handle_class_ctrl_read_callback () |
| Callback routine for a class control read.
|
void | usb_handle_class_ctrl_write_callback (uns8 *data, uns16 count) |
| Callback routine for a class control write.
|
void | usb_handle_class_request_callback (setup_data_packet sdp) |
| Callback routine for a control transfer request that is placed on the class.
|
void | usb_handle_isr () |
| Handle USB interrupts.
|
void | usb_send_data (uns8 ep, uns8 *data, uns8 send_count, bit first) |
| Send data over an endpoint pipe.
|
void | usb_send_empty_data_pkt () |
| Send an empty data packet.
|
void | usb_setup () |
| Setup USB hardware ready for use.
|
void | usb_SOF_callback (uns16 frame) |
| Callback routine triggered each time a start of frame (SOF) has been received.
|
void | usb_stall_ep0 () |
| Send a stall on control transfer endpoint.
|
Variables |
control_mode_type | control_mode |
uns8 | usb_address |
setup_data_packet | usb_sdp |
usb_state_type | usb_state |
Detailed Description
Put the following in your config.h
- - - - - - - - - - - - - - - - - - - - pic_usb defines
- - - - - - - - - - - - - - - - - - - -
Use this define if you would like to get USB negotiation and data transfer information out the serial (UART) port. You'll also need to include pic_serial.c in your project. define USB_DEBUG
Use this define if you would like a high level (ie, lots) of USB debug information printed out the serial (UART) port. define USB_DEBUG_HIGH
Define the highest numbered endpoint you will use (in this case, we choose 3). define USB_HIGHEST_EP 3
Define either USB_SELF_POWERED or USB_BUS_POWERED define USB_SELF_POWERED define USB_BUS_POWERED
Define your endpoint buffers. These start at 0x500 for a 18f4550. You'll always need endpoint 0, which is the control transfer endpoint, and others as well depending on your use. You don't have to declare the endpoints you don't use, even if they're not sequential.
define USB_EP0_OUT_SIZE 8 define USB_EP0_OUT_ADDR 0x0200
define USB_EP0_IN_SIZE 8 define USB_EP0_IN_ADDR 0x0208
EP1 not used
define USB_EP2_IN_SIZE 8 define USB_EP2_IN_ADDR 0x0210
define USB_EP3_OUT_SIZE 8 define USB_EP3_OUT_ADDR 0x0218 define USB_EP3_IN_SIZE 8 define USB_EP3_IN_ADDR 0x0220
Use this define if you want to get a callback each SOF (Start Of Frame), generally every 1ms define USB_CALLBACK_ON_SOF if you define it, you'll need to include this routine in your code: void usb_SOF_callback(uns16 frame) { }
Use this define if you would like to know when your device has been configured and is ready for use define USB_CALLBACK_ON_DEVICE_CONFIGURED if you define it, you'll need to include this routine in your code: void usb_device_configured_callback() { }
Use this define if your device uses class control transfers, eg, CDC (virtual serial port) is one that does define USB_CALLBACK_ON_CTRL_CLASS if you define it, you'll need to include these routines in your code: void usb_handle_class_ctrl_read_callback(); void usb_handle_class_ctrl_write_callback(uns8 *data, uns16 count); void usb_handle_class_request_callback(setup_data_packet sdp);
Use this define if you would like to get notified when data has arrived or been succesfully sent define USB_EP_DATA_CALLBACK if you define it, you'll need to include these routines in your code: void usb_ep_data_out_callback(uns8 end_point, uns8 *buffer_location, uns16 byte_count); void usb_ep_data_in_callback(uns8 end_point, uns16 byte_count);
Put the following in your ISR
usb_handle_isr();
Put the following in your system setup routine
Setup USB usb_setup();
Turn on USB interrupts void turn_usb_ints_on();
Turn on global interrupts turn_global_ints_on();
When you're ready to start the USB subsystem and negotiate address, send descriptors etc, call
usb_enable_module();
Define Documentation
#define dt_CONFIGURATION 0x02 |
#define dt_CS_INTERFACE 0x24 |
#define dt_DEVICE_QUALIFIER 0x06 |
#define dt_HID_REPORT 0x22 |
#define dt_INTERFACE 0x04 |
#define dt_INTERFACE_ASSOC 0x0b |
#define dt_INTERFACE_POWER 0x08 |
#define dt_OTHER_SPEED_CONFIG 0x07 |
#define pid_ACK 0b00000010 |
#define pid_DATA0 0b00000011 |
#define pid_DATA1 0b00001011 |
#define pid_DATA2 0b00000111 |
#define pid_IN 0b00001001 |
#define pid_MDATA 0b00001111 |
#define pid_NAK 0b00001010 |
#define pid_NYET 0b00000110 |
#define pid_OUT 0b00000001 |
#define pid_SETUP 0b00001101 |
#define pid_SOF 0b00000101 |
#define pid_STALL 0b00001110 |
#define req_Clear_Feature 0x01 |
#define req_Get_Configuration 0x08 |
#define req_Get_Descriptor 0x06 |
#define req_Get_Interface 0x0a |
#define req_Get_Status 0x00 |
#define req_Set_Address 0x05 |
#define req_Set_Configuration 0x09 |
#define req_Set_Descriptor 0x07 |
#define req_Set_Feature 0x03 |
#define req_Set_Interface 0x0b |
#define req_Synch_Frame 0x0c |
#define usb_send_status_ack |
( |
|
) |
usb_send_empty_data_pkt() |
Send a status acknowledge by sending an empty data packet
Enumeration Type Documentation
Describe the state of the control transfer
- Enumerator:
cm_IDLE |
No control transfer taking place
|
cm_CTRL_WRITE_DATA_STAGE |
Device receiving data during the data stage
|
cm_CTRL_WRITE_DATA_STAGE_CLASS |
Device receiving data during the data stage destined for the class
|
cm_CTRL_READ_DATA_STAGE |
Device sending data during the data stage
|
cm_CTRL_READ_DATA_STAGE_CLASS |
Device class is sending data during the data stage
|
cm_CTRL_READ_AWAITING_STATUS |
Device is awaiting reception of status after sending data
|
cm_CTRL_WRITE_SENDING_STATUS |
Device is sending status after receiving data
|
Handle the different states that USB device can be in
- Enumerator:
st_POWERED |
USB device is powered up, ready to start negotiating
|
st_DEFAULT |
USB device is now negotiating
|
st_ADDRESS |
USB device now has an address
|
st_CONFIGURED |
USB device is completely configured and ready to rock and roll
|
Handle the special case of when we send a status ack and THEN change the address. So we need to know that the USB device is in that micro state (ie, received the new address but not yet sent the status
- Enumerator:
-
Function Documentation
void turn_usb_ints_on |
( |
|
) |
|
If you are using interrupt-driven code (generally the best way of doing things) you can turn on USB interrupts using turn_usb_ints_on(). Don't forget that you will also need to call turn_global_ints_on() as well. Typically this is called in your system setup routine.
00962 {
00963
00964 set_bit(uie, STALLIE);
00965 set_bit(uie, TRNIE);
00966 set_bit(uie, URSTIE);
00967 set_bit(pie2, USBIE);
00968 #ifdef USB_CALLBACK_ON_SOF
00969 set_bit(uie, SOFIE);
00970 #endif
00971 }
void usb_device_configured_callback |
( |
|
) |
|
Once descriptors have been received by the host and the host has selected a configuration to use, this routine is triggered. Typically this means that negotiations have completed successfully and an appropriate driver has been loaded.
In order for this callback to be triggered, you must define USB_CALLBACK_ON_DEVICE_CONFIGURED in your config.h
void usb_enable_module |
( |
|
) |
|
After you've called usb_setup(), you can call usb_enable_module() whenever you're ready for USB negotiations to occur. Normally, this would need to occur relatively quickly after power-up if your PIC is powered by USB and it's purpose is to talk over USB. This is normally called from your main() routine once all other configuration is done.
Once the USB module has successfully negotiated a connection with the host, usb_device_configured_callback() will be called if you have requested this in your config.h file. This will indicate a successful connection. Because of the way USB works, there is no way to tell that it *hasn't* worked, except via a timer - if you haven't had a good connection in several seconds, you can assume it has failed (although this may just mean the user is hunting for a driver disk etc).
void usb_ep_data_in_callback |
( |
uns8 |
end_point, |
|
|
uns16 |
byte_count | |
|
) |
| | |
If you have called usb_send_data to transfer data to the host, this routine will be fired once this data has been transferred. You may send more data by using usb_send_data(). Since the current PicPack USB library supports only single buffering, transfer speed is limited by how quickly you can refill the buffer again. In the future, we may support double buffering (ping poing buffering) which will most likely improve transfer speeds (to be fair, transfer performance has not been a limiting factor in tests so far).
In order for this callback to be triggered, you must define USB_EP_DATA_CALLBACK in your config.h
- Parameters:
-
| end_point | The endpoint on which the data was transferred |
| byte_count | The number of bytes that were actually transferred |
void usb_ep_data_out_callback |
( |
uns8 |
end_point, |
|
|
uns8 * |
buffer_location, |
|
|
uns16 |
byte_count | |
|
) |
| | |
If data is sent to the device and the endpoint is not endpoint 0 (the control transfer endpoint) then this routine is called. Since the routine is passed the actual hardware buffer location, it is important to pull data out of the buffer as soon as possible in order to free up the buffer to receive more data. The buffer is re-primed only once this routine completes since PicPack only supports single-buffered mode. In the future, we may look at supporting double buffering (ping-pong buffering) in order to be able to receive more data even while this routine is being called.
In order for this callback to be triggered, you must define USB_EP_DATA_CALLBACK in your config.h
- Parameters:
-
| end_point | The endpoint the data was sent do |
| buffer_lcoation | The memory location of the USB buffer where the data was received into |
| byte_count | The number of bytes received |
00289 {
00290 uns8 cdc_rx_next;
00291 #ifdef CDC_DEBUG
00292 serial_print_str(" EP data out: ");
00293 serial_print_int(byte_count);
00294 serial_print_str(" bytes ");
00295 #endif
00296
00297
00298
00299 if (end_point == USB_CDC_DATA_ENDPOINT) {
00300 uns8 count;
00301 for (count = 0; count < byte_count; count++) {
00302 cdc_rx_next = cdc_rx_end + 1;
00303 if (cdc_rx_next == USB_CDC_RX_BUFFER_SIZE) {
00304 cdc_rx_next = 0;
00305 }
00306 if (cdc_rx_next != cdc_rx_start) {
00307 cdc_rx_buffer[cdc_rx_end] = buffer[count];
00308 cdc_rx_end = cdc_rx_next;
00309 } else {
00310
00311 break;
00312 }
00313 }
00314 } else {
00315 #ifdef CDC_DEBUG
00316 serial_print_str("data for ep ");
00317 serial_print_int(end_point);
00318 #endif
00319 }
00320
00321 #ifdef USB_CDC_USE_LEDS
00322 platform_leds_flash(3);
00323 #endif
00324 }
void usb_get_descriptor_callback |
( |
uns8 |
descriptor_type, |
|
|
uns8 |
descriptor_num, |
|
|
uns8 ** |
rtn_descriptor_ptr, |
|
|
uns16 * |
rtn_descriptor_size | |
|
) |
| | |
Once negotiations start, descriptors are quested by the host. The device must be able to respond to these requests. Typically, this routine consists of a switch statement depending on the descriptor_type parameter. The descriptor_num is used to specify which of the descriptor_type descriptors are required, since they may be several (for example, string descriptors).
Since descriptors are specific to a particular device (and project), this callback routine and the associated descriptors are put in a file called usb_config_xxxx.c and placed in the project workspace. This is because while the descriptors could have been provided as part of the PicPack library, you will almost always want to change them to suit your application, even if only for changing the vendor and device IDs and serial numbers.
At present, descriptors are required to be in RAM.
Since descriptor requests are an essential part of the USB protocol, this callback routine is mandatory.
Returns the USB state, either powered, default, address or connect. This is updated as the negotiation progresses. It may be useful to query this if, after a suitable time-out, the connection has not been made.
void usb_handle_class_ctrl_read_callback |
( |
|
) |
|
When a control transfer is taking place, this routine is called to indicate that a control read for the class has taken place. Since everything in USB land is all about what has just happened, this callback will occur after data has been transferred to the host. If you wish to send more data to the host, use usb_send_data(), or if your control read has sent all the data required, you will need to indicate that the state has changed by setting the control_mode variable to cm_CTRL_READ_AWAITING_STATUS. This will indicate to the stack that it should now wait for the status packet before completing the control transfer.
To allow this callback to trigger, ensure you define USB_CALLBACK_ON_CLASS_CTRL in your config.h
void usb_handle_class_ctrl_write_callback |
( |
uns8 * |
data, |
|
|
uns16 |
count | |
|
) |
| | |
When a control transfer is taking place, this routine is called to indicate that a control write for the class has taken place. Since everything in USB land is all about what has just happened, this callback will occur after data has been received by the device. If you expect more data from the host, it will arrive in due course since endpoint 0 will be primed for more data automatically. If you have received all the data from the host, you will need to set the control_mode state variable to cm_CTRL_WRITE_SENDING_STATUS and then actually send the status by calling usb_send_status_ack(). Once the status has actually been sent, the control_mode state will automatically change to cm_IDLE to indicate the transfer has completed.
To allow this callback to trigger, ensure you define USB_CALLBACK_ON_CLASS_CTRL in your config.h
After receiving a setup packet, where the request is placed on the class, this routine is called. In usb_handle_class_request_callback, you can set up ready for the data stage of the control transfer. The direction of the data stage can be determined by examining test_bit(sdp.bRequest, DATA_STAGE_DIR) although generally it appears to be obvious from the request. The request is stored in sdp.bRequest.
Typically, if it is a control read transfer (that is, it is a request by the host for data), then you will need to move the control_mode state variable to cm_CTRL_READ_DATA_STAGE_CLASS and send data using usb_send_data(). If you only intend to send one packet, you can immediately move the control_mode state variable to cm_CTRL_READ_AWAITING_STATUS to indicate you are waiting for the status to arrive. You could wait for the usb_handle_class_ctrl_read callback and do it (move to cm_CTROL_READ_AWAITING_STATUS) but the PicPack USB stack can handle the control read event for you if you've already switched states.
If it is a control write transfer (that is, it is a request by the host to send data to the device), then you will need to move the control_mode state variable to cm_CTRL_WRITE_DATA_STAGE_CLASS. Then, the usb_handle_class_ctrl_write will be fired when data is received by the device in the data stage.
To allow this callback to trigger, ensure you define USB_CALLBACK_ON_CLASS_CTRL in your config.h
usb_handle_isr() should be inserted in your interrupt service routine. Alternatively, if you have reason not to want to do interrupt-driven USB, for example, a bootloader, you can poll this routine.
Make sure you call turn_usb_ints() and turn_global_ints_on() to ensure interrupts occur.
It will check for any of the USB interrupt flags and handle: USB transactions, USB reset, USB stall, USB Start Of Frame (including calling usb_SOF_callback() if configured in your config.h and most importantly USB transaction, which is where all the hard work is done.
00928 {
00929
00930 while (test_bit(pir2, USBIF)) {
00931
00932 while (test_bit(uir, TRNIF)) {
00933 uns8 stat = ustat;
00934 clear_bit(uir, TRNIF);
00935 usb_handle_transaction(stat);
00936 }
00937
00938 if (test_bit(uir, URSTIF)) {
00939 usb_handle_reset();
00940 clear_bit(uir, URSTIF);
00941 }
00942
00943 if (test_bit(uir, STALLIF)) {
00944 usb_handle_stall();
00945 clear_bit(uir, STALLIF);
00946 }
00947 if (test_bit(uir, SOFIF)) {
00948 #ifdef USB_CALLBACK_ON_SOF
00949 #ifdef ufrm
00950 usb_SOF_callback(ufrm);
00951 #else
00952 usb_SOF_callback(ufrmh << 8 | ufrml);
00953 #endif
00954 clear_bit(uir, SOFIF);
00955 #endif
00956 }
00957
00958 clear_bit(pir2, USBIF);
00959 }
00960 }
void usb_send_data |
( |
uns8 |
ep, |
|
|
uns8 * |
data, |
|
|
uns8 |
send_count, |
|
|
bit |
first | |
|
) |
| | |
Use this routine to send data across the USB pipe.
- Parameters:
-
| ep | Endpoint that the data should be sent from |
| data | pointer to the data |
| send_count | the number of bytes to send |
| first | True if this is the first in a series of sends. Generally, this can be set to False, since it will automatically be set to the right value on endpoint creation. However, in the case of control transfers, the data stage needs to have the first parameter set to True to ensure the DTS bit is set correctly. |
00211 {
00212 uns8 count;
00213 buffer_descriptor *bd;
00214 uns8 *buffer;
00215
00216
00217 #ifdef USB_DEBUG
00218 serial_print_str("Send:EP");
00219 serial_print_int(ep);
00220 serial_putc(' ');
00221 #endif
00222
00223 buffer = ep_in_buffer_location[ep];
00224
00225 bd = ep_in_bd_location[ep];
00226
00227 if (test_bit(bd->stat, UOWN)) {
00228 #ifdef USB_DEBUG
00229 serial_print_str(" !Adon't own it! ");
00230 #endif
00231 return;
00232 }
00233
00234 count = 0;
00235 while ((count < send_count)) {
00236 buffer[count] = data[count];
00237 count++;
00238 }
00239
00240
00241 bd->count = count;
00242 bd->addr = (uns16)buffer;
00243 if (first) {
00244 clear_bit(bd->stat, DTS);
00245 }
00246
00247 toggle_bit(bd->stat, DTS);
00248 clear_bit(bd->stat, KEN);
00249 clear_bit(bd->stat, INCDIS);
00250 set_bit (bd->stat, DTSEN);
00251 clear_bit(bd->stat, BSTALL);
00252 clear_bit(bd->stat, BC9);
00253 clear_bit(bd->stat, BC8);
00254
00255 set_bit (bd->stat, UOWN);
00256 }
void usb_send_empty_data_pkt |
( |
|
) |
|
Use this routine to send an data across the USB pipe on endpoint 0. This is the equivalent of sending a status acknowledge.
usb_setup() configures the PIC USB hardware ready for use and prepares the internal data structures used to keep track of where the endpoint buffers are.
After calling usb_setup(), you are ready to call usb_enable_module() to actually start USB negotiations. Ensure that you have usb_handle_isr() in your interrupt service routine.
00973 {
00974
00975 usb_state = st_POWERED;
00976
00977
00978 #ifdef UTRDIS
00979 clear_bit(ucfg, UTRDIS);
00980 #endif
00981 set_bit (ucfg, FSEN);
00982 set_bit (ucfg, UPUEN);
00983
00984 clear_bit(ucfg, PPB1);
00985 set_bit(ucfg, PPB0);
00986
00987
00988 set_bit(ucon, PPBRST);
00989 clear_bit(ucon, PPBRST);
00990
00991
00992
00993 set_bit(uep0, EPHSHK);
00994 set_bit(uep0, EPOUTEN);
00995 set_bit(uep0, EPINEN);
00996 clear_bit(uep0, EPCONDIS);
00997
00998
00999
01000
01001 ep_out_bd_location[0] = &bd0out_e;
01002 #if USB_HIGHEST_EP >= 1
01003 ep_out_bd_location[1] = &bd1out;
01004 #endif
01005 #if USB_HIGHEST_EP >= 2
01006 ep_out_bd_location[2] = &bd2out;
01007 #endif
01008 #if USB_HIGHEST_EP >= 3
01009 ep_out_bd_location[3] = &bd3out;
01010 #endif
01011 #if USB_HIGHEST_EP >= 4
01012 ep_out_bd_location[4] = &bd4out;
01013 #endif
01014
01015 ep_in_bd_location[0] = &bd0in;
01016 #if USB_HIGHEST_EP >= 1
01017 ep_in_bd_location[1] = &bd1in;
01018 #endif
01019 #if USB_HIGHEST_EP >= 2
01020 ep_in_bd_location[2] = &bd2in;
01021 #endif
01022 #if USB_HIGHEST_EP >= 3
01023 ep_in_bd_location[3] = &bd3in;
01024 #endif
01025 #if USB_HIGHEST_EP >= 4
01026 ep_in_bd_location[4] = &bd4in;
01027 #endif
01028
01029
01030 }
void usb_SOF_callback |
( |
uns16 |
frame |
) |
|
Frames in USB occur each 1ms. A SOF packet is sent to each device at the start of each frame. This is a really neat way of getting a 1ms timer without any further work.
- Parameters:
-
| frame | The frame number. Frames will wrap at 65535. |
Use this routine to send a stall on the control transfer endpoint - usually used to indicate that the requested function is not available.
Variable Documentation
Store the control mode state
Store the last setup data packet
Store the current USB device state