blob: 8d6ce67823ccac14a355bce28a1dd7af01f723af [file] [log] [blame]
Christian Gmeiner94be71e2007-11-30 00:13:00 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
Michael Sevakis94f7d0f2008-04-18 16:42:50 +00008 * $Id$
Christian Gmeiner94be71e2007-11-30 00:13:00 +00009 *
10 * Copyright (C) 2007 by Christian Gmeiner
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Christian Gmeiner94be71e2007-11-30 00:13:00 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Frank Gevaerts776d0152008-03-02 20:45:33 +000021#include "string.h"
Christian Gmeiner94be71e2007-11-30 00:13:00 +000022#include "system.h"
23#include "usb_core.h"
24#include "usb_drv.h"
Frank Gevaerts776d0152008-03-02 20:45:33 +000025#include "kernel.h"
Bertrik Sikkenba39a5c2008-05-03 07:10:21 +000026#include "usb_serial.h"
Christian Gmeiner94be71e2007-11-30 00:13:00 +000027
28//#define LOGF_ENABLE
29#include "logf.h"
30
Frank Gevaerts07427592008-02-20 22:54:26 +000031#ifdef USB_SERIAL
32
Frank Gevaertsf0b4a322008-03-06 21:25:09 +000033/* serial interface */
Frank Gevaertsbec6aa32008-04-26 19:02:16 +000034static struct usb_interface_descriptor __attribute__((aligned(2)))
Frank Gevaertsf0b4a322008-03-06 21:25:09 +000035 interface_descriptor =
36{
37 .bLength = sizeof(struct usb_interface_descriptor),
38 .bDescriptorType = USB_DT_INTERFACE,
39 .bInterfaceNumber = 0,
40 .bAlternateSetting = 0,
41 .bNumEndpoints = 2,
42 .bInterfaceClass = USB_CLASS_CDC_DATA,
43 .bInterfaceSubClass = 0,
44 .bInterfaceProtocol = 0,
45 .iInterface = 0
46};
47
Frank Gevaertsbec6aa32008-04-26 19:02:16 +000048
49static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor =
Frank Gevaertsf0b4a322008-03-06 21:25:09 +000050{
51 .bLength = sizeof(struct usb_endpoint_descriptor),
52 .bDescriptorType = USB_DT_ENDPOINT,
53 .bEndpointAddress = 0,
54 .bmAttributes = USB_ENDPOINT_XFER_BULK,
55 .wMaxPacketSize = 0,
56 .bInterval = 0
57};
58
Frank Gevaerts8abe9cf2008-03-02 22:12:51 +000059#define BUFFER_SIZE 512 /* Max 16k because of controller limitations */
Frank Gevaerts02bfba62008-04-20 16:51:09 +000060#if CONFIG_CPU == IMX31L
Michael Sevakis94f7d0f2008-04-18 16:42:50 +000061static unsigned char send_buffer[BUFFER_SIZE]
62 USBDEVBSS_ATTR __attribute__((aligned(32)));
Frank Gevaerts02bfba62008-04-20 16:51:09 +000063static unsigned char receive_buffer[32]
Michael Sevakis94f7d0f2008-04-18 16:42:50 +000064 USBDEVBSS_ATTR __attribute__((aligned(32)));
Frank Gevaerts02bfba62008-04-20 16:51:09 +000065#else
66static unsigned char send_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
67static unsigned char receive_buffer[32] __attribute__((aligned(32)));
68#endif
69
Frank Gevaerts776d0152008-03-02 20:45:33 +000070static bool busy_sending = false;
71static int buffer_start;
72static int buffer_length;
73static bool active = false;
74
Frank Gevaertsf0b4a322008-03-06 21:25:09 +000075static int usb_endpoint;
76static int usb_interface;
77
Michael Sevakis94f7d0f2008-04-18 16:42:50 +000078static struct mutex sendlock SHAREDBSS_ATTR;
Christian Gmeiner94be71e2007-11-30 00:13:00 +000079
Frank Gevaertsf0b4a322008-03-06 21:25:09 +000080static void sendout(void)
81{
82 if(buffer_start+buffer_length > BUFFER_SIZE)
83 {
84 /* Buffer wraps. Only send the first part */
85 usb_drv_send_nonblocking(usb_endpoint, &send_buffer[buffer_start],
86 (BUFFER_SIZE - buffer_start));
87 }
88 else
89 {
90 /* Send everything */
91 usb_drv_send_nonblocking(usb_endpoint, &send_buffer[buffer_start],
92 buffer_length);
93 }
94 busy_sending=true;
95}
96
Frank Gevaertsbec6aa32008-04-26 19:02:16 +000097int usb_serial_set_first_endpoint(int endpoint)
Frank Gevaertsf0b4a322008-03-06 21:25:09 +000098{
Frank Gevaertsbec6aa32008-04-26 19:02:16 +000099 usb_endpoint = endpoint;
100 return endpoint + 1;
101}
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000102
Frank Gevaertsbec6aa32008-04-26 19:02:16 +0000103int usb_serial_set_first_interface(int interface)
104{
105 usb_interface = interface;
106 return interface + 1;
107}
108
109
110int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size)
111{
112 unsigned char *orig_dest = dest;
113
114 endpoint_descriptor.wMaxPacketSize=max_packet_size;
115 interface_descriptor.bInterfaceNumber=usb_interface;
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000116
117 memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor));
118 dest+=sizeof(struct usb_interface_descriptor);
119
Frank Gevaertsee8ebc92008-05-06 20:48:50 +0000120 endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_IN;
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000121 memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor));
122 dest+=sizeof(struct usb_endpoint_descriptor);
123
Frank Gevaertsee8ebc92008-05-06 20:48:50 +0000124 endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_OUT;
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000125 memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor));
Frank Gevaertsbec6aa32008-04-26 19:02:16 +0000126 dest+=sizeof(struct usb_endpoint_descriptor);
127
128 return (dest - orig_dest);
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000129}
130
Frank Gevaertsbec6aa32008-04-26 19:02:16 +0000131void usb_serial_init_connection(void)
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000132{
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000133 /* prime rx endpoint */
Michael Sevakis94f7d0f2008-04-18 16:42:50 +0000134 usb_drv_recv(usb_endpoint, receive_buffer, sizeof receive_buffer);
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000135
136 /* we come here too after a bus reset, so reset some data */
137 mutex_lock(&sendlock);
138 busy_sending = false;
139 if(buffer_length>0)
140 {
141 sendout();
142 }
143 mutex_unlock(&sendlock);
144}
145
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000146/* called by usb_code_init() */
147void usb_serial_init(void)
148{
149 logf("serial: init");
Frank Gevaerts776d0152008-03-02 20:45:33 +0000150 busy_sending = false;
151 buffer_start = 0;
152 buffer_length = 0;
153 active = true;
154 mutex_init(&sendlock);
155}
156
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000157void usb_serial_disconnect(void)
Frank Gevaerts776d0152008-03-02 20:45:33 +0000158{
159 active = false;
160}
161
Frank Gevaerts776d0152008-03-02 20:45:33 +0000162void usb_serial_send(unsigned char *data,int length)
163{
164 if(!active)
165 return;
Frank Gevaerts0b4299a2008-03-02 23:34:30 +0000166 if(length<=0)
167 return;
Frank Gevaerts776d0152008-03-02 20:45:33 +0000168 mutex_lock(&sendlock);
169 if(buffer_start+buffer_length > BUFFER_SIZE)
170 {
171 /* current buffer wraps, so new data can't */
172 int available_space = BUFFER_SIZE - buffer_length;
173 length=MIN(length,available_space);
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000174 memcpy(&send_buffer[(buffer_start+buffer_length)%BUFFER_SIZE],
175 data,length);
Frank Gevaerts776d0152008-03-02 20:45:33 +0000176 buffer_length+=length;
177 }
178 else
179 {
180 /* current buffer doesn't wrap, so new data might */
Frank Gevaertsf0b4a322008-03-06 21:25:09 +0000181 int available_end_space = (BUFFER_SIZE - (buffer_start+buffer_length));
Frank Gevaerts776d0152008-03-02 20:45:33 +0000182 int first_chunk = MIN(length,available_end_space);
183 memcpy(&send_buffer[buffer_start + buffer_length],data,first_chunk);
184 length-=first_chunk;
185 buffer_length+=first_chunk;
186 if(length>0)
187 {
188 /* wrap */
189 memcpy(&send_buffer[0],&data[first_chunk],MIN(length,buffer_start));
190 buffer_length+=MIN(length,buffer_start);
191 }
192 }
193 if(busy_sending)
194 {
195 /* Do nothing. The transfer completion handler will pick it up */
196 }
197 else
198 {
199 sendout();
200 }
201 mutex_unlock(&sendlock);
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000202}
203
204/* called by usb_core_transfer_complete() */
Frank Gevaertsbec6aa32008-04-26 19:02:16 +0000205void usb_serial_transfer_complete(int ep,bool in, int status, int length)
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000206{
Frank Gevaertsbec6aa32008-04-26 19:02:16 +0000207 (void)ep;
Frank Gevaerts07427592008-02-20 22:54:26 +0000208 switch (in) {
209 case false:
Frank Gevaerts776d0152008-03-02 20:45:33 +0000210 logf("serial: %s", receive_buffer);
211 /* Data received. TODO : Do something with it ? */
Michael Sevakis94f7d0f2008-04-18 16:42:50 +0000212 usb_drv_recv(usb_endpoint, receive_buffer, sizeof receive_buffer);
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000213 break;
214
Frank Gevaerts07427592008-02-20 22:54:26 +0000215 case true:
Frank Gevaerts776d0152008-03-02 20:45:33 +0000216 mutex_lock(&sendlock);
217 /* Data sent out. Update circular buffer */
218 if(status == 0)
219 {
220 buffer_start = (buffer_start + length)%BUFFER_SIZE;
221 buffer_length -= length;
222 }
223 busy_sending = false;
224
Frank Gevaerts0b4299a2008-03-02 23:34:30 +0000225 if(buffer_length>0)
Frank Gevaerts776d0152008-03-02 20:45:33 +0000226 {
227 sendout();
228 }
229 mutex_unlock(&sendlock);
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000230 break;
231 }
232}
233
234/* called by usb_core_control_request() */
235bool usb_serial_control_request(struct usb_ctrlrequest* req)
236{
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000237 bool handled = false;
238 switch (req->bRequest) {
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000239 default:
240 logf("serial: unhandeld req %d", req->bRequest);
241 }
Christian Gmeiner94be71e2007-11-30 00:13:00 +0000242 return handled;
243}
Frank Gevaerts07427592008-02-20 22:54:26 +0000244
245#endif /*USB_SERIAL*/