xref: /nrf52832-nimble/rt-thread/components/drivers/usb/usbhost/class/adk.c (revision 167494296f0543431a51b6b1b83e957045294e05)
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 
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 */
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 */
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 */
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 */
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 */
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  */
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  */
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  */
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