| /* |
| * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| /* |
| * driver assumes self-powered hardware, and |
| * has no way for users to trigger remote wakeup. |
| */ |
| |
| /*#define VERBOSE_DEBUG*/ |
| |
| #include <linux/kernel.h> |
| #include <linux/slab.h> |
| #include <linux/utsname.h> |
| #include <linux/device.h> |
| |
| #include "g_nvusb.h" |
| #include "gadget_chips.h" |
| |
| /*-------------------------------------------------------------------------*/ |
| |
| /* |
| * Kbuild is not very cooperative with respect to linking separately |
| * compiled library objects into one module. So for now we won't use |
| * separate compilation ... ensuring init/exit sections work to shrink |
| * the runtime footprint, and giving us at least some parts of what |
| * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
| */ |
| #include "composite.c" |
| #include "usbstring.c" |
| #include "config.c" |
| #include "epautoconf.c" |
| #include "f_nvusb.c" |
| |
| /*-------------------------------------------------------------------------*/ |
| |
| #define DRIVER_VERSION "Nvidia Version 1.0" |
| |
| static const char longname[] = "Gadget nvusb"; |
| |
| /*-------------------------------------------------------------------------*/ |
| #define DRIVER_VENDOR_NUM 0x0955 |
| #define DRIVER_PRODUCT_NUM 0xffff |
| |
| /*-------------------------------------------------------------------------*/ |
| |
| static struct usb_device_descriptor device_desc = { |
| .bLength = sizeof device_desc, |
| .bDescriptorType = USB_DT_DEVICE, |
| |
| .bcdUSB = cpu_to_le16(0x0200), |
| .bDeviceClass = USB_CLASS_VENDOR_SPEC, |
| |
| .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), |
| .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), |
| .bNumConfigurations = 1, |
| }; |
| |
| /* string IDs are assigned dynamically */ |
| |
| #define STRING_MANUFACTURER_IDX 0 |
| #define STRING_PRODUCT_IDX 1 |
| #define STRING_SERIAL_IDX 2 |
| |
| static char manufacturer[50]; |
| |
| /* default serial number takes at least two packets */ |
| static const char serial[] = "0123456789.0123456789.0123456789"; |
| |
| static struct usb_string strings_dev[] = { |
| [STRING_MANUFACTURER_IDX].s = manufacturer, |
| [STRING_PRODUCT_IDX].s = longname, |
| [STRING_SERIAL_IDX].s = serial, |
| { } /* end of list */ |
| }; |
| |
| static struct usb_gadget_strings stringtab_dev = { |
| .language = 0x0409, /* en-us */ |
| .strings = strings_dev, |
| }; |
| |
| static struct usb_gadget_strings *dev_strings[] = { |
| &stringtab_dev, |
| NULL, |
| }; |
| |
| /*-------------------------------------------------------------------------*/ |
| |
| static int __init nvusb_bind(struct usb_composite_dev *cdev) |
| { |
| int gcnum; |
| struct usb_gadget *gadget = cdev->gadget; |
| int id; |
| |
| /* Allocate string descriptor numbers ... note that string |
| * contents can be overridden by the composite_dev glue. |
| */ |
| id = usb_string_id(cdev); |
| if (id < 0) |
| return id; |
| strings_dev[STRING_MANUFACTURER_IDX].id = id; |
| device_desc.iManufacturer = id; |
| |
| id = usb_string_id(cdev); |
| if (id < 0) |
| return id; |
| strings_dev[STRING_PRODUCT_IDX].id = id; |
| device_desc.iProduct = id; |
| |
| id = usb_string_id(cdev); |
| if (id < 0) |
| return id; |
| strings_dev[STRING_SERIAL_IDX].id = id; |
| device_desc.iSerialNumber = id; |
| |
| nvusb_add(cdev); |
| |
| gcnum = usb_gadget_controller_number(gadget); |
| if (gcnum >= 0) |
| device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); |
| else { |
| /* gadget nvusb is so simple (for now, no altsettings) that |
| * it SHOULD NOT have problems with bulk-capable hardware. |
| * so just warn about unrcognized controllers -- don't panic. |
| * |
| * things like configuration and altsetting numbering |
| * can need hardware-specific attention though. |
| */ |
| pr_warning("%s: controller '%s' not recognized\n", |
| longname, gadget->name); |
| device_desc.bcdDevice = cpu_to_le16(0x9999); |
| } |
| |
| INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); |
| |
| snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", |
| init_utsname()->sysname, init_utsname()->release, |
| gadget->name); |
| |
| return 0; |
| } |
| |
| static int nvusb_unbind(struct usb_composite_dev *cdev) |
| { |
| return 0; |
| } |
| |
| static struct usb_composite_driver nvusb_composite_driver = { |
| .name = "nvusb", |
| .dev = &device_desc, |
| .strings = dev_strings, |
| .max_speed = USB_SPEED_HIGH, |
| .unbind = nvusb_unbind, |
| }; |
| |
| MODULE_AUTHOR("NVIDIA"); |
| MODULE_LICENSE("GPL"); |
| |
| static int __init init(void) |
| { |
| return usb_composite_probe(&nvusb_composite_driver, nvusb_bind); |
| } |
| module_init(init); |
| |
| static void __exit cleanup(void) |
| { |
| usb_composite_unregister(&nvusb_composite_driver); |
| } |
| module_exit(cleanup); |