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