]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/usb/serial/slave/v2_0/src/usbs_serial.c
Initial revision
[karo-tx-redboot.git] / packages / io / usb / serial / slave / v2_0 / src / usbs_serial.c
1 //==========================================================================
2 //
3 //      usbs_serial.c
4 //
5 //      Support for slave-side USB serial devices.
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 //
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.
15 //
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
19 // for more details.
20 //
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.
24 //
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.
31 //
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.
34 //
35 // -------------------------------------------
36 //####ECOSGPLCOPYRIGHTEND####
37 //==========================================================================
38 //#####DESCRIPTIONBEGIN####
39 //
40 // Author(s):    Frank M. Pagliughi (fmp), SoRo Systems, Inc.
41 // Date:         2008-06-02
42 //
43 //####DESCRIPTIONEND####
44 //
45 //==========================================================================
46
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>
54
55 #include <pkgconf/io_usb_slave_serial.h>
56 #include <cyg/io/usb/usbs_serial.h>
57 #include <string.h>
58
59 #if defined(CYGBLD_IO_USB_SLAVE_SERIAL_DEBUG)
60 #define DBG diag_printf
61 #else
62 #define DBG (1) ? (void)0 : diag_printf
63 #endif
64
65 #define EP0_MAX_PACKET_SIZE     CYGNUM_IO_USB_SLAVE_SERIAL_EP0_MAX_PACKET_SIZE
66
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;
70
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)
78
79
80 #define VENDOR_ID               CYGNUM_IO_USB_SLAVE_SERIAL_VENDOR_ID
81 #define PRODUCT_ID              CYGNUM_IO_USB_SLAVE_SERIAL_PRODUCT_ID
82
83 #define USB_MAX_STR_LEN         256
84
85 #define LO_BYTE_16(word16)      ((cyg_uint8) ((word16) & 0xFF))
86 #define HI_BYTE_16(word16)      ((cyg_uint8) (((word16) >> 8) & 0xFF))
87
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))
92
93
94 #define MFG_STR_INDEX           '\x01'
95 #define PRODUCT_STR_INDEX       '\x02'
96
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))
101
102
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
108 #else
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
113 #endif
114
115 // ----- Configuration Descriptor -----
116
117 static const usb_configuration_descriptor usb_configuration = {
118     length:             sizeof(usb_configuration_descriptor),
119     type:               USB_CONFIGURATION_DESCRIPTOR_TYPE,
120     total_length_lo:    
121         USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(USBS_SERIAL_NUM_IFACE, 
122                                                      USBS_SERIAL_NUM_ENDP),
123     total_length_hi:    
124         USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(USBS_SERIAL_NUM_IFACE, 
125                                                      USBS_SERIAL_NUM_ENDP),
126     number_interfaces:  USBS_SERIAL_NUM_IFACE,
127     configuration_id:   1,
128     configuration_str:  0,
129     attributes:         (USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED |
130                          USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED),
131     max_power:          50
132 };
133
134 // ----- Interface Descriptor -----
135
136 static const usb_interface_descriptor usb_interface[] = {
137
138 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
139     {
140         length:             sizeof(usb_interface_descriptor),
141         type:               USB_INTERFACE_DESCRIPTOR_TYPE,
142         interface_id:       0,
143         alternate_setting:  0,
144         number_endpoints:   1,
145         interface_class:    0x02,   // Comm class
146         interface_subclass: 0x02,
147         interface_protocol: 0x01,
148         interface_str:      0x00
149     },
150     {
151         length:             sizeof(usb_interface_descriptor),
152         type:               USB_INTERFACE_DESCRIPTOR_TYPE,
153         interface_id:       1,
154         alternate_setting:  0,
155         number_endpoints:   2,
156         interface_class:    USBS_SERIAL_DATA_IFACE_CLASS,
157         interface_subclass: 0x00,
158         interface_protocol: 0x00,
159         interface_str:      0x00
160     }
161 #else
162     {
163         length:             sizeof(usb_interface_descriptor),
164         type:               USB_INTERFACE_DESCRIPTOR_TYPE,
165         interface_id:       0,
166         alternate_setting:  0,
167         number_endpoints:   2,
168         interface_class:    USBS_SERIAL_DATA_IFACE_CLASS,
169         interface_subclass: 0x00,
170         interface_protocol: 0x00,
171         interface_str:      0x00
172     }
173 #endif
174 };
175
176 // ----- Endpoint Descriptors -----
177
178 static const usb_endpoint_descriptor usb_endpoints[] =
179
180 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
181     // Interrupt in endpoint
182     {
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,
187         0x40,
188         0,
189         255
190     },
191 #endif
192
193     // Tx (Bulk IN) Endpoint Descriptor
194     {
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,
199         0x40,
200         0,
201         0
202     },
203
204     // Rx (Bulk OUT) Endpoint Descriptor
205     {
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,
210         0x40,
211         0,
212         0
213     }
214 };
215
216 // ----- String Descriptors -----
217
218 static char mfg_str_descr[USB_MAX_STR_LEN],
219             product_str_descr[USB_MAX_STR_LEN];
220
221
222 static const char* usb_strings[] = {
223     "\x04\x03\x09\x04",
224     mfg_str_descr,
225     product_str_descr
226 };
227
228 // ----- Enumeration Data w/ Device Descriptor -----
229
230 static usbs_enumeration_data usb_enum_data = {
231     {
232         length:                 sizeof(usb_device_descriptor),
233         type:                   USB_DEVICE_DESCRIPTOR_TYPE,
234         usb_spec_lo:            0x00, 
235         usb_spec_hi:            0x02,
236         device_class:           USBS_SERIAL_DEVICE_CLASS,
237         device_subclass:        0,
238         device_protocol:        0,
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),
244         device_lo:              0x00,
245         device_hi:              0x00,
246         manufacturer_str:       MFG_STR_INDEX,
247         product_str:            PRODUCT_STR_INDEX,
248         serial_number_str:      0,
249         number_configurations:  1
250     },
251
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
259 };
260
261 // --------------------------------------------------------------------------
262 // USBS Serial Data
263 // --------------------------------------------------------------------------
264
265 usbs_control_endpoint* usbs_serial_ep0 = EP0;
266
267 // Lock for the state.
268 cyg_mutex_t usbs_serial_lock;   
269
270 // Condition variable for state changes
271 cyg_cond_t  usbs_serial_state_cond;
272
273 int usbs_serial_state;
274
275 usbs_serial usbs_ser0 = {
276     tx_ep:      TX_EP,
277     rx_ep:      RX_EP,
278     tx_result:  0,    
279     rx_result:  0,    
280 };
281
282 static void (*usbs_serial_app_state_change_fn)(struct usbs_control_endpoint*, 
283                                                void*, usbs_state_change, int) 
284 = 0;
285
286 // --------------------------------------------------------------------------
287 // Create a USB String Descriptor from a C string.
288
289 void
290 usbs_serial_create_str_descriptor(char descr[], const char *str)
291 {
292     int i, n = strlen(str);
293
294     if (n > (USB_MAX_STR_LEN/2 - 2))
295         n = USB_MAX_STR_LEN/2 - 2;
296
297     descr[0] = (cyg_uint8) (2*n + 2);
298     descr[1] = USB_DEVREQ_DESCRIPTOR_TYPE_STRING;
299
300     for (i=0; i<n; i++) {
301         descr[i*2+2] = str[i];
302         descr[i*2+3] = '\x00';
303     }
304 }
305
306 // --------------------------------------------------------------------------
307 // ACM Class Handler
308 //
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.
318 // 
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
322
323 #ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
324
325 static usbs_control_return 
326 usbs_serial_acm_class_handler(usbs_control_endpoint* ep0, void* data)
327 {
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.
332
333   DBG("USB Serial ACM Class Handler: ");
334   
335   switch (req->request) {
336     
337     case USBS_SERIAL_SET_LINE_CODING :
338       DBG("ACM Request: Set Line Coding\n");
339       result = USBS_CONTROL_RETURN_HANDLED;
340       break;
341       
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;
354       break;
355       
356     default :
357       DBG("*** Unhandled ACM Request: 0x%02X ***\n",
358           (unsigned) req->request);
359   }
360   
361   return result;
362 }
363 #endif      // CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
364
365 // --------------------------------------------------------------------------
366 // Callback for a USB state change
367
368 void
369 usbs_serial_state_change_handler(usbs_control_endpoint* ep, void* data,
370                                  usbs_state_change change, int prev_state)
371 {
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" };
376   
377   if (change > 0) {
378     DBG("### %d:%s ###\n", change, STATE_CHG_STR[(int) change-1]);
379   }
380 #endif
381   
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);
385   
386   if (usbs_serial_app_state_change_fn)
387     (*usbs_serial_app_state_change_fn)(ep, data, change, prev_state);
388 }
389
390 // --------------------------------------------------------------------------
391 // Block the calling thread until the USB is configured.
392  
393 void
394 usbs_serial_wait_until_configured(void)
395 {
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);
400 }
401
402 // --------------------------------------------------------------------------
403 // Determine if the device is currently configured.
404
405 cyg_bool
406 usbs_serial_is_configured(void)
407 {
408   return usbs_serial_state == USBS_STATE_CONFIGURED;
409 }
410
411 // --------------------------------------------------------------------------
412 // Callback for when a transmit is complete
413
414 static void 
415 usbs_serial_tx_complete(void *p, int result)
416 {
417   usbs_serial* ser = (usbs_serial*) p;
418   ser->tx_result = result;
419   cyg_semaphore_post(&ser->tx_ready);
420 }
421
422 // --------------------------------------------------------------------------
423 // Callback for when a receive is complete
424
425 static void 
426 usbs_serial_rx_complete(void *p, int result)
427 {
428   usbs_serial* ser = (usbs_serial*) p;
429   ser->rx_result = result;
430   cyg_semaphore_post(&ser->rx_ready);
431 }
432
433 // --------------------------------------------------------------------------
434 // Start an asynchronous transmit of a buffer.
435 // 
436  
437 void
438 usbs_serial_start_tx(usbs_serial* ser, const void* buf, int n)
439 {
440   usbs_start_tx_buffer(ser->tx_ep, (unsigned char*) buf, n,
441                        usbs_serial_tx_complete, ser);
442 }
443
444 // --------------------------------------------------------------------------
445 // Block the caller until the transmit is complete
446
447 int
448 usbs_serial_wait_for_tx(usbs_serial* ser)
449 {
450   cyg_semaphore_wait(&ser->tx_ready);
451   return ser->tx_result;
452 }
453
454 // --------------------------------------------------------------------------
455 // Perform a synchronous transmit and wait for it to complete.
456
457 int
458 usbs_serial_tx(usbs_serial* ser, const void* buf, int n)
459 {
460   usbs_serial_start_tx(ser, buf, n);
461   return usbs_serial_wait_for_tx(ser);
462 }
463
464 // --------------------------------------------------------------------------
465 // Start an asynchronous receive of a buffer.
466
467 void
468 usbs_serial_start_rx(usbs_serial* ser, void* buf, int n)
469 {
470   usbs_start_rx_buffer(ser->rx_ep, (unsigned char*) buf, n,
471                        usbs_serial_rx_complete, ser);
472 }
473
474 // --------------------------------------------------------------------------
475 // Block the caller until the receive is complete
476
477 int
478 usbs_serial_wait_for_rx(usbs_serial* ser)
479 {
480   cyg_semaphore_wait(&ser->rx_ready);
481   return ser->rx_result;
482 }
483
484 // --------------------------------------------------------------------------
485 // Perform a synchronous receive and wait for it to complete.
486
487 int
488 usbs_serial_rx(usbs_serial* ser, void* buf, int n)
489 {
490   usbs_serial_start_rx(ser, buf, n);
491   return usbs_serial_wait_for_rx(ser);
492 }
493
494 // --------------------------------------------------------------------------
495 // Initialize a serial port structure.
496
497 void
498 usbs_serial_init(usbs_serial* ser, usbs_tx_endpoint* tx_ep, 
499                  usbs_rx_endpoint* rx_ep)
500 {
501   ser->tx_ep = tx_ep;
502   ser->rx_ep = rx_ep;
503   
504   cyg_semaphore_init(&ser->tx_ready, 0);
505   cyg_semaphore_init(&ser->rx_ready, 0);
506 }
507
508 // --------------------------------------------------------------------------
509 // Start the USB subsystem
510
511 void
512 usbs_serial_start(void)
513 {
514   usbs_serial_init(&usbs_ser0, TX_EP, RX_EP);
515   
516   cyg_mutex_init(&usbs_serial_lock);
517   cyg_cond_init(&usbs_serial_state_cond, &usbs_serial_lock);
518   
519   // Make the mfg & product names into USB string descriptors
520   
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);
525   
526   // ----- Set up enumeration & USB callbacks -----
527   
528   usbs_serial_state = usbs_serial_ep0->state;
529   
530   usbs_serial_ep0->enumeration_data   = &usb_enum_data;
531   
532   if (usbs_serial_ep0->state_change_fn)
533     usbs_serial_app_state_change_fn = usbs_serial_ep0->state_change_fn;
534   
535   usbs_serial_ep0->state_change_fn = usbs_serial_state_change_handler;
536   
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;
540 #endif
541   
542   // ----- Start USB subsystem -----
543   
544   usbs_start(usbs_serial_ep0);
545 }