From 7f002110dcccf7efb8c260bdc2106c2192257c96 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 6 Nov 2010 12:21:46 +1300 Subject: [PATCH] Improved dispatching of user control callbacks. Only cdc_acm example is updated. --- examples/other/usb_cdcacm/cdcacm.c | 31 +++---- include/usbd.h | 15 ++-- lib/usb/usb_control.c | 126 +++++++++++------------------ lib/usb/usb_private.h | 15 ++-- 4 files changed, 72 insertions(+), 115 deletions(-) diff --git a/examples/other/usb_cdcacm/cdcacm.c b/examples/other/usb_cdcacm/cdcacm.c index ae4ad1c6..3d37db2b 100644 --- a/examples/other/usb_cdcacm/cdcacm.c +++ b/examples/other/usb_cdcacm/cdcacm.c @@ -163,18 +163,19 @@ static const char *usb_strings[] = { "DEMO" }; -static int cdcacm_control_command(struct usb_setup_data *req, - void (**complete)(struct usb_setup_data *req)) +static int cdcacm_control_request(struct usb_setup_data *req, u8 **buf, + u16 *len, void (**complete)(struct usb_setup_data *req)) { (void)complete; - char buf[10]; - struct usb_cdc_notification *notif = (void*)buf; + (void)buf; switch(req->bRequest) { - case USB_CDC_REQ_SET_CONTROL_LINE_STATE: + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { /* This Linux cdc_acm driver requires this to be implemented * even though it's optional in the CDC spec, and we don't * advertise it in the ACM functional descriptor. */ + char buf[10]; + struct usb_cdc_notification *notif = (void*)buf; /* We echo signals back to host as notification */ notif->bmRequestType = 0xA1; @@ -186,19 +187,9 @@ static int cdcacm_control_command(struct usb_setup_data *req, buf[9] = 0; //usbd_ep_write_packet(0x83, buf, 10); return 1; - } - return 0; -} - -static int cdcacm_control_write(struct usb_setup_data *req, u8 *buf, u16 len, - void (**complete)(struct usb_setup_data *req)) -{ - (void)complete; - (void)buf; - - switch(req->bRequest) { + } case USB_CDC_REQ_SET_LINE_CODING: - if(len < sizeof(struct usb_cdc_line_coding)) + if(*len < sizeof(struct usb_cdc_line_coding)) return 0; return 1; @@ -226,8 +217,10 @@ static void cdcacm_set_config(u16 wValue) usbd_ep_setup(0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); - usbd_register_control_command_callback(cdcacm_control_command); - usbd_register_control_write_callback(cdcacm_control_write); + usbd_register_control_callback( + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); } int main(void) diff --git a/include/usbd.h b/include/usbd.h index d825d9ec..310c44e6 100644 --- a/include/usbd.h +++ b/include/usbd.h @@ -36,16 +36,13 @@ extern void usbd_register_reset_callback(void (*callback)(void)); extern void usbd_register_suspend_callback(void (*callback)(void)); extern void usbd_register_resume_callback(void (*callback)(void)); +typedef int (*usbd_control_callback)(struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + void (**complete)(struct usb_setup_data *req)); + /* */ -extern void usbd_register_control_command_callback( - int (*callback)(struct usb_setup_data *req, - void (**complete)(struct usb_setup_data *req))); -extern void usbd_register_control_read_callback( - int (*callback)(struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, void (**complete)(struct usb_setup_data *req))); -extern void usbd_register_control_write_callback( - int (*callback)(struct usb_setup_data *req, uint8_t *buf, - uint16_t len, void (**complete)(struct usb_setup_data *req))); +extern int usbd_register_control_callback(uint8_t type, uint8_t type_mask, + usbd_control_callback callback); /* */ extern void diff --git a/lib/usb/usb_control.c b/lib/usb/usb_control.c index f5e4d27c..c10144d8 100644 --- a/lib/usb/usb_control.c +++ b/lib/usb/usb_control.c @@ -36,30 +36,21 @@ static struct usb_control_state { } control_state; /** Register application callback function for handling of usb control - * request with no data. */ -void usbd_register_control_command_callback( - int (*callback)(struct usb_setup_data *req, - void (**complete)(struct usb_setup_data *req))) + * request. */ +int usbd_register_control_callback(uint8_t type, uint8_t type_mask, + usbd_control_callback callback) { - _usbd_device.user_callback_control_command = callback; -} + int i; + for(i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) { + if(_usbd_device.user_control_callback[i].cb) + continue; -/** Register application callback function for handling of usb control - * request to read data. */ -void usbd_register_control_read_callback( - int (*callback)(struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, void (**complete)(struct usb_setup_data *req))) -{ - _usbd_device.user_callback_control_read = callback; -} - -/** Register application callback function for handling of usb control - * request with received data. */ -void usbd_register_control_write_callback( - int (*callback)(struct usb_setup_data *req, uint8_t *buf, uint16_t len, - void (**complete)(struct usb_setup_data *req))) -{ - _usbd_device.user_callback_control_write = callback; + _usbd_device.user_control_callback[i].type = type; + _usbd_device.user_control_callback[i].type_mask = type_mask; + _usbd_device.user_control_callback[i].cb = callback; + return 0; + } + return -1; } static void usb_control_send_chunk(void) @@ -102,58 +93,47 @@ static int usb_control_recv_chunk(void) return packetsize; } -static void usb_control_setup_nodata(struct usb_setup_data *req) +static int usb_control_request_dispatch(struct usb_setup_data *req) { int result = 0; - - /* Buffer unused */ - control_state.ctrl_buf = _usbd_device.ctrl_buf; - control_state.ctrl_len = 0; + int i; + struct user_control_callback *cb = _usbd_device.user_control_callback; /* Call user command hook function */ - if(_usbd_device.user_callback_control_command) - result = _usbd_device.user_callback_control_command(req, - &control_state.complete); + for(i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) { + if(cb[i].cb == NULL) + break; - /* Try standard command if not already handled */ - if(!result) - result = _usbd_standard_request(req, - &control_state.ctrl_buf, - &control_state.ctrl_len); - - if(result) { - /* Go to status stage if handled */ - usbd_ep_write_packet(0, NULL, 0); - control_state.state = STATUS_IN; - } else { - /* Stall endpoint on failure */ - usbd_ep_stall_set(0, 1); - } -} - -static void usb_control_setup_read(struct usb_setup_data *req) -{ - int result = 0; - - control_state.ctrl_buf = _usbd_device.ctrl_buf; - control_state.ctrl_len = req->wLength; - - /* Call user command hook function */ - if(_usbd_device.user_callback_control_read) - result = _usbd_device.user_callback_control_read(req, - &control_state.ctrl_buf, + if((req->bmRequestType & cb[i].type_mask) == cb[i].type) { + result = cb[i].cb(req, &control_state.ctrl_buf, &control_state.ctrl_len, &control_state.complete); + if(result) + return result; + } + } /* Try standard request if not already handled */ - if(!result) - result = _usbd_standard_request(req, - &control_state.ctrl_buf, + return _usbd_standard_request(req, &control_state.ctrl_buf, &control_state.ctrl_len); - - if(result) { - /* Go to status stage if handled */ - usb_control_send_chunk(); +} + +/* Handle commands and read requests. */ +static void usb_control_setup_read(struct usb_setup_data *req) +{ + + control_state.ctrl_buf = _usbd_device.ctrl_buf; + control_state.ctrl_len = req->wLength; + + if(usb_control_request_dispatch(req)) { + if(control_state.ctrl_len) { + /* Go to data out stage if handled */ + usb_control_send_chunk(); + } else { + /* Go to status stage if handled */ + usbd_ep_write_packet(0, NULL, 0); + control_state.state = STATUS_IN; + } } else { /* Stall endpoint on failure */ usbd_ep_stall_set(0, 1); @@ -189,7 +169,7 @@ void _usbd_control_setup(uint8_t ea) } if(req->wLength == 0) { - usb_control_setup_nodata(req); + usb_control_setup_read(req); } else if(req->bmRequestType & 0x80) { usb_control_setup_read(req); } else { @@ -216,20 +196,8 @@ void _usbd_control_out(uint8_t ea) /* We have now received the full data payload. * Invoke callback to process. */ - if(_usbd_device.user_callback_control_write) - result = _usbd_device.user_callback_control_write( - &control_state.req, - control_state.ctrl_buf, - control_state.ctrl_len, - &control_state.complete); - - if(!result) - result = _usbd_standard_request( - &control_state.req, - &control_state.ctrl_buf, - &control_state.ctrl_len); - - if(result) { + if(usb_control_request_dispatch(&control_state.req)) { + /* Got to status stage on success */ usbd_ep_write_packet(0, NULL, 0); control_state.state = STATUS_IN; } else { diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h index 6cbc5765..6c7e0739 100644 --- a/lib/usb/usb_private.h +++ b/lib/usb/usb_private.h @@ -21,6 +21,8 @@ #ifndef __USB_PRIVATE_H #define __USB_PRIVATE_H +#define MAX_USER_CONTROL_CALLBACK 4 + #define MIN(a, b) ((a)<(b) ? (a) : (b)) /** Internal collection of device information. */ @@ -42,14 +44,11 @@ extern struct _usbd_device { void (*user_callback_suspend)(void); void (*user_callback_resume)(void); - int (*user_callback_control_command)(struct usb_setup_data *req, - void (**complete)(struct usb_setup_data *req)); - int (*user_callback_control_read)(struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - void (**complete)(struct usb_setup_data *req)); - int (*user_callback_control_write)(struct usb_setup_data *req, - uint8_t *buf, uint16_t len, - void (**complete)(struct usb_setup_data *req)); + struct user_control_callback { + usbd_control_callback cb; + uint8_t type; + uint8_t type_mask; + } user_control_callback[MAX_USER_CONTROL_CALLBACK]; void (*user_callback_ctr[8][3])(uint8_t ea);