📄 usbs.h
字号:
// functions. However in simple devices those device-specific // state change functions could be invoked directly. void (*state_change_fn)(struct usbs_control_endpoint*, void*, usbs_state_change, int /* old state */); void* state_change_data; // When a standard control message arrives, the device driver will // detect some requests such as SET_ADDRESS and handle it // internally. Otherwise if higher-level code has installed a // callback then that will be invoked. If the callback returns // UNKNOWN then the default handler usbs_handle_standard_control() // is used to process the request. usbs_control_return (*standard_control_fn)(struct usbs_control_endpoint*, void*); void* standard_control_data; // These three callbacks are used for other types of control // messages. The generic USB code has no way of knowing what // such control messages are about. usbs_control_return (*class_control_fn)(struct usbs_control_endpoint*, void*); void* class_control_data; usbs_control_return (*vendor_control_fn)(struct usbs_control_endpoint*, void*); void* vendor_control_data; usbs_control_return (*reserved_control_fn)(struct usbs_control_endpoint*, void*); void* reserved_control_data; // If a control operation involves transferring more data than // just the initial eight-byte packet, the following fields are // used to keep track of the current operation. The original // control request indicates the direction of the transfer (IN or // OUT) and a length field. For OUT this length is exact, for IN // it is an upper bound. The transfer operates mostly as per the // bulk protocol, but if the length requested is an exact multiple // of the control fifo size (typically eight bytes) then there // is no need for an empty packet at the end. // // For an OUT operation the control message handler should supply // a suitable buffer via the "buffer" field below. The only other // field of interest is the complete_fn which must be provided and // will be invoked once all the data has arrived. Alternatively // the OUT operation may get aborted if a new control message // arrives. The second argument is an error code -EPIPE or -EIO, // or zero to indicate success. The return code is used by the // device driver during the status phase. // // IN is more complicated and the defined interface makes it // possible to gather data from multiple locations, eliminating // the need for copying into large buffers in some circumstances. // Basically when an IN request arrives the device driver will // look at the buffer and buffer_size fields, extracting data from // there if possible. If the current buffer has been exhausted // then the the refill function will be invoked, and this can // reset the buffer and size fields to point somewhere else. // This continues until such time that there is no longer // a refill function and the current buffer is empty. The // refill function can use the refill_data and refill_index // to keep track of the current state. The control_buffer // fields are available as well. At the end of the transfer, // if a completion function has been supplied then it will // be invoked. The return code will be ignored. unsigned char* buffer; int buffer_size; void (*fill_buffer_fn)(struct usbs_control_endpoint*); void* fill_data; int fill_index; usbs_control_return (*complete_fn)(struct usbs_control_endpoint*, int);} usbs_control_endpoint;// Data endpoints are a little bit simpler, but not much. From the// perspective of a device driver things a single buffer is most// convenient, but that is quite likely to require a max-size buffer// at a higher level and an additional copy operation. Supplying// a vector of buffers is a bit more general, but in a layered// system it may be desirable to prepend to this vector...// A combination of a current buffer and a refill/empty function// offers flexibility, at the cost of additional function calls// from inside the device driver.//// FIXME: implement support for fill/empty functions.//// Some USB devices may prefer buffers of particular alignment,// e.g. for DMA purposes. This is hard to reconcile with the// current interface. However pushing such alignment restrictions// etc. up into the higher levels is difficult, e.g. it does// not map at all onto a conventional read/write interface.// The device driver will just have to do the best it can.//// The completion function will be invoked at the end of the transfer.// The second argument indicates per-transfer completion data. The// third argument indicates the total amount received, or an error// code: typically -EPIPE to indicate a broken conenction; -EAGAIN to// indicate a stall condition; -EMSGSIZE if the host is sending more// data than the target is expecting; or -EIO to indicate some other// error. Individual device drivers should avoid generating other// errors.typedef struct usbs_rx_endpoint { void (*start_rx_fn)(struct usbs_rx_endpoint*); void (*set_halted_fn)(struct usbs_rx_endpoint*, cyg_bool); void (*complete_fn)(void*, int); void* complete_data; unsigned char* buffer; int buffer_size; cyg_bool halted;} usbs_rx_endpoint;typedef struct usbs_tx_endpoint { void (*start_tx_fn)(struct usbs_tx_endpoint*); void (*set_halted_fn)(struct usbs_tx_endpoint*, cyg_bool); void (*complete_fn)(void*, int); void* complete_data; const unsigned char*buffer; int buffer_size; cyg_bool halted;} usbs_tx_endpoint;// Functions called by device drivers.extern usbs_control_return usbs_handle_standard_control(struct usbs_control_endpoint*); // Utility functions. These just invoke the corresponding function// pointers in the endpoint structures. It is assumed that the// necessary fields in the endpoint structures will have been// filled in already.extern void usbs_start(usbs_control_endpoint*);extern void usbs_start_rx(usbs_rx_endpoint*);extern void usbs_start_tx(usbs_tx_endpoint*);extern void usbs_start_rx_buffer(usbs_rx_endpoint*, unsigned char*, int, void (*)(void*, int), void*);extern void usbs_start_tx_buffer(usbs_tx_endpoint*, const unsigned char*, int, void (*)(void*, int), void*);extern cyg_bool usbs_rx_endpoint_halted(usbs_rx_endpoint*);extern cyg_bool usbs_tx_endpoint_halted(usbs_tx_endpoint*);extern void usbs_set_rx_endpoint_halted(usbs_rx_endpoint*, cyg_bool);extern void usbs_set_tx_endpoint_halted(usbs_tx_endpoint*, cyg_bool);extern void usbs_start_rx_endpoint_wait(usbs_rx_endpoint*, void (*)(void*, int), void*);extern void usbs_start_tx_endpoint_wait(usbs_tx_endpoint*, void (*)(void*, int), void*); // Functions that can go into devtab entries. These should not be// called directly, they are intended only for use by USB device// drivers.#if defined(CYGPKG_IO) && defined(CYGPKG_ERROR)#include <cyg/io/io.h>extern Cyg_ErrNo usbs_devtab_cwrite(cyg_io_handle_t, const void*, cyg_uint32*);extern Cyg_ErrNo usbs_devtab_cread(cyg_io_handle_t, void*, cyg_uint32*);extern Cyg_ErrNo usbs_devtab_get_config(cyg_io_handle_t, cyg_uint32, void*, cyg_uint32*);extern Cyg_ErrNo usbs_devtab_set_config(cyg_io_handle_t, cyg_uint32, const void*, cyg_uint32*);#endif// Additional support for testing.// Test cases need to have some way of finding out about what support is// actually provided by the USB device driver, for example what endpoints// are available. There is no perfect way of achieving this. One approach// would be to scan through the devtab table looking for devices of the// form /dev/usbs1r. That is not reliable: the devtab entries may have been// configured out if higher-level code uses the usb-specific API; or the// devtab entries may have been renamed. Also having a devtab entry does not// really give the kind of information a general-purpose testcase needs,// for example upper bounds on transfer size. // // An alternative approach is to have a data structure that somehow// defines the USB hardware, and the USB device driver then creates an// instance of this. This is the approach actually taken. The problem// now is how the test code can access this instance. Accessing by// unique name is simple, as long as there is only one USB device in// the system (which of course will usually be the case on the USB// slave side). Alternative approaches such as creating a table at// link time or a list during static construction time are vulnerable// either to selective linking or to having these structures present// in applications other than the test cases. In future it might be// possible to address the latter issue by extending the build system// support, e.g. a new library libtesting.a and a new object file// testing.o.//// Note that a given endpoint could be used for bulk transfers some// of the time, then for isochronous transfers, etc. It is the// responsibility of the host to only perform one type of IN operation// for a given endpoint number, and ditto for OUT. typedef struct usbs_testing_endpoint { int endpoint_type; // One of ATTR_CONTROL, ATTR_BULK, ... int endpoint_number; // Between 0 and 15 int endpoint_direction; // ENDPOINT_IN or ENDPOINT_OUT void* endpoint; // pointer to the usbs_control_endpoint, usbs_rx_endpoint, ... const char* devtab_entry; // e.g. "/dev/usbs1r", or 0 if inaccessible via devtab int min_size; // Minimum transfer size int max_size; // -1 indicates no specific upper bound int max_in_padding; // extra bytes that the target may send, usually 0. // Primarily for SA11x0 hardware. It is assumed // for now that no other hardware will exhibit // comparable problems. int alignment; // Buffer should be aligned to a suitable boundary} usbs_testing_endpoint;// A specific instance provided by the device driver. The end of// the table is indicated by a NULL endpoint field. extern usbs_testing_endpoint usbs_testing_endpoints[]; #define USBS_TESTING_ENDPOINTS_TERMINATOR \ { \ endpoint_type : USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL, \ endpoint_number : 0, \ endpoint_direction : USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN, \ endpoint : (void*) 0, \ devtab_entry : (const char*) 0, \ min_size : 0, \ max_size : 0, \ max_in_padding : 0, \ alignment : 0 \ }#define USBS_TESTING_ENDPOINTS_IS_TERMINATOR(_endpoint_) ((void*)0 == (_endpoint_).endpoint) #ifdef __cplusplus} // extern "C" {#endif#endif // CYGONCE_USBS_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -