Cleaner solution to plugin-included core files.
[kugel-rb.git] / firmware / usbstack / usb_serial.c
blob1b143d56eb32c81262217f2f9b158f08c4edef85
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 by Christian Gmeiner
12 * 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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "string.h"
22 #include "system.h"
23 #include "usb_core.h"
24 #include "usb_drv.h"
25 #include "kernel.h"
26 #include "usb_serial.h"
28 //#define LOGF_ENABLE
29 #include "logf.h"
31 #ifdef USB_SERIAL
33 /* serial interface */
34 static struct usb_interface_descriptor __attribute__((aligned(2)))
35 interface_descriptor =
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
49 static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor =
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
59 #define BUFFER_SIZE 512 /* Max 16k because of controller limitations */
60 #if CONFIG_CPU == IMX31L
61 static unsigned char send_buffer[BUFFER_SIZE]
62 USBDEVBSS_ATTR __attribute__((aligned(32)));
63 static unsigned char receive_buffer[32]
64 USBDEVBSS_ATTR __attribute__((aligned(32)));
65 #else
66 static unsigned char send_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
67 static unsigned char receive_buffer[32] __attribute__((aligned(32)));
68 #endif
70 static bool busy_sending = false;
71 static int buffer_start;
72 static int buffer_length;
73 static bool active = false;
75 static int ep_in, ep_out;
76 static int usb_interface;
78 static struct mutex sendlock SHAREDBSS_ATTR;
80 static void sendout(void)
82 if(buffer_start+buffer_length > BUFFER_SIZE)
84 /* Buffer wraps. Only send the first part */
85 usb_drv_send_nonblocking(ep_in, &send_buffer[buffer_start],
86 (BUFFER_SIZE - buffer_start));
88 else
90 /* Send everything */
91 usb_drv_send_nonblocking(ep_in, &send_buffer[buffer_start],
92 buffer_length);
94 busy_sending=true;
97 int usb_serial_request_endpoints(struct usb_class_driver *drv)
99 ep_in = usb_core_request_endpoint(USB_DIR_IN, drv);
101 if (ep_in < 0)
102 return -1;
104 ep_out = usb_core_request_endpoint(USB_DIR_OUT, drv);
106 if (ep_out < 0) {
107 usb_core_release_endpoint(ep_in);
108 return -1;
111 return 0;
114 int usb_serial_set_first_interface(int interface)
116 usb_interface = interface;
117 return interface + 1;
121 int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size)
123 unsigned char *orig_dest = dest;
125 endpoint_descriptor.wMaxPacketSize=max_packet_size;
126 interface_descriptor.bInterfaceNumber=usb_interface;
128 memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor));
129 dest+=sizeof(struct usb_interface_descriptor);
131 endpoint_descriptor.bEndpointAddress = ep_in;
132 memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor));
133 dest+=sizeof(struct usb_endpoint_descriptor);
135 endpoint_descriptor.bEndpointAddress = ep_out;
136 memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor));
137 dest+=sizeof(struct usb_endpoint_descriptor);
139 return (dest - orig_dest);
142 void usb_serial_init_connection(void)
144 /* prime rx endpoint */
145 usb_drv_recv(ep_out, receive_buffer, sizeof receive_buffer);
147 /* we come here too after a bus reset, so reset some data */
148 mutex_lock(&sendlock);
149 busy_sending = false;
150 if(buffer_length>0)
152 sendout();
154 mutex_unlock(&sendlock);
157 /* called by usb_code_init() */
158 void usb_serial_init(void)
160 logf("serial: init");
161 busy_sending = false;
162 buffer_start = 0;
163 buffer_length = 0;
164 active = true;
165 mutex_init(&sendlock);
168 void usb_serial_disconnect(void)
170 active = false;
173 void usb_serial_send(unsigned char *data,int length)
175 if(!active)
176 return;
177 if(length<=0)
178 return;
179 mutex_lock(&sendlock);
180 if(buffer_start+buffer_length > BUFFER_SIZE)
182 /* current buffer wraps, so new data can't */
183 int available_space = BUFFER_SIZE - buffer_length;
184 length=MIN(length,available_space);
185 memcpy(&send_buffer[(buffer_start+buffer_length)%BUFFER_SIZE],
186 data,length);
187 buffer_length+=length;
189 else
191 /* current buffer doesn't wrap, so new data might */
192 int available_end_space = (BUFFER_SIZE - (buffer_start+buffer_length));
193 int first_chunk = MIN(length,available_end_space);
194 memcpy(&send_buffer[buffer_start + buffer_length],data,first_chunk);
195 length-=first_chunk;
196 buffer_length+=first_chunk;
197 if(length>0)
199 /* wrap */
200 memcpy(&send_buffer[0],&data[first_chunk],MIN(length,buffer_start));
201 buffer_length+=MIN(length,buffer_start);
204 if(busy_sending)
206 /* Do nothing. The transfer completion handler will pick it up */
208 else
210 sendout();
212 mutex_unlock(&sendlock);
215 /* called by usb_core_transfer_complete() */
216 void usb_serial_transfer_complete(int ep,int dir, int status, int length)
218 (void)ep;
219 switch (dir) {
220 case USB_DIR_OUT:
221 logf("serial: %s", receive_buffer);
222 /* Data received. TODO : Do something with it ? */
223 usb_drv_recv(ep_out, receive_buffer, sizeof receive_buffer);
224 break;
226 case USB_DIR_IN:
227 mutex_lock(&sendlock);
228 /* Data sent out. Update circular buffer */
229 if(status == 0)
231 buffer_start = (buffer_start + length)%BUFFER_SIZE;
232 buffer_length -= length;
234 busy_sending = false;
236 if(buffer_length>0)
238 sendout();
240 mutex_unlock(&sendlock);
241 break;
245 /* called by usb_core_control_request() */
246 bool usb_serial_control_request(struct usb_ctrlrequest* req)
248 bool handled = false;
249 switch (req->bRequest) {
250 default:
251 logf("serial: unhandeld req %d", req->bRequest);
253 return handled;
256 #endif /*USB_SERIAL*/