| .. | .. |
|---|
| 10 | 10 | #include <linux/ctype.h> |
|---|
| 11 | 11 | #include <linux/debugfs.h> |
|---|
| 12 | 12 | #include <linux/delay.h> |
|---|
| 13 | +#include <linux/idr.h> |
|---|
| 13 | 14 | #include <linux/kref.h> |
|---|
| 14 | 15 | #include <linux/miscdevice.h> |
|---|
| 15 | 16 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 34 | 35 | MODULE_LICENSE("GPL"); |
|---|
| 35 | 36 | |
|---|
| 36 | 37 | /*----------------------------------------------------------------------*/ |
|---|
| 38 | + |
|---|
| 39 | +static DEFINE_IDA(driver_id_numbers); |
|---|
| 40 | +#define DRIVER_DRIVER_NAME_LENGTH_MAX 32 |
|---|
| 37 | 41 | |
|---|
| 38 | 42 | #define RAW_EVENT_QUEUE_SIZE 16 |
|---|
| 39 | 43 | |
|---|
| .. | .. |
|---|
| 144 | 148 | STATE_DEV_INVALID = 0, |
|---|
| 145 | 149 | STATE_DEV_OPENED, |
|---|
| 146 | 150 | STATE_DEV_INITIALIZED, |
|---|
| 151 | + STATE_DEV_REGISTERING, |
|---|
| 147 | 152 | STATE_DEV_RUNNING, |
|---|
| 148 | 153 | STATE_DEV_CLOSED, |
|---|
| 149 | 154 | STATE_DEV_FAILED |
|---|
| .. | .. |
|---|
| 158 | 163 | |
|---|
| 159 | 164 | /* Reference to misc device: */ |
|---|
| 160 | 165 | struct device *dev; |
|---|
| 166 | + |
|---|
| 167 | + /* Make driver names unique */ |
|---|
| 168 | + int driver_id_number; |
|---|
| 161 | 169 | |
|---|
| 162 | 170 | /* Protected by lock: */ |
|---|
| 163 | 171 | enum dev_state state; |
|---|
| .. | .. |
|---|
| 187 | 195 | spin_lock_init(&dev->lock); |
|---|
| 188 | 196 | init_completion(&dev->ep0_done); |
|---|
| 189 | 197 | raw_event_queue_init(&dev->queue); |
|---|
| 198 | + dev->driver_id_number = -1; |
|---|
| 190 | 199 | return dev; |
|---|
| 191 | 200 | } |
|---|
| 192 | 201 | |
|---|
| .. | .. |
|---|
| 197 | 206 | |
|---|
| 198 | 207 | kfree(dev->udc_name); |
|---|
| 199 | 208 | kfree(dev->driver.udc_name); |
|---|
| 209 | + kfree(dev->driver.driver.name); |
|---|
| 210 | + if (dev->driver_id_number >= 0) |
|---|
| 211 | + ida_free(&driver_id_numbers, dev->driver_id_number); |
|---|
| 200 | 212 | if (dev->req) { |
|---|
| 201 | 213 | if (dev->ep0_urb_queued) |
|---|
| 202 | 214 | usb_ep_dequeue(dev->gadget->ep0, dev->req); |
|---|
| .. | .. |
|---|
| 297 | 309 | dev->eps_num = i; |
|---|
| 298 | 310 | spin_unlock_irqrestore(&dev->lock, flags); |
|---|
| 299 | 311 | |
|---|
| 312 | + ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL); |
|---|
| 313 | + if (ret < 0) { |
|---|
| 314 | + dev_err(&gadget->dev, "failed to queue event\n"); |
|---|
| 315 | + set_gadget_data(gadget, NULL); |
|---|
| 316 | + return ret; |
|---|
| 317 | + } |
|---|
| 318 | + |
|---|
| 300 | 319 | /* Matches kref_put() in gadget_unbind(). */ |
|---|
| 301 | 320 | kref_get(&dev->count); |
|---|
| 302 | | - |
|---|
| 303 | | - ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL); |
|---|
| 304 | | - if (ret < 0) |
|---|
| 305 | | - dev_err(&gadget->dev, "failed to queue event\n"); |
|---|
| 306 | | - |
|---|
| 307 | 321 | return ret; |
|---|
| 308 | 322 | } |
|---|
| 309 | 323 | |
|---|
| .. | .. |
|---|
| 417 | 431 | static int raw_ioctl_init(struct raw_dev *dev, unsigned long value) |
|---|
| 418 | 432 | { |
|---|
| 419 | 433 | int ret = 0; |
|---|
| 434 | + int driver_id_number; |
|---|
| 420 | 435 | struct usb_raw_init arg; |
|---|
| 421 | 436 | char *udc_driver_name; |
|---|
| 422 | 437 | char *udc_device_name; |
|---|
| 438 | + char *driver_driver_name; |
|---|
| 423 | 439 | unsigned long flags; |
|---|
| 424 | 440 | |
|---|
| 425 | 441 | if (copy_from_user(&arg, (void __user *)value, sizeof(arg))) |
|---|
| .. | .. |
|---|
| 438 | 454 | return -EINVAL; |
|---|
| 439 | 455 | } |
|---|
| 440 | 456 | |
|---|
| 457 | + driver_id_number = ida_alloc(&driver_id_numbers, GFP_KERNEL); |
|---|
| 458 | + if (driver_id_number < 0) |
|---|
| 459 | + return driver_id_number; |
|---|
| 460 | + |
|---|
| 461 | + driver_driver_name = kmalloc(DRIVER_DRIVER_NAME_LENGTH_MAX, GFP_KERNEL); |
|---|
| 462 | + if (!driver_driver_name) { |
|---|
| 463 | + ret = -ENOMEM; |
|---|
| 464 | + goto out_free_driver_id_number; |
|---|
| 465 | + } |
|---|
| 466 | + snprintf(driver_driver_name, DRIVER_DRIVER_NAME_LENGTH_MAX, |
|---|
| 467 | + DRIVER_NAME ".%d", driver_id_number); |
|---|
| 468 | + |
|---|
| 441 | 469 | udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL); |
|---|
| 442 | | - if (!udc_driver_name) |
|---|
| 443 | | - return -ENOMEM; |
|---|
| 470 | + if (!udc_driver_name) { |
|---|
| 471 | + ret = -ENOMEM; |
|---|
| 472 | + goto out_free_driver_driver_name; |
|---|
| 473 | + } |
|---|
| 444 | 474 | ret = strscpy(udc_driver_name, &arg.driver_name[0], |
|---|
| 445 | 475 | UDC_NAME_LENGTH_MAX); |
|---|
| 446 | | - if (ret < 0) { |
|---|
| 447 | | - kfree(udc_driver_name); |
|---|
| 448 | | - return ret; |
|---|
| 449 | | - } |
|---|
| 476 | + if (ret < 0) |
|---|
| 477 | + goto out_free_udc_driver_name; |
|---|
| 450 | 478 | ret = 0; |
|---|
| 451 | 479 | |
|---|
| 452 | 480 | udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL); |
|---|
| 453 | 481 | if (!udc_device_name) { |
|---|
| 454 | | - kfree(udc_driver_name); |
|---|
| 455 | | - return -ENOMEM; |
|---|
| 482 | + ret = -ENOMEM; |
|---|
| 483 | + goto out_free_udc_driver_name; |
|---|
| 456 | 484 | } |
|---|
| 457 | 485 | ret = strscpy(udc_device_name, &arg.device_name[0], |
|---|
| 458 | 486 | UDC_NAME_LENGTH_MAX); |
|---|
| 459 | | - if (ret < 0) { |
|---|
| 460 | | - kfree(udc_driver_name); |
|---|
| 461 | | - kfree(udc_device_name); |
|---|
| 462 | | - return ret; |
|---|
| 463 | | - } |
|---|
| 487 | + if (ret < 0) |
|---|
| 488 | + goto out_free_udc_device_name; |
|---|
| 464 | 489 | ret = 0; |
|---|
| 465 | 490 | |
|---|
| 466 | 491 | spin_lock_irqsave(&dev->lock, flags); |
|---|
| 467 | 492 | if (dev->state != STATE_DEV_OPENED) { |
|---|
| 468 | 493 | dev_dbg(dev->dev, "fail, device is not opened\n"); |
|---|
| 469 | | - kfree(udc_driver_name); |
|---|
| 470 | | - kfree(udc_device_name); |
|---|
| 471 | 494 | ret = -EINVAL; |
|---|
| 472 | 495 | goto out_unlock; |
|---|
| 473 | 496 | } |
|---|
| .. | .. |
|---|
| 482 | 505 | dev->driver.suspend = gadget_suspend; |
|---|
| 483 | 506 | dev->driver.resume = gadget_resume; |
|---|
| 484 | 507 | dev->driver.reset = gadget_reset; |
|---|
| 485 | | - dev->driver.driver.name = DRIVER_NAME; |
|---|
| 508 | + dev->driver.driver.name = driver_driver_name; |
|---|
| 486 | 509 | dev->driver.udc_name = udc_device_name; |
|---|
| 487 | 510 | dev->driver.match_existing_only = 1; |
|---|
| 511 | + dev->driver_id_number = driver_id_number; |
|---|
| 488 | 512 | |
|---|
| 489 | 513 | dev->state = STATE_DEV_INITIALIZED; |
|---|
| 514 | + spin_unlock_irqrestore(&dev->lock, flags); |
|---|
| 515 | + return ret; |
|---|
| 490 | 516 | |
|---|
| 491 | 517 | out_unlock: |
|---|
| 492 | 518 | spin_unlock_irqrestore(&dev->lock, flags); |
|---|
| 519 | +out_free_udc_device_name: |
|---|
| 520 | + kfree(udc_device_name); |
|---|
| 521 | +out_free_udc_driver_name: |
|---|
| 522 | + kfree(udc_driver_name); |
|---|
| 523 | +out_free_driver_driver_name: |
|---|
| 524 | + kfree(driver_driver_name); |
|---|
| 525 | +out_free_driver_id_number: |
|---|
| 526 | + ida_free(&driver_id_numbers, driver_id_number); |
|---|
| 493 | 527 | return ret; |
|---|
| 494 | 528 | } |
|---|
| 495 | 529 | |
|---|
| .. | .. |
|---|
| 507 | 541 | ret = -EINVAL; |
|---|
| 508 | 542 | goto out_unlock; |
|---|
| 509 | 543 | } |
|---|
| 544 | + dev->state = STATE_DEV_REGISTERING; |
|---|
| 510 | 545 | spin_unlock_irqrestore(&dev->lock, flags); |
|---|
| 511 | 546 | |
|---|
| 512 | 547 | ret = usb_gadget_probe_driver(&dev->driver); |
|---|
| .. | .. |
|---|
| 564 | 599 | return -ENODEV; |
|---|
| 565 | 600 | } |
|---|
| 566 | 601 | length = min(arg.length, event->length); |
|---|
| 567 | | - if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) |
|---|
| 602 | + if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) { |
|---|
| 603 | + kfree(event); |
|---|
| 568 | 604 | return -EFAULT; |
|---|
| 605 | + } |
|---|
| 569 | 606 | |
|---|
| 607 | + kfree(event); |
|---|
| 570 | 608 | return 0; |
|---|
| 571 | 609 | } |
|---|
| 572 | 610 | |
|---|
| .. | .. |
|---|
| 1000 | 1038 | ret = -EBUSY; |
|---|
| 1001 | 1039 | goto out_unlock; |
|---|
| 1002 | 1040 | } |
|---|
| 1003 | | - if ((in && !ep->ep->caps.dir_in) || (!in && ep->ep->caps.dir_in)) { |
|---|
| 1041 | + if (in != usb_endpoint_dir_in(ep->ep->desc)) { |
|---|
| 1004 | 1042 | dev_dbg(&dev->gadget->dev, "fail, wrong direction\n"); |
|---|
| 1005 | 1043 | ret = -EINVAL; |
|---|
| 1006 | 1044 | goto out_unlock; |
|---|