123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- /*
- * cdc_acm.c
- *
- * USB CDC ACM handling (Communications Device Class, Abstract Control Model).
- *
- * Written & released by Keir Fraser <keir.xen@gmail.com>
- *
- * This is free and unencumbered software released into the public domain.
- * See the file COPYING for more details, or visit <http://unlicense.org>.
- */
- #define TRACE 1
- /* CDC Communications Class requests */
- #define CDC_SET_LINE_CODING 0x20
- #define CDC_GET_LINE_CODING 0x21
- #define CDC_SET_CONTROL_LINE_STATE 0x22
- #define CDC_SEND_BREAK 0x23
- static struct packed line_coding {
- uint32_t baud;
- uint8_t nr_stop;
- uint8_t parity;
- uint8_t nr_data;
- } line_coding = {
- .baud = 9600,
- .nr_stop = 0,
- .parity = 0,
- .nr_data = 8 };
- #if TRACE
- #define TRC printk
- #else
- static inline void TRC(const char *format, ...) { }
- #endif
- static void dump_line_coding(const struct line_coding *lc)
- {
- int parity = (lc->parity > 4) ? 5 : lc->parity;
- TRC("%u,%u%c%s\n", lc->baud, lc->nr_data,
- "noems?"[parity],
- (lc->nr_stop == 0) ? "1"
- : (lc->nr_stop == 1) ? "1.5"
- : (lc->nr_stop == 2) ? "2" : "X");
- }
- bool_t cdc_acm_handle_class_request(void)
- {
- struct usb_device_request *req = &ep0.req;
- bool_t handled = TRUE;
- switch (req->bRequest) {
- case CDC_SET_LINE_CODING: {
- struct line_coding *lc = (struct line_coding *)ep0.data;
- TRC("SET_LINE_CODING: ");
- dump_line_coding(lc);
- if (line_coding.baud != lc->baud) {
- switch (lc->baud) {
- case BAUD_CLEAR_COMMS:
- usb_cdc_acm_ops.configure();
- printk("Comms Line Cleared\n");
- break;
- }
- }
- line_coding = *lc;
- break;
- }
- case CDC_GET_LINE_CODING: {
- struct line_coding *lc = (struct line_coding *)ep0.data;
- TRC("GET_LINE_CODING: ");
- *lc = line_coding;
- dump_line_coding(lc);
- ep0.data_len = sizeof(*lc);
- break;
- }
- case CDC_SET_CONTROL_LINE_STATE:
- /* wValue = DTR/RTS. We ignore them and return success. */
- break;
- case CDC_SEND_BREAK:
- /* wValue = #millisecs. We ignore it and return success. */
- TRC("BREAK\n");
- break;
- default:
- WARN("[Class-specific: %02x]\n", req->bRequest);
- handled = FALSE;
- break;
- }
- return handled;
- }
- bool_t cdc_acm_set_configuration(void)
- {
- uint8_t bulk_type = EPT_DBLBUF;
- #ifdef BOOTLOADER
- /* We don't bother with the complicated double-buffered endpoints. The
- * regular bulk endpoints are fast enough and possibly more reliable. */
- bulk_type = EPT_BULK;
- #endif
- gw_info.usb_speed = usb_is_highspeed() ? 1 : 0;
- /* Notification Element (D->H) */
- usb_configure_ep(0x81, EPT_INTERRUPT, 0);
- /* Bulk Pipe (H->D) */
- usb_configure_ep(0x02, bulk_type, usb_bulk_mps);
- /* Bulk Pipe (D->H) */
- usb_configure_ep(0x83, bulk_type, usb_bulk_mps);
- usb_cdc_acm_ops.configure();
- return TRUE;
- }
- /*
- * Local variables:
- * mode: C
- * c-file-style: "Linux"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
|