1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-12-12 Yi Qiu first version
9 */
10
11 #include <rtthread.h>
12 #include <drivers/usb_host.h>
13 #include "adk.h"
14
15 #ifdef RT_USBH_ADK
16
17 static struct uclass_driver adk_driver;
18 static const char* _adk_manufacturer = RT_NULL;
19 static const char* _adk_model = RT_NULL;
20 static const char* _adk_description = RT_NULL;
21 static const char* _adk_version = RT_NULL;
22 static const char* _adk_uri = RT_NULL;
23 static const char* _adk_serial = RT_NULL;
24
rt_usbh_adk_set_string(const char * manufacturer,const char * model,const char * description,const char * _version,const char * uri,const char * serial)25 rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model,
26 const char* description, const char* _version, const char* uri,
27 const char* serial)
28 {
29 _adk_manufacturer = manufacturer;
30 _adk_model = model;
31 _adk_description = description;
32 _adk_version = _version;
33 _adk_uri = uri;
34 _adk_serial = serial;
35
36 return RT_EOK;
37 }
38
39 #ifdef RT_USING_MODULE
40 #include <rtm.h>
41
42 RTM_EXPORT(rt_usbh_adk_set_string);
43 #endif
44
45 /**
46 * This function will do USB_REQ_GET_PROTOCOL request to set idle period to the usb adk device
47 *
48 * @param intf the interface instance.
49 * @duration the idle period of requesting data.
50 * @report_id the report id
51 *
52 * @return the error code, RT_EOK on successfully.
53 */
rt_usbh_adk_get_protocol(struct uintf * intf,rt_uint16_t * protocol)54 static rt_err_t rt_usbh_adk_get_protocol(struct uintf* intf, rt_uint16_t *protocol)
55 {
56 struct urequest setup;
57 uinst_t device;
58 int timeout = USB_TIMEOUT_BASIC;
59
60 /* parameter check */
61 RT_ASSERT(intf != RT_NULL);
62 RT_ASSERT(intf->device != RT_NULL);
63
64 device = intf->device;
65
66 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_VENDOR |
67 USB_REQ_TYPE_DEVICE;
68 setup.request = USB_REQ_GET_PROTOCOL;
69 setup.index = 0;
70 setup.length = 2;
71 setup.value = 0;
72
73 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)protocol, 2,
74 timeout) == 0) return RT_EOK;
75 else return -RT_FALSE;
76 }
77
78 /**
79 * This function will do USB_REQ_SEND_STRING request to set idle period to the usb adk device
80 *
81 * @param intf the interface instance.
82 * @duration the idle period of requesting data.
83 * @report_id the report id
84 *
85 * @return the error code, RT_EOK on successfully.
86 */
rt_usbh_adk_send_string(struct uintf * intf,rt_uint16_t index,const char * str)87 static rt_err_t rt_usbh_adk_send_string(struct uintf* intf, rt_uint16_t index,
88 const char* str)
89 {
90 struct urequest setup;
91 uinst_t device;
92 int timeout = USB_TIMEOUT_BASIC;
93
94 /* parameter check */
95 RT_ASSERT(intf != RT_NULL);
96 RT_ASSERT(intf->device != RT_NULL);
97
98 device = intf->device;
99
100 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
101 USB_REQ_TYPE_DEVICE;
102 setup.request = USB_REQ_SEND_STRING;
103 setup.index = index;
104 setup.length = rt_strlen(str) + 1;
105 setup.value = 0;
106
107 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)str,
108 rt_strlen(str) + 1, timeout) == 0) return RT_EOK;
109 else return -RT_FALSE;
110 }
111
112 /**
113 * This function will do USB_REQ_START request to set idle period to the usb adk device
114 *
115 * @param intf the interface instance.
116 * @duration the idle period of requesting data.
117 * @report_id the report id
118 *
119 * @return the error code, RT_EOK on successfully.
120 */
rt_usbh_adk_start(struct uintf * intf)121 static rt_err_t rt_usbh_adk_start(struct uintf* intf)
122 {
123 struct urequest setup;
124 uinst_t device;
125 int timeout = USB_TIMEOUT_BASIC;
126
127 /* parameter check */
128 RT_ASSERT(intf != RT_NULL);
129 RT_ASSERT(intf->device != RT_NULL);
130
131 device = intf->device;
132
133 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
134 USB_REQ_TYPE_DEVICE;
135 setup.request = USB_REQ_START;
136 setup.index = 0;
137 setup.length = 0;
138 setup.value = 0;
139
140 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0,
141 timeout) == 0) return RT_EOK;
142 else return -RT_FALSE;
143 }
144
145 /**
146 * This function will read data from usb adk device
147 *
148 * @param intf the interface instance.
149 *
150 * @return the error code, RT_EOK on successfully.
151 */
rt_usbh_adk_read(rt_device_t device,rt_off_t pos,void * buffer,rt_size_t size)152 static rt_size_t rt_usbh_adk_read(rt_device_t device, rt_off_t pos, void* buffer,
153 rt_size_t size)
154 {
155 uadk_t adk;
156 rt_size_t length;
157 struct uintf* intf;
158
159 /* check parameter */
160 RT_ASSERT(device != RT_NULL);
161 RT_ASSERT(buffer != RT_NULL);
162
163 intf = (struct uintf*)device->user_data;
164 adk = (uadk_t)intf->user_data;
165
166 length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_in,
167 buffer, size, 300);
168
169 return length;
170
171 }
172
173 /**
174 * This function will write data to usb adk device
175 *
176 * @param intf the interface instance.
177 *
178 * @return the error code, RT_EOK on successfully.
179 */
rt_usbh_adk_write(rt_device_t device,rt_off_t pos,const void * buffer,rt_size_t size)180 static rt_size_t rt_usbh_adk_write (rt_device_t device, rt_off_t pos, const void* buffer,
181 rt_size_t size)
182 {
183 uadk_t adk;
184 rt_size_t length;
185 struct uintf* intf;
186
187 RT_ASSERT(buffer != RT_NULL);
188
189 intf = (struct uintf*)device->user_data;
190 adk = (uadk_t)intf->user_data;
191
192 length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_out,
193 (void*)buffer, size, 300);
194
195 return length;
196 }
197
198 #ifdef RT_USING_DEVICE_OPS
199 const static struct rt_device_ops adk_device_ops =
200 {
201 RT_NULL;
202 RT_NULL;
203 RT_NULL;
204 rt_usbh_adk_read;
205 rt_usbh_adk_write;
206 RT_NULL;
207 };
208 #endif
209
210 /**
211 * This function will run adk class driver when usb device is detected and identified
212 * as a adk class device, it will continue the enumulate process.
213 *
214 * @param arg the argument.
215 *
216 * @return the error code, RT_EOK on successfully.
217 */
rt_usbh_adk_enable(void * arg)218 static rt_err_t rt_usbh_adk_enable(void* arg)
219 {
220 int i = 0;
221 uadk_t adk;
222 struct uintf* intf = (struct uintf*)arg;
223 udev_desc_t dev_desc;
224 rt_uint16_t protocol;
225 rt_err_t ret;
226
227 /* parameter check */
228 if(intf == RT_NULL)
229 {
230 rt_kprintf("the interface is not available\n");
231 return -RT_EIO;
232 }
233
234 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_adk_run\n"));
235
236 dev_desc = &intf->device->dev_desc;
237 if(dev_desc->idVendor == USB_ACCESSORY_VENDOR_ID &&
238 (dev_desc->idProduct == USB_ACCESSORY_PRODUCT_ID ||
239 dev_desc->idProduct == USB_ACCESSORY_ADB_PRODUCT_ID))
240 {
241 if(intf->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR;
242
243 RT_DEBUG_LOG(RT_DEBUG_USB, ("found android accessory device\n"));
244 }
245 else
246 {
247 RT_DEBUG_LOG(RT_DEBUG_USB, ("switch device\n"));
248
249 if((ret = rt_usbh_adk_get_protocol(intf, &protocol)) != RT_EOK)
250 {
251 rt_kprintf("rt_usbh_adk_get_protocol failed\n");
252 return ret;
253 }
254
255 if(protocol != 1)
256 {
257 rt_kprintf("read protocol failed\n");
258 return -RT_ERROR;
259 }
260
261 rt_usbh_adk_send_string(intf,
262 ACCESSORY_STRING_MANUFACTURER, _adk_manufacturer);
263 rt_usbh_adk_send_string(intf,
264 ACCESSORY_STRING_MODEL, _adk_model);
265 rt_usbh_adk_send_string(intf,
266 ACCESSORY_STRING_DESCRIPTION, _adk_description);
267 rt_usbh_adk_send_string(intf,
268 ACCESSORY_STRING_VERSION, _adk_version);
269 rt_usbh_adk_send_string(intf,
270 ACCESSORY_STRING_URI, _adk_uri);
271 rt_usbh_adk_send_string(intf,
272 ACCESSORY_STRING_SERIAL, _adk_serial);
273
274 RT_DEBUG_LOG(RT_DEBUG_USB, ("manufacturer %s\n", _adk_manufacturer));
275 RT_DEBUG_LOG(RT_DEBUG_USB, ("model %s\n", _adk_model));
276 RT_DEBUG_LOG(RT_DEBUG_USB, ("description %s\n", _adk_description));
277 RT_DEBUG_LOG(RT_DEBUG_USB, ("version %s\n", _adk_version));
278 RT_DEBUG_LOG(RT_DEBUG_USB, ("uri %s\n", _adk_uri));
279 RT_DEBUG_LOG(RT_DEBUG_USB, ("serial %s\n", _adk_serial));
280
281 if((ret = rt_usbh_adk_start(intf)) != RT_EOK)
282 {
283 rt_kprintf("rt_usbh_adk_start failed\n");
284 return ret;
285 }
286
287 return RT_EOK;
288 }
289
290 adk = rt_malloc(sizeof(struct uadkinst));
291 RT_ASSERT(adk != RT_NULL);
292
293 /* initilize the data structure */
294 rt_memset(adk, 0, sizeof(struct uadkinst));
295 intf->user_data = (void*)adk;
296
297 for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
298 {
299 uep_desc_t ep_desc;
300
301 /* get endpoint descriptor from interface descriptor */
302 rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
303 if(ep_desc == RT_NULL)
304 {
305 rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
306 return -RT_ERROR;
307 }
308
309 /* the endpoint type of adk class should be BULK */
310 if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
311 continue;
312
313 /* allocate pipes according to the endpoint type */
314 if(ep_desc->bEndpointAddress & USB_DIR_IN)
315 {
316 /* allocate an in pipe for the adk instance */
317 ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_in,
318 intf, ep_desc, RT_NULL);
319 if(ret != RT_EOK) return ret;
320 }
321 else
322 {
323 /* allocate an output pipe for the adk instance */
324 ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_out,
325 intf, ep_desc, RT_NULL);
326 if(ret != RT_EOK) return ret;
327 }
328 }
329
330 /* check pipes infomation */
331 if(adk->pipe_in == RT_NULL || adk->pipe_out == RT_NULL)
332 {
333 rt_kprintf("pipe error, unsupported device\n");
334 return -RT_ERROR;
335 }
336
337 /* set configuration */
338 ret = rt_usbh_set_configure(intf->device, 1);
339 if(ret != RT_EOK) return ret;
340
341 /* register adk device */
342 adk->device.type = RT_Device_Class_Char;
343 #ifdef RT_USING_DEVICE_OPS
344 adk->device.ops = &adk_device_ops;
345 #else
346 adk->device.init = RT_NULL;
347 adk->device.open = RT_NULL;
348 adk->device.close = RT_NULL;
349 adk->device.read = rt_usbh_adk_read;
350 adk->device.write = rt_usbh_adk_write;
351 adk->device.control = RT_NULL;
352 #endif
353 adk->device.user_data = (void*)intf;
354
355 rt_device_register(&adk->device, "adkdev", RT_DEVICE_FLAG_RDWR);
356
357 return RT_EOK;
358 }
359
360 /**
361 * This function will be invoked when usb device plug out is detected and it would clean
362 * and release all hub class related resources.
363 *
364 * @param arg the argument.
365 *
366 * @return the error code, RT_EOK on successfully.
367 */
rt_usbh_adk_disable(void * arg)368 static rt_err_t rt_usbh_adk_disable(void* arg)
369 {
370 uadk_t adk;
371 struct uintf* intf = (struct uintf*)arg;
372
373 RT_ASSERT(intf != RT_NULL);
374
375 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_adk_stop\n"));
376
377 adk = (uadk_t)intf->user_data;
378 if(adk == RT_NULL)
379 {
380 rt_free(intf);
381 return RT_EOK;
382 }
383
384 if(adk->pipe_in != RT_NULL)
385 rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_in);
386
387 if(adk->pipe_out != RT_NULL)
388 rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_out);
389
390 /* unregister adk device */
391 rt_device_unregister(&adk->device);
392
393 /* free adk instance */
394 if(adk != RT_NULL)
395 {
396 rt_free(adk);
397 }
398
399 /* free interface instance */
400 rt_free(intf);
401
402 return RT_EOK;
403 }
404
405 /**
406 * This function will register adk class driver to the usb class driver manager.
407 * and it should be invoked in the usb system initialization.
408 *
409 * @return the error code, RT_EOK on successfully.
410 */
rt_usbh_class_driver_adk(void)411 ucd_t rt_usbh_class_driver_adk(void)
412 {
413 adk_driver.class_code = USB_CLASS_ADK;
414
415 adk_driver.enable = rt_usbh_adk_enable;
416 adk_driver.disable = rt_usbh_adk_disable;
417
418 return &adk_driver;
419 }
420
421 #endif
422
423