Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
Michael Sevakis | 94f7d0f | 2008-04-18 16:42:50 +0000 | [diff] [blame] | 8 | * $Id$ |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 9 | * |
| 10 | * Copyright (C) 2007 by Christian Gmeiner |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 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. |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 21 | #include "string.h" |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 22 | #include "system.h" |
| 23 | #include "usb_core.h" |
| 24 | #include "usb_drv.h" |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 25 | #include "kernel.h" |
Bertrik Sikken | ba39a5c | 2008-05-03 07:10:21 +0000 | [diff] [blame] | 26 | #include "usb_serial.h" |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 27 | |
| 28 | //#define LOGF_ENABLE |
| 29 | #include "logf.h" |
| 30 | |
Frank Gevaerts | 0742759 | 2008-02-20 22:54:26 +0000 | [diff] [blame] | 31 | #ifdef USB_SERIAL |
| 32 | |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 33 | /* serial interface */ |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 34 | static struct usb_interface_descriptor __attribute__((aligned(2))) |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 35 | 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 Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 48 | |
| 49 | static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor = |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 50 | { |
| 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 Gevaerts | 8abe9cf | 2008-03-02 22:12:51 +0000 | [diff] [blame] | 59 | #define BUFFER_SIZE 512 /* Max 16k because of controller limitations */ |
Frank Gevaerts | 02bfba6 | 2008-04-20 16:51:09 +0000 | [diff] [blame] | 60 | #if CONFIG_CPU == IMX31L |
Michael Sevakis | 94f7d0f | 2008-04-18 16:42:50 +0000 | [diff] [blame] | 61 | static unsigned char send_buffer[BUFFER_SIZE] |
| 62 | USBDEVBSS_ATTR __attribute__((aligned(32))); |
Frank Gevaerts | 02bfba6 | 2008-04-20 16:51:09 +0000 | [diff] [blame] | 63 | static unsigned char receive_buffer[32] |
Michael Sevakis | 94f7d0f | 2008-04-18 16:42:50 +0000 | [diff] [blame] | 64 | USBDEVBSS_ATTR __attribute__((aligned(32))); |
Frank Gevaerts | 02bfba6 | 2008-04-20 16:51:09 +0000 | [diff] [blame] | 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 |
| 69 | |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 70 | static bool busy_sending = false; |
| 71 | static int buffer_start; |
| 72 | static int buffer_length; |
| 73 | static bool active = false; |
| 74 | |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 75 | static int usb_endpoint; |
| 76 | static int usb_interface; |
| 77 | |
Michael Sevakis | 94f7d0f | 2008-04-18 16:42:50 +0000 | [diff] [blame] | 78 | static struct mutex sendlock SHAREDBSS_ATTR; |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 79 | |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 80 | static 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 Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 97 | int usb_serial_set_first_endpoint(int endpoint) |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 98 | { |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 99 | usb_endpoint = endpoint; |
| 100 | return endpoint + 1; |
| 101 | } |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 102 | |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 103 | int usb_serial_set_first_interface(int interface) |
| 104 | { |
| 105 | usb_interface = interface; |
| 106 | return interface + 1; |
| 107 | } |
| 108 | |
| 109 | |
| 110 | int 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 Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 116 | |
| 117 | memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor)); |
| 118 | dest+=sizeof(struct usb_interface_descriptor); |
| 119 | |
Frank Gevaerts | ee8ebc9 | 2008-05-06 20:48:50 +0000 | [diff] [blame] | 120 | endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_IN; |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 121 | memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor)); |
| 122 | dest+=sizeof(struct usb_endpoint_descriptor); |
| 123 | |
Frank Gevaerts | ee8ebc9 | 2008-05-06 20:48:50 +0000 | [diff] [blame] | 124 | endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_OUT; |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 125 | memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor)); |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 126 | dest+=sizeof(struct usb_endpoint_descriptor); |
| 127 | |
| 128 | return (dest - orig_dest); |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 129 | } |
| 130 | |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 131 | void usb_serial_init_connection(void) |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 132 | { |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 133 | /* prime rx endpoint */ |
Michael Sevakis | 94f7d0f | 2008-04-18 16:42:50 +0000 | [diff] [blame] | 134 | usb_drv_recv(usb_endpoint, receive_buffer, sizeof receive_buffer); |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 135 | |
| 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 Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 146 | /* called by usb_code_init() */ |
| 147 | void usb_serial_init(void) |
| 148 | { |
| 149 | logf("serial: init"); |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 150 | busy_sending = false; |
| 151 | buffer_start = 0; |
| 152 | buffer_length = 0; |
| 153 | active = true; |
| 154 | mutex_init(&sendlock); |
| 155 | } |
| 156 | |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 157 | void usb_serial_disconnect(void) |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 158 | { |
| 159 | active = false; |
| 160 | } |
| 161 | |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 162 | void usb_serial_send(unsigned char *data,int length) |
| 163 | { |
| 164 | if(!active) |
| 165 | return; |
Frank Gevaerts | 0b4299a | 2008-03-02 23:34:30 +0000 | [diff] [blame] | 166 | if(length<=0) |
| 167 | return; |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 168 | 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 Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 174 | memcpy(&send_buffer[(buffer_start+buffer_length)%BUFFER_SIZE], |
| 175 | data,length); |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 176 | buffer_length+=length; |
| 177 | } |
| 178 | else |
| 179 | { |
| 180 | /* current buffer doesn't wrap, so new data might */ |
Frank Gevaerts | f0b4a32 | 2008-03-06 21:25:09 +0000 | [diff] [blame] | 181 | int available_end_space = (BUFFER_SIZE - (buffer_start+buffer_length)); |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 182 | 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 Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | /* called by usb_core_transfer_complete() */ |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 205 | void usb_serial_transfer_complete(int ep,bool in, int status, int length) |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 206 | { |
Frank Gevaerts | bec6aa3 | 2008-04-26 19:02:16 +0000 | [diff] [blame] | 207 | (void)ep; |
Frank Gevaerts | 0742759 | 2008-02-20 22:54:26 +0000 | [diff] [blame] | 208 | switch (in) { |
| 209 | case false: |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 210 | logf("serial: %s", receive_buffer); |
| 211 | /* Data received. TODO : Do something with it ? */ |
Michael Sevakis | 94f7d0f | 2008-04-18 16:42:50 +0000 | [diff] [blame] | 212 | usb_drv_recv(usb_endpoint, receive_buffer, sizeof receive_buffer); |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 213 | break; |
| 214 | |
Frank Gevaerts | 0742759 | 2008-02-20 22:54:26 +0000 | [diff] [blame] | 215 | case true: |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 216 | 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 Gevaerts | 0b4299a | 2008-03-02 23:34:30 +0000 | [diff] [blame] | 225 | if(buffer_length>0) |
Frank Gevaerts | 776d015 | 2008-03-02 20:45:33 +0000 | [diff] [blame] | 226 | { |
| 227 | sendout(); |
| 228 | } |
| 229 | mutex_unlock(&sendlock); |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 230 | break; |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | /* called by usb_core_control_request() */ |
| 235 | bool usb_serial_control_request(struct usb_ctrlrequest* req) |
| 236 | { |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 237 | bool handled = false; |
| 238 | switch (req->bRequest) { |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 239 | default: |
| 240 | logf("serial: unhandeld req %d", req->bRequest); |
| 241 | } |
Christian Gmeiner | 94be71e | 2007-11-30 00:13:00 +0000 | [diff] [blame] | 242 | return handled; |
| 243 | } |
Frank Gevaerts | 0742759 | 2008-02-20 22:54:26 +0000 | [diff] [blame] | 244 | |
| 245 | #endif /*USB_SERIAL*/ |