diff options
Diffstat (limited to 'firmware/usbstack/drivers/device/usb_serial.c')
-rw-r--r-- | firmware/usbstack/drivers/device/usb_serial.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/firmware/usbstack/drivers/device/usb_serial.c b/firmware/usbstack/drivers/device/usb_serial.c new file mode 100644 index 0000000000..fe1e52f25a --- /dev/null +++ b/firmware/usbstack/drivers/device/usb_serial.c | |||
@@ -0,0 +1,300 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Christian Gmeiner | ||
11 | * | ||
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. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "usb_serial.h" | ||
21 | #include <string.h> | ||
22 | |||
23 | static struct usb_dcd_controller_ops* ops; | ||
24 | |||
25 | struct usb_device_driver usb_serial_driver = { | ||
26 | .name = "serial", | ||
27 | .bind = usb_serial_driver_bind, | ||
28 | .unbind = NULL, | ||
29 | .request = usb_serial_driver_request, | ||
30 | .suspend = NULL, | ||
31 | .resume = NULL, | ||
32 | .speed = usb_serial_driver_speed, | ||
33 | }; | ||
34 | |||
35 | /*-------------------------------------------------------------------------*/ | ||
36 | /* usb descriptors */ | ||
37 | |||
38 | /* TODO: implement strings */ | ||
39 | #define GS_MANUFACTURER_STR_ID 0 | ||
40 | #define GS_PRODUCT_STR_ID 0 | ||
41 | #define GS_SERIAL_STR_ID 0 | ||
42 | #define GS_BULK_CONFIG_STR_ID 0 | ||
43 | #define GS_DATA_STR_ID 0 | ||
44 | |||
45 | #define GS_BULK_CONFIG_ID 1 | ||
46 | |||
47 | static struct usb_device_descriptor serial_device_desc = { | ||
48 | .bLength = USB_DT_DEVICE_SIZE, | ||
49 | .bDescriptorType = USB_DT_DEVICE, | ||
50 | .bcdUSB = 0x0200, | ||
51 | .bDeviceClass = USB_CLASS_COMM, | ||
52 | .bDeviceSubClass = 0, | ||
53 | .bDeviceProtocol = 0, | ||
54 | .idVendor = 0x0525, | ||
55 | .idProduct = 0xa4a6, | ||
56 | .iManufacturer = GS_MANUFACTURER_STR_ID, | ||
57 | .iProduct = GS_PRODUCT_STR_ID, | ||
58 | .iSerialNumber = GS_SERIAL_STR_ID, | ||
59 | .bNumConfigurations = 1, | ||
60 | }; | ||
61 | |||
62 | static struct usb_config_descriptor serial_bulk_config_desc = { | ||
63 | .bLength = USB_DT_CONFIG_SIZE, | ||
64 | .bDescriptorType = USB_DT_CONFIG, | ||
65 | |||
66 | .bNumInterfaces = 1, | ||
67 | .bConfigurationValue = GS_BULK_CONFIG_ID, | ||
68 | .iConfiguration = GS_BULK_CONFIG_STR_ID, | ||
69 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
70 | .bMaxPower = 1, | ||
71 | }; | ||
72 | |||
73 | static struct usb_interface_descriptor serial_bulk_interface_desc = { | ||
74 | .bLength = USB_DT_INTERFACE_SIZE, | ||
75 | .bDescriptorType = USB_DT_INTERFACE, | ||
76 | .bInterfaceNumber = 0, | ||
77 | .bNumEndpoints = 2, | ||
78 | .bInterfaceClass = USB_CLASS_CDC_DATA, | ||
79 | .bInterfaceSubClass = 0, | ||
80 | .bInterfaceProtocol = 0, | ||
81 | .iInterface = GS_DATA_STR_ID, | ||
82 | }; | ||
83 | |||
84 | static struct usb_endpoint_descriptor serial_fullspeed_in_desc = { | ||
85 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
86 | .bDescriptorType = USB_DT_ENDPOINT, | ||
87 | .bEndpointAddress = USB_DIR_IN, | ||
88 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
89 | .wMaxPacketSize = 8, | ||
90 | }; | ||
91 | |||
92 | static struct usb_endpoint_descriptor serial_fullspeed_out_desc = { | ||
93 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
94 | .bDescriptorType = USB_DT_ENDPOINT, | ||
95 | .bEndpointAddress = USB_DIR_OUT, | ||
96 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
97 | .wMaxPacketSize = 8, | ||
98 | }; | ||
99 | |||
100 | static struct usb_debug_descriptor serial_debug_desc = { | ||
101 | .bLength = sizeof(struct usb_debug_descriptor), | ||
102 | .bDescriptorType = USB_DT_DEBUG, | ||
103 | }; | ||
104 | |||
105 | static struct usb_qualifier_descriptor serial_qualifier_desc = { | ||
106 | .bLength = sizeof(struct usb_qualifier_descriptor), | ||
107 | .bDescriptorType = USB_DT_DEVICE_QUALIFIER, | ||
108 | .bcdUSB = 0x0200, | ||
109 | .bDeviceClass = USB_CLASS_COMM, | ||
110 | .bNumConfigurations = 1, | ||
111 | }; | ||
112 | |||
113 | struct usb_descriptor_header *serial_bulk_fullspeed_function[] = { | ||
114 | (struct usb_descriptor_header *) &serial_bulk_interface_desc, | ||
115 | (struct usb_descriptor_header *) &serial_fullspeed_in_desc, | ||
116 | (struct usb_descriptor_header *) &serial_fullspeed_out_desc, | ||
117 | NULL, | ||
118 | }; | ||
119 | |||
120 | #define BUFFER_SIZE 100 | ||
121 | uint8_t buf[BUFFER_SIZE]; | ||
122 | |||
123 | struct usb_response res; | ||
124 | |||
125 | /* helper functions */ | ||
126 | static int config_buf(uint8_t *buf, uint8_t type, unsigned index); | ||
127 | static int set_config(int config); | ||
128 | |||
129 | |||
130 | struct device { | ||
131 | struct usb_ep* in; | ||
132 | struct usb_ep* out; | ||
133 | uint32_t used_config; | ||
134 | }; | ||
135 | |||
136 | static struct device dev; | ||
137 | |||
138 | /*-------------------------------------------------------------------------*/ | ||
139 | |||
140 | void usb_serial_driver_init(void) { | ||
141 | |||
142 | logf("usb serial: register"); | ||
143 | usb_device_driver_register(&usb_serial_driver); | ||
144 | } | ||
145 | |||
146 | /*-------------------------------------------------------------------------*/ | ||
147 | |||
148 | void usb_serial_driver_bind(void* controler_ops) { | ||
149 | |||
150 | logf("usb serial: bind"); | ||
151 | ops = controler_ops; | ||
152 | |||
153 | /* serach and asign endpoints */ | ||
154 | usb_ep_autoconfig_reset(); | ||
155 | |||
156 | dev.in = usb_ep_autoconfig(&serial_fullspeed_in_desc); | ||
157 | if (!dev.in) { | ||
158 | goto autoconf_fail; | ||
159 | } | ||
160 | dev.in->claimed = true; | ||
161 | logf("usb serial: in: %s", dev.in->name); | ||
162 | |||
163 | dev.out = usb_ep_autoconfig(&serial_fullspeed_out_desc); | ||
164 | if (!dev.out) { | ||
165 | goto autoconf_fail; | ||
166 | } | ||
167 | dev.out->claimed = true; | ||
168 | logf("usb serial: out: %s", dev.out->name); | ||
169 | |||
170 | /* update device decsriptor */ | ||
171 | serial_device_desc.bMaxPacketSize0 = ops->ep0->maxpacket; | ||
172 | |||
173 | /* update qualifie descriptor */ | ||
174 | serial_qualifier_desc.bMaxPacketSize0 = ops->ep0->maxpacket; | ||
175 | |||
176 | /* update debug descriptor */ | ||
177 | serial_debug_desc.bDebugInEndpoint = dev.in->ep_num; | ||
178 | serial_debug_desc.bDebugOutEndpoint = dev.out->ep_num; | ||
179 | |||
180 | return; | ||
181 | |||
182 | autoconf_fail: | ||
183 | logf("failed to find endpoiunts"); | ||
184 | } | ||
185 | |||
186 | int usb_serial_driver_request(struct usb_ctrlrequest* request) { | ||
187 | |||
188 | int ret = -EOPNOTSUPP; | ||
189 | logf("usb serial: request"); | ||
190 | |||
191 | res.length = 0; | ||
192 | res.buf = NULL; | ||
193 | |||
194 | switch (request->bRequestType & USB_TYPE_MASK) { | ||
195 | case USB_TYPE_STANDARD: | ||
196 | |||
197 | switch (request->bRequest) { | ||
198 | case USB_REQ_GET_DESCRIPTOR: | ||
199 | |||
200 | switch (request->wValue >> 8) { | ||
201 | case USB_DT_DEVICE: | ||
202 | logf("usb serial: sending device desc"); | ||
203 | ret = MIN(sizeof(struct usb_device_descriptor), request->wLength); | ||
204 | res.buf = &serial_device_desc; | ||
205 | break; | ||
206 | |||
207 | case USB_DT_DEVICE_QUALIFIER: | ||
208 | logf("usb serial: sending qualifier dec"); | ||
209 | ret = MIN(sizeof(struct usb_qualifier_descriptor), request->wLength); | ||
210 | res.buf = &serial_qualifier_desc; | ||
211 | |||
212 | case USB_DT_CONFIG: | ||
213 | logf("usb serial: sending config desc"); | ||
214 | |||
215 | ret = config_buf(buf, request->wValue >> 8, request->wValue & 0xff); | ||
216 | if (ret >= 0) { | ||
217 | logf("%d, vs %d", request->wLength, ret); | ||
218 | ret = MIN(request->wLength, (uint16_t)ret); | ||
219 | } | ||
220 | res.buf = buf; | ||
221 | break; | ||
222 | |||
223 | case USB_DT_DEBUG: | ||
224 | logf("usb serial: sending debug desc"); | ||
225 | ret = MIN(sizeof(struct usb_debug_descriptor), request->wLength); | ||
226 | res.buf = &serial_debug_desc; | ||
227 | break; | ||
228 | } | ||
229 | break; | ||
230 | |||
231 | case USB_REQ_SET_CONFIGURATION: | ||
232 | logf("usb serial: set configuration %d", request->wValue); | ||
233 | ret = set_config(request->wValue); | ||
234 | break; | ||
235 | |||
236 | case USB_REQ_GET_CONFIGURATION: | ||
237 | logf("usb serial: get configuration"); | ||
238 | ret = 1; | ||
239 | res.buf = &dev.used_config; | ||
240 | break; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (ret >= 0) { | ||
245 | res.length = ret; | ||
246 | ret = ops->send(NULL, &res); | ||
247 | } | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | void usb_serial_driver_speed(enum usb_device_speed speed) { | ||
253 | |||
254 | switch (speed) { | ||
255 | case USB_SPEED_LOW: | ||
256 | case USB_SPEED_FULL: | ||
257 | logf("usb serial: using fullspeed"); | ||
258 | break; | ||
259 | case USB_SPEED_HIGH: | ||
260 | logf("usb serial: using highspeed"); | ||
261 | break; | ||
262 | default: | ||
263 | logf("speed: hmm"); | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /*-------------------------------------------------------------------------*/ | ||
269 | /* helper functions */ | ||
270 | |||
271 | static int config_buf(uint8_t *buf, uint8_t type, unsigned index) { | ||
272 | |||
273 | int len; | ||
274 | |||
275 | /* TODO check index*/ | ||
276 | |||
277 | len = usb_stack_configdesc(&serial_bulk_config_desc, buf, BUFFER_SIZE, serial_bulk_fullspeed_function); | ||
278 | if (len < 0) { | ||
279 | return len; | ||
280 | } | ||
281 | ((struct usb_config_descriptor *)buf)->bDescriptorType = type; | ||
282 | return len; | ||
283 | } | ||
284 | |||
285 | static int set_config(int config) { | ||
286 | |||
287 | /* TODO check config*/ | ||
288 | |||
289 | /* enable endpoints */ | ||
290 | logf("setup %s", dev.in->name); | ||
291 | ops->enable(dev.in); | ||
292 | logf("setup %s", dev.out->name); | ||
293 | ops->enable(dev.out); | ||
294 | |||
295 | /* store config */ | ||
296 | logf("using config %d", config); | ||
297 | dev.used_config = config; | ||
298 | |||
299 | return 0; | ||
300 | } | ||