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