implement logf over usb-serial. Needs USB_SERIAL defined in usb_core.h to work, and...
[kugel-rb.git] / firmware / usbstack / usb_serial.c
blob5aca36b59aae3462cf5883fee364b54d3d2ef812
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
10 * Copyright (C) 2007 by Christian Gmeiner
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "string.h"
20 #include "system.h"
21 #include "usb_core.h"
22 #include "usb_drv.h"
23 #include "kernel.h"
25 //#define LOGF_ENABLE
26 #include "logf.h"
28 #ifdef USB_SERIAL
30 #define BUFFER_SIZE 16384 /* No larger, because of controller limitations */
31 static unsigned char _send_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
32 static unsigned char* send_buffer;
34 static unsigned char _receive_buffer[512] __attribute__((aligned(32)));
35 static unsigned char* receive_buffer;
36 static bool busy_sending = false;
37 static int buffer_start;
38 static int buffer_length;
39 static bool active = false;
41 static struct mutex sendlock;
43 /* called by usb_code_init() */
44 void usb_serial_init(void)
46 logf("serial: init");
47 send_buffer = (void*)UNCACHED_ADDR(&_send_buffer);
48 receive_buffer = (void*)UNCACHED_ADDR(&_receive_buffer);
49 busy_sending = false;
50 buffer_start = 0;
51 buffer_length = 0;
52 active = true;
53 mutex_init(&sendlock);
56 void usb_serial_exit(void)
58 active = false;
61 static void sendout(void)
63 if(buffer_start+buffer_length > BUFFER_SIZE)
65 /* Buffer wraps. Only send the first part */
66 usb_drv_send_nonblocking(EP_SERIAL, &send_buffer[buffer_start],(BUFFER_SIZE - buffer_start));
68 else
70 /* Send everything */
71 usb_drv_send_nonblocking(EP_SERIAL, &send_buffer[buffer_start],buffer_length);
73 busy_sending=true;
76 void usb_serial_send(unsigned char *data,int length)
78 if(!active)
79 return;
80 mutex_lock(&sendlock);
81 if(buffer_start+buffer_length > BUFFER_SIZE)
83 /* current buffer wraps, so new data can't */
84 int available_space = BUFFER_SIZE - buffer_length;
85 length=MIN(length,available_space);
86 memcpy(&send_buffer[(buffer_start+buffer_length)%BUFFER_SIZE],data,MIN(length,available_space));
87 buffer_length+=length;
89 else
91 /* current buffer doesn't wrap, so new data might */
92 int available_end_space = (BUFFER_SIZE - (buffer_start + buffer_length));
93 int first_chunk = MIN(length,available_end_space);
94 memcpy(&send_buffer[buffer_start + buffer_length],data,first_chunk);
95 length-=first_chunk;
96 buffer_length+=first_chunk;
97 if(length>0)
99 /* wrap */
100 memcpy(&send_buffer[0],&data[first_chunk],MIN(length,buffer_start));
101 buffer_length+=MIN(length,buffer_start);
104 if(busy_sending)
106 /* Do nothing. The transfer completion handler will pick it up */
108 else
110 sendout();
112 mutex_unlock(&sendlock);
115 /* called by usb_core_transfer_complete() */
116 void usb_serial_transfer_complete(bool in, int status, int length)
118 switch (in) {
119 case false:
120 logf("serial: %s", receive_buffer);
121 /* Data received. TODO : Do something with it ? */
122 usb_drv_recv(EP_SERIAL, receive_buffer, sizeof _receive_buffer);
123 break;
125 case true:
126 mutex_lock(&sendlock);
127 /* Data sent out. Update circular buffer */
128 if(status == 0)
130 buffer_start = (buffer_start + length)%BUFFER_SIZE;
131 buffer_length -= length;
133 busy_sending = false;
135 if(buffer_length!=0)
137 sendout();
139 mutex_unlock(&sendlock);
140 break;
144 /* called by usb_core_control_request() */
145 bool usb_serial_control_request(struct usb_ctrlrequest* req)
147 bool handled = false;
148 switch (req->bRequest) {
149 case USB_REQ_SET_CONFIGURATION:
150 logf("serial: set config");
151 /* prime rx endpoint */
152 usb_drv_recv(EP_SERIAL, receive_buffer, sizeof _receive_buffer);
153 handled = true;
155 /* we come here too after a bus reset, so reset some data */
156 busy_sending = false;
157 sendout();
158 break;
160 default:
161 logf("serial: unhandeld req %d", req->bRequest);
164 return handled;
167 #endif /*USB_SERIAL*/