]>
Commit | Line | Data |
---|---|---|
232c150a WD |
1 | /* |
2 | * (C) Copyright 2003 | |
3 | * Gerry Hamel, [email protected], Texas Instruments | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | * | |
19 | */ | |
20 | ||
21 | #include <common.h> | |
22 | ||
23 | #ifdef CONFIG_USB_TTY | |
24 | ||
25 | #include <circbuf.h> | |
26 | #include <devices.h> | |
27 | #include "usbtty.h" | |
28 | ||
29 | #if 0 | |
30 | #define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) | |
31 | #else | |
32 | #define TTYDBG(fmt,args...) do{}while(0) | |
33 | #endif | |
34 | ||
35 | #if 0 | |
36 | #define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) | |
37 | #else | |
38 | #define TTYERR(fmt,args...) do{}while(0) | |
39 | #endif | |
40 | ||
41 | /* | |
42 | * Buffers to hold input and output data | |
43 | */ | |
44 | #define USBTTY_BUFFER_SIZE 256 | |
45 | static circbuf_t usbtty_input; | |
46 | static circbuf_t usbtty_output; | |
47 | ||
48 | ||
49 | /* | |
50 | * Instance variables | |
51 | */ | |
52 | static device_t usbttydev; | |
53 | static struct usb_device_instance device_instance[1]; | |
54 | static struct usb_bus_instance bus_instance[1]; | |
55 | static struct usb_configuration_instance config_instance[NUM_CONFIGS]; | |
56 | static struct usb_interface_instance interface_instance[NUM_INTERFACES]; | |
57 | static struct usb_alternate_instance alternate_instance[NUM_INTERFACES]; | |
58 | static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */ | |
59 | ||
60 | /* | |
61 | * Static allocation of urbs | |
62 | */ | |
63 | #define RECV_ENDPOINT 1 | |
64 | #define TX_ENDPOINT 2 | |
65 | ||
66 | /* | |
67 | * Global flag | |
68 | */ | |
69 | int usbtty_configured_flag = 0; | |
70 | ||
71 | ||
6629d2f2 WD |
72 | /* |
73 | * Serial number | |
74 | */ | |
75 | static char serial_number[16]; | |
76 | ||
232c150a WD |
77 | /* |
78 | * Descriptors | |
79 | */ | |
80 | static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4}; | |
81 | static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)]; | |
82 | static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)]; | |
6629d2f2 | 83 | static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)]; |
232c150a WD |
84 | static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)]; |
85 | static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)]; | |
86 | ||
87 | static struct usb_string_descriptor *usbtty_string_table[] = { | |
88 | (struct usb_string_descriptor*)wstrLang, | |
89 | (struct usb_string_descriptor*)wstrManufacturer, | |
90 | (struct usb_string_descriptor*)wstrProduct, | |
91 | (struct usb_string_descriptor*)wstrSerial, | |
92 | (struct usb_string_descriptor*)wstrConfiguration, | |
93 | (struct usb_string_descriptor*)wstrInterface | |
94 | }; | |
95 | extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */ | |
96 | ||
97 | static struct usb_device_descriptor device_descriptor = { | |
98 | bLength: sizeof(struct usb_device_descriptor), | |
99 | bDescriptorType: USB_DT_DEVICE, | |
100 | bcdUSB: USB_BCD_VERSION, | |
101 | bDeviceClass: USBTTY_DEVICE_CLASS, | |
102 | bDeviceSubClass: USBTTY_DEVICE_SUBCLASS, | |
103 | bDeviceProtocol: USBTTY_DEVICE_PROTOCOL, | |
104 | bMaxPacketSize0: EP0_MAX_PACKET_SIZE, | |
105 | idVendor: CONFIG_USBD_VENDORID, | |
106 | idProduct: CONFIG_USBD_PRODUCTID, | |
107 | bcdDevice: USBTTY_BCD_DEVICE, | |
108 | iManufacturer: STR_MANUFACTURER, | |
109 | iProduct: STR_PRODUCT, | |
110 | iSerialNumber: STR_SERIAL, | |
111 | bNumConfigurations: NUM_CONFIGS | |
112 | }; | |
113 | static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = { | |
114 | { | |
115 | bLength: sizeof(struct usb_configuration_descriptor), | |
116 | bDescriptorType: USB_DT_CONFIG, | |
117 | wTotalLength: (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) + | |
118 | (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) + | |
119 | (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS), | |
120 | bNumInterfaces: NUM_INTERFACES, | |
121 | bConfigurationValue: 1, | |
122 | iConfiguration: STR_CONFIG, | |
123 | bmAttributes: BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED, | |
124 | bMaxPower: USBTTY_MAXPOWER | |
125 | }, | |
126 | }; | |
127 | static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = { | |
128 | { | |
129 | bLength: sizeof(struct usb_interface_descriptor), | |
130 | bDescriptorType: USB_DT_INTERFACE, | |
131 | bInterfaceNumber: 0, | |
132 | bAlternateSetting: 0, | |
133 | bNumEndpoints: NUM_ENDPOINTS, | |
134 | bInterfaceClass: USBTTY_INTERFACE_CLASS, | |
135 | bInterfaceSubClass: USBTTY_INTERFACE_SUBCLASS, | |
136 | bInterfaceProtocol: USBTTY_INTERFACE_PROTOCOL, | |
137 | iInterface: STR_INTERFACE | |
138 | }, | |
139 | }; | |
140 | static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = { | |
141 | { | |
142 | bLength: sizeof(struct usb_endpoint_descriptor), | |
143 | bDescriptorType: USB_DT_ENDPOINT, | |
144 | bEndpointAddress: CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT, | |
145 | bmAttributes: USB_ENDPOINT_XFER_BULK, | |
146 | wMaxPacketSize: CONFIG_USBD_SERIAL_OUT_PKTSIZE, | |
147 | bInterval: 0 | |
148 | }, | |
149 | { | |
150 | bLength: sizeof(struct usb_endpoint_descriptor), | |
151 | bDescriptorType: USB_DT_ENDPOINT, | |
152 | bEndpointAddress: CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN, | |
153 | bmAttributes: USB_ENDPOINT_XFER_BULK, | |
154 | wMaxPacketSize: CONFIG_USBD_SERIAL_IN_PKTSIZE, | |
155 | bInterval: 0 | |
156 | }, | |
157 | { | |
158 | bLength: sizeof(struct usb_endpoint_descriptor), | |
159 | bDescriptorType: USB_DT_ENDPOINT, | |
160 | bEndpointAddress: CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN, | |
161 | bmAttributes: USB_ENDPOINT_XFER_INT, | |
162 | wMaxPacketSize: CONFIG_USBD_SERIAL_INT_PKTSIZE, | |
163 | bInterval: 0 | |
164 | }, | |
165 | }; | |
166 | static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = { | |
167 | &(ep_descriptors[0]), | |
168 | &(ep_descriptors[1]), | |
169 | &(ep_descriptors[2]), | |
170 | }; | |
171 | ||
172 | /* utility function for converting char* to wide string used by USB */ | |
173 | static void str2wide (char *str, u16 * wide) | |
174 | { | |
175 | int i; | |
176 | ||
177 | for (i = 0; i < strlen (str) && str[i]; i++) | |
178 | wide[i] = (u16) str[i]; | |
179 | } | |
180 | ||
181 | /* | |
182 | * Prototypes | |
183 | */ | |
184 | static void usbtty_init_strings (void); | |
185 | static void usbtty_init_instances (void); | |
186 | static void usbtty_init_endpoints (void); | |
187 | ||
188 | static void usbtty_event_handler (struct usb_device_instance *device, | |
189 | usb_device_event_t event, int data); | |
190 | static int usbtty_configured (void); | |
191 | ||
192 | static int write_buffer (circbuf_t * buf); | |
193 | static int fill_buffer (circbuf_t * buf); | |
194 | ||
195 | void usbtty_poll (void); | |
196 | static void pretend_interrupts (void); | |
197 | ||
198 | ||
199 | /* | |
200 | * Test whether a character is in the RX buffer | |
201 | */ | |
202 | int usbtty_tstc (void) | |
203 | { | |
204 | usbtty_poll (); | |
205 | return (usbtty_input.size > 0); | |
206 | } | |
207 | ||
208 | /* | |
209 | * Read a single byte from the usb client port. Returns 1 on success, 0 | |
210 | * otherwise. When the function is succesfull, the character read is | |
211 | * written into its argument c. | |
212 | */ | |
213 | int usbtty_getc (void) | |
214 | { | |
215 | char c; | |
216 | ||
217 | while (usbtty_input.size <= 0) { | |
218 | usbtty_poll (); | |
219 | } | |
220 | ||
221 | buf_pop (&usbtty_input, &c, 1); | |
222 | return c; | |
223 | } | |
224 | ||
225 | /* | |
226 | * Output a single byte to the usb client port. | |
227 | */ | |
228 | void usbtty_putc (const char c) | |
229 | { | |
230 | buf_push (&usbtty_output, &c, 1); | |
231 | /* If \n, also do \r */ | |
232 | if (c == '\n') | |
233 | buf_push (&usbtty_output, "\r", 1); | |
234 | ||
235 | /* Poll at end to handle new data... */ | |
236 | if ((usbtty_output.size + 2) >= usbtty_output.totalsize) { | |
237 | usbtty_poll (); | |
238 | } | |
239 | } | |
240 | ||
241 | ||
242 | /* usbtty_puts() helper function for finding the next '\n' in a string */ | |
243 | static int next_nl_pos (const char *s) | |
244 | { | |
245 | int i; | |
246 | ||
247 | for (i = 0; s[i] != '\0'; i++) { | |
248 | if (s[i] == '\n') | |
249 | return i; | |
250 | } | |
251 | return i; | |
252 | } | |
253 | ||
254 | /* | |
255 | * Output a string to the usb client port. | |
256 | */ | |
257 | static void __usbtty_puts (const char *str, int len) | |
258 | { | |
259 | int maxlen = usbtty_output.totalsize; | |
260 | int space, n; | |
261 | ||
262 | /* break str into chunks < buffer size, if needed */ | |
263 | while (len > 0) { | |
264 | space = maxlen - usbtty_output.size; | |
265 | ||
266 | /* Empty buffer here, if needed, to ensure space... */ | |
267 | if (space <= 0) { | |
268 | write_buffer (&usbtty_output); | |
269 | space = maxlen - usbtty_output.size; | |
270 | if (space <= 0) { | |
271 | space = len; /* allow old data to be overwritten. */ | |
272 | } | |
273 | } | |
274 | ||
275 | n = MIN (space, MIN (len, maxlen)); | |
276 | buf_push (&usbtty_output, str, n); | |
277 | ||
278 | str += n; | |
279 | len -= n; | |
280 | } | |
281 | } | |
282 | ||
283 | void usbtty_puts (const char *str) | |
284 | { | |
285 | int n; | |
286 | int len = strlen (str); | |
287 | ||
288 | /* add '\r' for each '\n' */ | |
289 | while (len > 0) { | |
290 | n = next_nl_pos (str); | |
291 | ||
292 | if (str[n] == '\n') { | |
293 | __usbtty_puts (str, n + 1); | |
294 | __usbtty_puts ("\r", 1); | |
295 | str += (n + 1); | |
296 | len -= (n + 1); | |
297 | } else { | |
298 | /* No \n found. All done. */ | |
299 | __usbtty_puts (str, n); | |
300 | break; | |
301 | } | |
302 | } | |
303 | ||
304 | /* Poll at end to handle new data... */ | |
305 | usbtty_poll (); | |
306 | } | |
307 | ||
308 | /* | |
309 | * Initialize the usb client port. | |
310 | * | |
311 | */ | |
312 | int drv_usbtty_init (void) | |
313 | { | |
314 | int rc; | |
6629d2f2 WD |
315 | char * sn; |
316 | int snlen; | |
42dfe7a1 | 317 | |
6629d2f2 WD |
318 | if (!(sn = getenv("serial#"))) { |
319 | sn = "000000000000"; | |
320 | } | |
321 | snlen = strlen(sn); | |
322 | if (snlen > sizeof(serial_number) - 1) { | |
323 | printf ("Warning: serial number %s is too long (%d > %d)\n", | |
324 | sn, snlen, sizeof(serial_number) - 1); | |
325 | snlen = sizeof(serial_number) - 1; | |
326 | } | |
327 | memcpy (serial_number, sn, snlen); | |
328 | serial_number[snlen] = '\0'; | |
232c150a WD |
329 | |
330 | /* prepare buffers... */ | |
331 | buf_init (&usbtty_input, USBTTY_BUFFER_SIZE); | |
332 | buf_init (&usbtty_output, USBTTY_BUFFER_SIZE); | |
333 | ||
334 | /* Now, set up USB controller and infrastructure */ | |
335 | udc_init (); /* Basic USB initialization */ | |
336 | ||
337 | usbtty_init_strings (); | |
338 | usbtty_init_instances (); | |
339 | ||
340 | udc_startup_events (device_instance); /* Enable our device, initialize udc pointers */ | |
341 | udc_connect (); /* Enable pullup for host detection */ | |
342 | ||
343 | usbtty_init_endpoints (); | |
344 | ||
345 | /* Device initialization */ | |
346 | memset (&usbttydev, 0, sizeof (usbttydev)); | |
347 | ||
348 | strcpy (usbttydev.name, "usbtty"); | |
349 | usbttydev.ext = 0; /* No extensions */ | |
350 | usbttydev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT; | |
351 | usbttydev.tstc = usbtty_tstc; /* 'tstc' function */ | |
352 | usbttydev.getc = usbtty_getc; /* 'getc' function */ | |
353 | usbttydev.putc = usbtty_putc; /* 'putc' function */ | |
354 | usbttydev.puts = usbtty_puts; /* 'puts' function */ | |
355 | ||
356 | rc = device_register (&usbttydev); | |
357 | ||
358 | return (rc == 0) ? 1 : rc; | |
359 | } | |
360 | ||
361 | static void usbtty_init_strings (void) | |
362 | { | |
363 | struct usb_string_descriptor *string; | |
364 | ||
365 | string = (struct usb_string_descriptor *) wstrManufacturer; | |
366 | string->bLength = sizeof (wstrManufacturer); | |
367 | string->bDescriptorType = USB_DT_STRING; | |
368 | str2wide (CONFIG_USBD_MANUFACTURER, string->wData); | |
369 | ||
370 | string = (struct usb_string_descriptor *) wstrProduct; | |
371 | string->bLength = sizeof (wstrProduct); | |
372 | string->bDescriptorType = USB_DT_STRING; | |
373 | str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData); | |
374 | ||
375 | string = (struct usb_string_descriptor *) wstrSerial; | |
6629d2f2 | 376 | string->bLength = 2 + 2*strlen(serial_number); |
232c150a | 377 | string->bDescriptorType = USB_DT_STRING; |
6629d2f2 | 378 | str2wide (serial_number, string->wData); |
232c150a WD |
379 | |
380 | string = (struct usb_string_descriptor *) wstrConfiguration; | |
381 | string->bLength = sizeof (wstrConfiguration); | |
382 | string->bDescriptorType = USB_DT_STRING; | |
383 | str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData); | |
384 | ||
385 | string = (struct usb_string_descriptor *) wstrInterface; | |
386 | string->bLength = sizeof (wstrInterface); | |
387 | string->bDescriptorType = USB_DT_STRING; | |
388 | str2wide (CONFIG_USBD_INTERFACE_STR, string->wData); | |
389 | ||
390 | /* Now, initialize the string table for ep0 handling */ | |
391 | usb_strings = usbtty_string_table; | |
392 | } | |
393 | ||
394 | static void usbtty_init_instances (void) | |
395 | { | |
396 | int i; | |
397 | ||
398 | /* initialize device instance */ | |
399 | memset (device_instance, 0, sizeof (struct usb_device_instance)); | |
400 | device_instance->device_state = STATE_INIT; | |
401 | device_instance->device_descriptor = &device_descriptor; | |
402 | device_instance->event = usbtty_event_handler; | |
403 | device_instance->bus = bus_instance; | |
404 | device_instance->configurations = NUM_CONFIGS; | |
405 | device_instance->configuration_instance_array = config_instance; | |
406 | ||
407 | /* initialize bus instance */ | |
408 | memset (bus_instance, 0, sizeof (struct usb_bus_instance)); | |
409 | bus_instance->device = device_instance; | |
410 | bus_instance->endpoint_array = endpoint_instance; | |
411 | bus_instance->max_endpoints = 1; | |
412 | bus_instance->maxpacketsize = 64; | |
6629d2f2 | 413 | bus_instance->serial_number_str = serial_number; |
232c150a WD |
414 | |
415 | /* configuration instance */ | |
416 | memset (config_instance, 0, | |
417 | sizeof (struct usb_configuration_instance)); | |
418 | config_instance->interfaces = NUM_INTERFACES; | |
419 | config_instance->configuration_descriptor = config_descriptors; | |
420 | config_instance->interface_instance_array = interface_instance; | |
421 | ||
422 | /* interface instance */ | |
423 | memset (interface_instance, 0, | |
424 | sizeof (struct usb_interface_instance)); | |
425 | interface_instance->alternates = 1; | |
426 | interface_instance->alternates_instance_array = alternate_instance; | |
427 | ||
428 | /* alternates instance */ | |
429 | memset (alternate_instance, 0, | |
430 | sizeof (struct usb_alternate_instance)); | |
431 | alternate_instance->interface_descriptor = interface_descriptors; | |
432 | alternate_instance->endpoints = NUM_ENDPOINTS; | |
433 | alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs; | |
434 | ||
435 | /* endpoint instances */ | |
436 | memset (&endpoint_instance[0], 0, | |
437 | sizeof (struct usb_endpoint_instance)); | |
438 | endpoint_instance[0].endpoint_address = 0; | |
439 | endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE; | |
440 | endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL; | |
441 | endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE; | |
442 | endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL; | |
443 | udc_setup_ep (device_instance, 0, &endpoint_instance[0]); | |
444 | ||
445 | for (i = 1; i <= NUM_ENDPOINTS; i++) { | |
446 | memset (&endpoint_instance[i], 0, | |
447 | sizeof (struct usb_endpoint_instance)); | |
448 | ||
449 | endpoint_instance[i].endpoint_address = | |
450 | ep_descriptors[i - 1].bEndpointAddress; | |
451 | ||
452 | endpoint_instance[i].rcv_packetSize = | |
453 | ep_descriptors[i - 1].wMaxPacketSize; | |
454 | endpoint_instance[i].rcv_attributes = | |
455 | ep_descriptors[i - 1].bmAttributes; | |
456 | ||
457 | endpoint_instance[i].tx_packetSize = | |
458 | ep_descriptors[i - 1].wMaxPacketSize; | |
459 | endpoint_instance[i].tx_attributes = | |
460 | ep_descriptors[i - 1].bmAttributes; | |
461 | ||
462 | urb_link_init (&endpoint_instance[i].rcv); | |
463 | urb_link_init (&endpoint_instance[i].rdy); | |
464 | urb_link_init (&endpoint_instance[i].tx); | |
465 | urb_link_init (&endpoint_instance[i].done); | |
466 | ||
467 | if (endpoint_instance[i].endpoint_address & USB_DIR_IN) | |
468 | endpoint_instance[i].tx_urb = | |
469 | usbd_alloc_urb (device_instance, | |
470 | &endpoint_instance[i]); | |
471 | else | |
472 | endpoint_instance[i].rcv_urb = | |
473 | usbd_alloc_urb (device_instance, | |
474 | &endpoint_instance[i]); | |
475 | } | |
476 | } | |
477 | ||
478 | static void usbtty_init_endpoints (void) | |
479 | { | |
480 | int i; | |
481 | ||
482 | bus_instance->max_endpoints = NUM_ENDPOINTS + 1; | |
483 | for (i = 0; i <= NUM_ENDPOINTS; i++) { | |
484 | udc_setup_ep (device_instance, i, &endpoint_instance[i]); | |
485 | } | |
486 | } | |
487 | ||
488 | ||
489 | /*********************************************************************************/ | |
490 | ||
491 | static struct urb *next_urb (struct usb_device_instance *device, | |
492 | struct usb_endpoint_instance *endpoint) | |
493 | { | |
494 | struct urb *current_urb = NULL; | |
495 | int space; | |
496 | ||
497 | /* If there's a queue, then we should add to the last urb */ | |
498 | if (!endpoint->tx_queue) { | |
499 | current_urb = endpoint->tx_urb; | |
500 | } else { | |
501 | /* Last urb from tx chain */ | |
502 | current_urb = | |
503 | p2surround (struct urb, link, endpoint->tx.prev); | |
504 | } | |
505 | ||
506 | /* Make sure this one has enough room */ | |
507 | space = current_urb->buffer_length - current_urb->actual_length; | |
508 | if (space > 0) { | |
509 | return current_urb; | |
510 | } else { /* No space here */ | |
511 | /* First look at done list */ | |
512 | current_urb = first_urb_detached (&endpoint->done); | |
513 | if (!current_urb) { | |
514 | current_urb = usbd_alloc_urb (device, endpoint); | |
515 | } | |
516 | ||
517 | urb_append (&endpoint->tx, current_urb); | |
518 | endpoint->tx_queue++; | |
519 | } | |
520 | return current_urb; | |
521 | } | |
522 | ||
523 | static int write_buffer (circbuf_t * buf) | |
524 | { | |
525 | if (!usbtty_configured ()) { | |
526 | return 0; | |
527 | } | |
528 | ||
529 | if (buf->size) { | |
530 | ||
531 | struct usb_endpoint_instance *endpoint = | |
532 | &endpoint_instance[TX_ENDPOINT]; | |
533 | struct urb *current_urb = NULL; | |
534 | char *dest; | |
535 | ||
536 | int space_avail; | |
537 | int popnum, popped; | |
538 | int total = 0; | |
539 | ||
540 | /* Break buffer into urb sized pieces, and link each to the endpoint */ | |
541 | while (buf->size > 0) { | |
542 | current_urb = next_urb (device_instance, endpoint); | |
543 | if (!current_urb) { | |
544 | TTYERR ("current_urb is NULL, buf->size %d\n", | |
545 | buf->size); | |
546 | return total; | |
547 | } | |
548 | ||
549 | dest = current_urb->buffer + | |
550 | current_urb->actual_length; | |
551 | ||
552 | space_avail = | |
553 | current_urb->buffer_length - | |
554 | current_urb->actual_length; | |
555 | popnum = MIN (space_avail, buf->size); | |
556 | if (popnum == 0) | |
557 | break; | |
558 | ||
559 | popped = buf_pop (buf, dest, popnum); | |
560 | if (popped == 0) | |
561 | break; | |
562 | current_urb->actual_length += popped; | |
563 | total += popped; | |
564 | ||
565 | /* If endpoint->last == 0, then transfers have not started on this endpoint */ | |
566 | if (endpoint->last == 0) { | |
567 | udc_endpoint_write (endpoint); | |
568 | } | |
569 | ||
570 | } /* end while */ | |
571 | return total; | |
572 | } /* end if tx_urb */ | |
573 | ||
574 | return 0; | |
575 | } | |
576 | ||
577 | static int fill_buffer (circbuf_t * buf) | |
578 | { | |
579 | struct usb_endpoint_instance *endpoint = | |
580 | &endpoint_instance[RECV_ENDPOINT]; | |
581 | ||
582 | if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { | |
583 | unsigned int nb = endpoint->rcv_urb->actual_length; | |
584 | char *src = (char *) endpoint->rcv_urb->buffer; | |
585 | ||
586 | buf_push (buf, src, nb); | |
587 | endpoint->rcv_urb->actual_length = 0; | |
588 | ||
589 | return nb; | |
590 | } | |
591 | ||
592 | return 0; | |
593 | } | |
594 | ||
595 | static int usbtty_configured (void) | |
596 | { | |
597 | return usbtty_configured_flag; | |
598 | } | |
599 | ||
600 | /*********************************************************************************/ | |
601 | ||
602 | static void usbtty_event_handler (struct usb_device_instance *device, | |
603 | usb_device_event_t event, int data) | |
604 | { | |
605 | switch (event) { | |
606 | case DEVICE_RESET: | |
607 | case DEVICE_BUS_INACTIVE: | |
608 | usbtty_configured_flag = 0; | |
609 | break; | |
610 | case DEVICE_CONFIGURED: | |
611 | usbtty_configured_flag = 1; | |
612 | break; | |
613 | ||
614 | case DEVICE_ADDRESS_ASSIGNED: | |
615 | usbtty_init_endpoints (); | |
616 | ||
617 | default: | |
618 | break; | |
619 | } | |
620 | } | |
621 | ||
622 | /*********************************************************************************/ | |
623 | ||
624 | ||
625 | /* | |
626 | * Since interrupt handling has not yet been implemented, we use this function | |
627 | * to handle polling. This is called by the tstc,getc,putc,puts routines to | |
628 | * update the USB state. | |
629 | */ | |
630 | void usbtty_poll (void) | |
631 | { | |
632 | /* New interrupts? */ | |
633 | pretend_interrupts (); | |
634 | ||
635 | /* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */ | |
636 | if (usbtty_configured ()) { | |
637 | write_buffer (&usbtty_output); | |
638 | } | |
639 | ||
640 | /* New interrupts? */ | |
641 | pretend_interrupts (); | |
642 | ||
643 | /* Check for new data from host.. (do this after checking interrupts to get latest data) */ | |
644 | if (usbtty_configured ()) { | |
645 | fill_buffer (&usbtty_input); | |
646 | } | |
647 | ||
648 | /* New interrupts? */ | |
649 | pretend_interrupts (); | |
650 | } | |
651 | ||
652 | static void pretend_interrupts (void) | |
653 | { | |
654 | /* Loop while we have interrupts. | |
655 | * If we don't do this, the input chain | |
656 | * polling delay is likely to miss | |
657 | * host requests. | |
658 | */ | |
659 | while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) { | |
660 | /* Handle any new IRQs */ | |
661 | omap1510_udc_irq (); | |
662 | omap1510_udc_noniso_irq (); | |
663 | } | |
664 | } | |
665 | #endif |