16c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*
26c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * ncm.c -- NCM gadget driver
36c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta *
46c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Copyright (C) 2010 Nokia Corporation
56c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com>
66c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta *
76c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * The driver borrows from ether.c which is:
86c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta *
96c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Copyright (C) 2003-2005,2008 David Brownell
106c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
116c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Copyright (C) 2008 Nokia Corporation
126c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta *
136c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * This program is free software; you can redistribute it and/or modify
146c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * it under the terms of the GNU General Public License as published by
156c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * the Free Software Foundation; either version 2 of the License, or
166c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * (at your option) any later version.
176c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta */
186c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
196c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/* #define DEBUG */
206c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/* #define VERBOSE_DEBUG */
216c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
226c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include <linux/kernel.h>
236c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include <linux/utsname.h>
246c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
256c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
266c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "u_ether.h"
276c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
286c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#define DRIVER_DESC		"NCM Gadget"
296c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
306c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*-------------------------------------------------------------------------*/
316c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
326c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*
336c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Kbuild is not very cooperative with respect to linking separately
346c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * compiled library objects into one module.  So for now we won't use
356c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * separate compilation ... ensuring init/exit sections work to shrink
366c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * the runtime footprint, and giving us at least some parts of what
376c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
386c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta */
396c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "composite.c"
406c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "usbstring.c"
416c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "config.c"
426c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "epautoconf.c"
436c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
446c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "f_ncm.c"
456c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#include "u_ether.c"
466c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
476c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*-------------------------------------------------------------------------*/
486c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
496c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
506c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * Instead:  allocate your own, using normal USB-IF procedures.
516c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta */
526c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
536c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/* Thanks to NetChip Technologies for donating this product ID.
546c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta * It's for devices with only CDC Ethernet configurations.
556c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta */
566c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#define CDC_VENDOR_NUM		0x0525	/* NetChip */
576c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#define CDC_PRODUCT_NUM		0xa4a1	/* Linux-USB Ethernet Gadget */
586c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
596c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*-------------------------------------------------------------------------*/
606c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
616c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_device_descriptor device_desc = {
626c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bLength =		sizeof device_desc,
636c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bDescriptorType =	USB_DT_DEVICE,
646c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
656c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bcdUSB =		cpu_to_le16 (0x0200),
666c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
676c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bDeviceClass =		USB_CLASS_COMM,
686c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bDeviceSubClass =	0,
696c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bDeviceProtocol =	0,
706c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* .bMaxPacketSize0 = f(hardware) */
716c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
726c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* Vendor and product id defaults change according to what configs
736c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 * we support.  (As does bNumConfigurations.)  These values can
746c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 * also be overridden by module parameters.
756c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 */
766c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.idVendor =		cpu_to_le16 (CDC_VENDOR_NUM),
776c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.idProduct =		cpu_to_le16 (CDC_PRODUCT_NUM),
786c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* .bcdDevice = f(hardware) */
796c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* .iManufacturer = DYNAMIC */
806c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* .iProduct = DYNAMIC */
816c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* NO SERIAL NUMBER */
826c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bNumConfigurations =	1,
836c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
846c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
856c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_otg_descriptor otg_descriptor = {
866c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bLength =		sizeof otg_descriptor,
876c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bDescriptorType =	USB_DT_OTG,
886c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
896c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* REVISIT SRP-only hardware is possible, although
906c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 * it would not be called "OTG" ...
916c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 */
926c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
936c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
946c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
956c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic const struct usb_descriptor_header *otg_desc[] = {
966c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	(struct usb_descriptor_header *) &otg_descriptor,
976c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	NULL,
986c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
996c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1006c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1016c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/* string IDs are assigned dynamically */
1026c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1036c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#define STRING_MANUFACTURER_IDX		0
1046c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta#define STRING_PRODUCT_IDX		1
1056c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1066c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic char manufacturer[50];
1076c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1086c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_string strings_dev[] = {
1096c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	[STRING_MANUFACTURER_IDX].s = manufacturer,
1106c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
1116c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	{  } /* end of list */
1126c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
1136c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1146c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_gadget_strings stringtab_dev = {
1156c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.language	= 0x0409,	/* en-us */
1166c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.strings	= strings_dev,
1176c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
1186c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1196c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_gadget_strings *dev_strings[] = {
1206c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	&stringtab_dev,
1216c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	NULL,
1226c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
1236c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1246c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic u8 hostaddr[ETH_ALEN];
1256c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1266c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*-------------------------------------------------------------------------*/
1276c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1286c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic int __init ncm_do_config(struct usb_configuration *c)
1296c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta{
1306c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* FIXME alloc iConfiguration string, set it in c->strings */
1316c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1326c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	if (gadget_is_otg(c->cdev->gadget)) {
1336c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		c->descriptors = otg_desc;
1346c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1356c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	}
1366c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1376c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	return ncm_bind_config(c, hostaddr);
1386c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta}
1396c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1406c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_configuration ncm_config_driver = {
1416c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* .label = f(hardware) */
1426c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.label			= "CDC Ethernet (NCM)",
1436c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bConfigurationValue	= 1,
1446c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* .iConfiguration = DYNAMIC */
1456c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
1466c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
1476c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1486c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta/*-------------------------------------------------------------------------*/
1496c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1506c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic int __init gncm_bind(struct usb_composite_dev *cdev)
1516c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta{
1526c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	int			gcnum;
1536c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	struct usb_gadget	*gadget = cdev->gadget;
1546c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	int			status;
1556c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1566c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* set up network link layer */
1576c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	status = gether_setup(cdev->gadget, hostaddr);
1586c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	if (status < 0)
1596c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		return status;
1606c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1616c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	gcnum = usb_gadget_controller_number(gadget);
1626c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	if (gcnum >= 0)
1636c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
1646c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	else {
1656c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		/* We assume that can_support_ecm() tells the truth;
1666c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		 * but if the controller isn't recognized at all then
1676c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		 * that assumption is a bit more likely to be wrong.
1686c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		 */
1696c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		dev_warn(&gadget->dev,
1706c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta			 "controller '%s' not recognized; trying %s\n",
1716c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta			 gadget->name,
1726c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta			 ncm_config_driver.label);
1736c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		device_desc.bcdDevice =
1746c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta			cpu_to_le16(0x0300 | 0x0099);
1756c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	}
1766c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1776c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1786c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* Allocate string descriptor numbers ... note that string
1796c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 * contents can be overridden by the composite_dev glue.
1806c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	 */
1816c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1826c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	/* device descriptor strings: manufacturer, product */
1836c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
1846c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		init_utsname()->sysname, init_utsname()->release,
1856c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		gadget->name);
1866c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	status = usb_string_id(cdev);
1876c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	if (status < 0)
1886c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		goto fail;
1896c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	strings_dev[STRING_MANUFACTURER_IDX].id = status;
1906c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	device_desc.iManufacturer = status;
1916c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1926c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	status = usb_string_id(cdev);
1936c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	if (status < 0)
1946c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		goto fail;
1956c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	strings_dev[STRING_PRODUCT_IDX].id = status;
1966c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	device_desc.iProduct = status;
1976c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
1986c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	status = usb_add_config(cdev, &ncm_config_driver,
1996c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta				ncm_do_config);
2006c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	if (status < 0)
2016c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta		goto fail;
2026c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2036c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
2046c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2056c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	return 0;
2066c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2076c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutafail:
2086c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	gether_cleanup();
2096c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	return status;
2106c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta}
2116c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2126c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic int __exit gncm_unbind(struct usb_composite_dev *cdev)
2136c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta{
2146c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	gether_cleanup();
2156c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	return 0;
2166c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta}
2176c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2186c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic struct usb_composite_driver ncm_driver = {
2196c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.name		= "g_ncm",
2206c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.dev		= &device_desc,
2216c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.strings	= dev_strings,
22235a0e0bf6f6b2b900d461e9f35c286953b2b1afcTatyana Brokhman	.max_speed	= USB_SPEED_HIGH,
2236c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	.unbind		= __exit_p(gncm_unbind),
2246c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta};
2256c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2266c34d2888221ca3df81e29f598873b4fb6cf838dYauheni KaliutaMODULE_DESCRIPTION(DRIVER_DESC);
2276c34d2888221ca3df81e29f598873b4fb6cf838dYauheni KaliutaMODULE_AUTHOR("Yauheni Kaliuta");
2286c34d2888221ca3df81e29f598873b4fb6cf838dYauheni KaliutaMODULE_LICENSE("GPL");
2296c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2306c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic int __init init(void)
2316c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta{
2326c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	return usb_composite_probe(&ncm_driver, gncm_bind);
2336c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta}
2346c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutamodule_init(init);
2356c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta
2366c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutastatic void __exit cleanup(void)
2376c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta{
2386c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta	usb_composite_unregister(&ncm_driver);
2396c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliuta}
2406c34d2888221ca3df81e29f598873b4fb6cf838dYauheni Kaliutamodule_exit(cleanup);
241