1 //==========================================================================
5 // Support for slave-side USB serial devices.
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
35 // -------------------------------------------
36 //####ECOSGPLCOPYRIGHTEND####
37 //==========================================================================
38 //#####DESCRIPTIONBEGIN####
40 // Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc.
43 //####DESCRIPTIONEND####
45 //==========================================================================
47 #include <cyg/infra/cyg_type.h>
48 #include <cyg/infra/cyg_ass.h>
49 #include <cyg/infra/cyg_trac.h>
50 #include <cyg/infra/diag.h>
51 #include <cyg/hal/hal_arch.h>
52 #include <cyg/hal/drv_api.h>
53 #include <cyg/kernel/kapi.h>
55 #include <pkgconf/io_usb_slave_serial.h>
56 #include <cyg/io/usb/usbs_serial.h>
59 #if defined(CYGBLD_IO_USB_SLAVE_SERIAL_DEBUG)
60 #define DBG diag_printf
62 #define DBG (1) ? (void)0 : diag_printf
65 #define EP0_MAX_PACKET_SIZE CYGNUM_IO_USB_SLAVE_SERIAL_EP0_MAX_PACKET_SIZE
67 extern usbs_control_endpoint CYGDAT_IO_USB_SLAVE_SERIAL_EP0;
68 extern usbs_tx_endpoint CYGDAT_IO_USB_SLAVE_SERIAL_TX_EP;
69 extern usbs_rx_endpoint CYGDAT_IO_USB_SLAVE_SERIAL_RX_EP;
71 #define TX_EP_NUM CYGNUM_IO_USB_SLAVE_SERIAL_TX_EP_NUM
72 #define RX_EP_NUM CYGNUM_IO_USB_SLAVE_SERIAL_RX_EP_NUM
73 #define INTR_EP_NUM CYGNUM_IO_USB_SLAVE_SERIAL_INTR_EP_NUM
74 #define EP0 (&CYGDAT_IO_USB_SLAVE_SERIAL_EP0)
75 #define TX_EP (&CYGDAT_IO_USB_SLAVE_SERIAL_TX_EP)
76 #define RX_EP (&CYGDAT_IO_USB_SLAVE_SERIAL_RX_EP)
77 #define INTR_EP (&CYGDAT_IO_USB_SLAVE_SERIAL_INTR_EP)
80 #define VENDOR_ID CYGNUM_IO_USB_SLAVE_SERIAL_VENDOR_ID
81 #define PRODUCT_ID CYGNUM_IO_USB_SLAVE_SERIAL_PRODUCT_ID
83 #define USB_MAX_STR_LEN 256
85 #define LO_BYTE_16(word16) ((cyg_uint8) ((word16) & 0xFF))
86 #define HI_BYTE_16(word16) ((cyg_uint8) (((word16) >> 8) & 0xFF))
88 #define BYTE0_32(word32) ((cyg_uint8) ((word32) & 0xFF))
89 #define BYTE1_32(word32) ((cyg_uint8) (((word32) >> 8) & 0xFF))
90 #define BYTE2_32(word32) ((cyg_uint8) (((word32) >> 16) & 0xFF))
91 #define BYTE3_32(word32) ((cyg_uint8) (((word32) >> 24) & 0xFF))
94 #define MFG_STR_INDEX '\x01'
95 #define PRODUCT_STR_INDEX '\x02'
97 #define USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH(interfaces, endpoints) \
98 (USB_CONFIGURATION_DESCRIPTOR_LENGTH + \
99 ((interfaces) * USB_INTERFACE_DESCRIPTOR_LENGTH) + \
100 ((endpoints) * USB_ENDPOINT_DESCRIPTOR_LENGTH))
103 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
104 #define USBS_SERIAL_DEVICE_CLASS 2
105 #define USBS_SERIAL_NUM_IFACE 2
106 #define USBS_SERIAL_NUM_ENDP 3
107 #define USBS_SERIAL_DATA_IFACE_CLASS 0x0A // Data
109 #define USBS_SERIAL_DEVICE_CLASS 0
110 #define USBS_SERIAL_NUM_IFACE 1
111 #define USBS_SERIAL_NUM_ENDP 2
112 #define USBS_SERIAL_DATA_IFACE_CLASS 0xFF // Vendor
115 // ----- Configuration Descriptor -----
117 static const usb_configuration_descriptor usb_configuration = {
118 length: sizeof(usb_configuration_descriptor),
119 type: USB_CONFIGURATION_DESCRIPTOR_TYPE,
121 USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(USBS_SERIAL_NUM_IFACE,
122 USBS_SERIAL_NUM_ENDP),
124 USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(USBS_SERIAL_NUM_IFACE,
125 USBS_SERIAL_NUM_ENDP),
126 number_interfaces: USBS_SERIAL_NUM_IFACE,
128 configuration_str: 0,
129 attributes: (USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED |
130 USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED),
134 // ----- Interface Descriptor -----
136 static const usb_interface_descriptor usb_interface[] = {
138 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
140 length: sizeof(usb_interface_descriptor),
141 type: USB_INTERFACE_DESCRIPTOR_TYPE,
143 alternate_setting: 0,
145 interface_class: 0x02, // Comm class
146 interface_subclass: 0x02,
147 interface_protocol: 0x01,
151 length: sizeof(usb_interface_descriptor),
152 type: USB_INTERFACE_DESCRIPTOR_TYPE,
154 alternate_setting: 0,
156 interface_class: USBS_SERIAL_DATA_IFACE_CLASS,
157 interface_subclass: 0x00,
158 interface_protocol: 0x00,
163 length: sizeof(usb_interface_descriptor),
164 type: USB_INTERFACE_DESCRIPTOR_TYPE,
166 alternate_setting: 0,
168 interface_class: USBS_SERIAL_DATA_IFACE_CLASS,
169 interface_subclass: 0x00,
170 interface_protocol: 0x00,
176 // ----- Endpoint Descriptors -----
178 static const usb_endpoint_descriptor usb_endpoints[] =
180 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
181 // Interrupt in endpoint
183 sizeof(usb_endpoint_descriptor),
184 USB_ENDPOINT_DESCRIPTOR_TYPE,
185 USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN | INTR_EP_NUM,
186 USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT,
193 // Tx (Bulk IN) Endpoint Descriptor
195 sizeof(usb_endpoint_descriptor),
196 USB_ENDPOINT_DESCRIPTOR_TYPE,
197 USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN | TX_EP_NUM,
198 USB_ENDPOINT_DESCRIPTOR_ATTR_BULK,
204 // Rx (Bulk OUT) Endpoint Descriptor
206 sizeof(usb_endpoint_descriptor),
207 USB_ENDPOINT_DESCRIPTOR_TYPE,
208 USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT | RX_EP_NUM,
209 USB_ENDPOINT_DESCRIPTOR_ATTR_BULK,
216 // ----- String Descriptors -----
218 static char mfg_str_descr[USB_MAX_STR_LEN],
219 product_str_descr[USB_MAX_STR_LEN];
222 static const char* usb_strings[] = {
228 // ----- Enumeration Data w/ Device Descriptor -----
230 static usbs_enumeration_data usb_enum_data = {
232 length: sizeof(usb_device_descriptor),
233 type: USB_DEVICE_DESCRIPTOR_TYPE,
236 device_class: USBS_SERIAL_DEVICE_CLASS,
239 max_packet_size: EP0_MAX_PACKET_SIZE,
240 vendor_lo: LO_BYTE_16(VENDOR_ID),
241 vendor_hi: HI_BYTE_16(VENDOR_ID),
242 product_lo: LO_BYTE_16(PRODUCT_ID),
243 product_hi: HI_BYTE_16(PRODUCT_ID),
246 manufacturer_str: MFG_STR_INDEX,
247 product_str: PRODUCT_STR_INDEX,
248 serial_number_str: 0,
249 number_configurations: 1
252 total_number_interfaces: USBS_SERIAL_NUM_IFACE,
253 total_number_endpoints: USBS_SERIAL_NUM_ENDP,
254 total_number_strings: 3,
255 configurations: &usb_configuration,
256 interfaces: usb_interface,
257 endpoints: usb_endpoints,
258 strings: (const unsigned char **) usb_strings
261 // --------------------------------------------------------------------------
263 // --------------------------------------------------------------------------
265 usbs_control_endpoint* usbs_serial_ep0 = EP0;
267 // Lock for the state.
268 cyg_mutex_t usbs_serial_lock;
270 // Condition variable for state changes
271 cyg_cond_t usbs_serial_state_cond;
273 int usbs_serial_state;
275 usbs_serial usbs_ser0 = {
282 static void (*usbs_serial_app_state_change_fn)(struct usbs_control_endpoint*,
283 void*, usbs_state_change, int)
286 // --------------------------------------------------------------------------
287 // Create a USB String Descriptor from a C string.
290 usbs_serial_create_str_descriptor(char descr[], const char *str)
292 int i, n = strlen(str);
294 if (n > (USB_MAX_STR_LEN/2 - 2))
295 n = USB_MAX_STR_LEN/2 - 2;
297 descr[0] = (cyg_uint8) (2*n + 2);
298 descr[1] = USB_DEVREQ_DESCRIPTOR_TYPE_STRING;
300 for (i=0; i<n; i++) {
301 descr[i*2+2] = str[i];
302 descr[i*2+3] = '\x00';
306 // --------------------------------------------------------------------------
309 // For a Windows host, the device must, at least, respond to a SetLineCoding
310 // request (0x20), otherwise Windows will report that it's unable to open the
311 // port. This request normally sets the standard serial parameters:
312 // baud rate, # stop bits, parity, and # data bits
313 // If we're just making believe that we're a serial port to communicate with
314 // the host via USB, then these values don't matter. So we ACK the request,
315 // but ignore the parameters.
316 // If we were actually creating a USB-serial converter, then we would need to
317 // read these values and configure the serial port accordingly.
319 // Similarly, the host can request the current settings through a
320 // GetLineCoding request (0x21). Since we're just faking it, we return some
321 // arbitrary values: 38400,1,N,8
323 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
325 static usbs_control_return
326 usbs_serial_acm_class_handler(usbs_control_endpoint* ep0, void* data)
328 usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN;
329 usb_devreq *req = (usb_devreq *) ep0->control_buffer;
330 static cyg_uint8 rsp_buf[32];
331 cyg_uint32 baud = 38400; // Arbitrary, fake value to return to the host.
333 DBG("USB Serial ACM Class Handler: ");
335 switch (req->request) {
337 case USBS_SERIAL_SET_LINE_CODING :
338 DBG("ACM Request: Set Line Coding\n");
339 result = USBS_CONTROL_RETURN_HANDLED;
342 case USBS_SERIAL_GET_LINE_CODING :
343 DBG("ACM Request: Get Line Coding\n");
344 rsp_buf[0] = BYTE0_32(baud);
345 rsp_buf[1] = BYTE1_32(baud);
346 rsp_buf[2] = BYTE2_32(baud);
347 rsp_buf[3] = BYTE3_32(baud);
348 rsp_buf[4] = 0; // One stop bit
349 rsp_buf[5] = 0; // No parity
350 rsp_buf[6] = 8; // 8 data bits
351 ep0->buffer = rsp_buf;
352 ep0->buffer_size = 7;
353 result = USBS_CONTROL_RETURN_HANDLED;
357 DBG("*** Unhandled ACM Request: 0x%02X ***\n",
358 (unsigned) req->request);
363 #endif // CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
365 // --------------------------------------------------------------------------
366 // Callback for a USB state change
369 usbs_serial_state_change_handler(usbs_control_endpoint* ep, void* data,
370 usbs_state_change change, int prev_state)
372 #if defined(CYGBLD_IO_USB_SLAVE_SERIAL_DEBUG)
373 const char *STATE_CHG_STR[] = { "Detached", "Attached", "Powered", "Reset",
374 "Addressed", "Configured", "Deconfigured",
375 "Suspended", "Resumed" };
378 DBG("### %d:%s ###\n", change, STATE_CHG_STR[(int) change-1]);
382 // Called from DSR, cond broadcast should be ok without mutex lock
383 usbs_serial_state = usbs_serial_ep0->state;
384 cyg_cond_broadcast(&usbs_serial_state_cond);
386 if (usbs_serial_app_state_change_fn)
387 (*usbs_serial_app_state_change_fn)(ep, data, change, prev_state);
390 // --------------------------------------------------------------------------
391 // Block the calling thread until the USB is configured.
394 usbs_serial_wait_until_configured(void)
396 cyg_mutex_lock(&usbs_serial_lock);
397 while (usbs_serial_state != USBS_STATE_CONFIGURED)
398 cyg_cond_wait(&usbs_serial_state_cond);
399 cyg_mutex_unlock(&usbs_serial_lock);
402 // --------------------------------------------------------------------------
403 // Determine if the device is currently configured.
406 usbs_serial_is_configured(void)
408 return usbs_serial_state == USBS_STATE_CONFIGURED;
411 // --------------------------------------------------------------------------
412 // Callback for when a transmit is complete
415 usbs_serial_tx_complete(void *p, int result)
417 usbs_serial* ser = (usbs_serial*) p;
418 ser->tx_result = result;
419 cyg_semaphore_post(&ser->tx_ready);
422 // --------------------------------------------------------------------------
423 // Callback for when a receive is complete
426 usbs_serial_rx_complete(void *p, int result)
428 usbs_serial* ser = (usbs_serial*) p;
429 ser->rx_result = result;
430 cyg_semaphore_post(&ser->rx_ready);
433 // --------------------------------------------------------------------------
434 // Start an asynchronous transmit of a buffer.
438 usbs_serial_start_tx(usbs_serial* ser, const void* buf, int n)
440 usbs_start_tx_buffer(ser->tx_ep, (unsigned char*) buf, n,
441 usbs_serial_tx_complete, ser);
444 // --------------------------------------------------------------------------
445 // Block the caller until the transmit is complete
448 usbs_serial_wait_for_tx(usbs_serial* ser)
450 cyg_semaphore_wait(&ser->tx_ready);
451 return ser->tx_result;
454 // --------------------------------------------------------------------------
455 // Perform a synchronous transmit and wait for it to complete.
458 usbs_serial_tx(usbs_serial* ser, const void* buf, int n)
460 usbs_serial_start_tx(ser, buf, n);
461 return usbs_serial_wait_for_tx(ser);
464 // --------------------------------------------------------------------------
465 // Start an asynchronous receive of a buffer.
468 usbs_serial_start_rx(usbs_serial* ser, void* buf, int n)
470 usbs_start_rx_buffer(ser->rx_ep, (unsigned char*) buf, n,
471 usbs_serial_rx_complete, ser);
474 // --------------------------------------------------------------------------
475 // Block the caller until the receive is complete
478 usbs_serial_wait_for_rx(usbs_serial* ser)
480 cyg_semaphore_wait(&ser->rx_ready);
481 return ser->rx_result;
484 // --------------------------------------------------------------------------
485 // Perform a synchronous receive and wait for it to complete.
488 usbs_serial_rx(usbs_serial* ser, void* buf, int n)
490 usbs_serial_start_rx(ser, buf, n);
491 return usbs_serial_wait_for_rx(ser);
494 // --------------------------------------------------------------------------
495 // Initialize a serial port structure.
498 usbs_serial_init(usbs_serial* ser, usbs_tx_endpoint* tx_ep,
499 usbs_rx_endpoint* rx_ep)
504 cyg_semaphore_init(&ser->tx_ready, 0);
505 cyg_semaphore_init(&ser->rx_ready, 0);
508 // --------------------------------------------------------------------------
509 // Start the USB subsystem
512 usbs_serial_start(void)
514 usbs_serial_init(&usbs_ser0, TX_EP, RX_EP);
516 cyg_mutex_init(&usbs_serial_lock);
517 cyg_cond_init(&usbs_serial_state_cond, &usbs_serial_lock);
519 // Make the mfg & product names into USB string descriptors
521 usbs_serial_create_str_descriptor(mfg_str_descr,
522 CYGDAT_IO_USB_SLAVE_SERIAL_MFG_STR);
523 usbs_serial_create_str_descriptor(product_str_descr,
524 CYGDAT_IO_USB_SLAVE_SERIAL_PRODUCT_STR);
526 // ----- Set up enumeration & USB callbacks -----
528 usbs_serial_state = usbs_serial_ep0->state;
530 usbs_serial_ep0->enumeration_data = &usb_enum_data;
532 if (usbs_serial_ep0->state_change_fn)
533 usbs_serial_app_state_change_fn = usbs_serial_ep0->state_change_fn;
535 usbs_serial_ep0->state_change_fn = usbs_serial_state_change_handler;
537 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
538 if (!usbs_serial_ep0->class_control_fn)
539 usbs_serial_ep0->class_control_fn = usbs_serial_acm_class_handler;
542 // ----- Start USB subsystem -----
544 usbs_start(usbs_serial_ep0);