diff options
Diffstat (limited to 'drivers/usb/gadget/nokia.c')
| -rw-r--r-- | drivers/usb/gadget/nokia.c | 275 |
1 files changed, 202 insertions, 73 deletions
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 661600abace..3ab38616751 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -16,11 +16,13 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/device.h> #include "u_serial.h" #include "u_ether.h" #include "u_phonet.h" +#include "u_ecm.h" #include "gadget_chips.h" /* Defines */ @@ -28,26 +30,10 @@ #define NOKIA_VERSION_NUM 0x0211 #define NOKIA_LONG_NAME "N900 (PC-Suite Mode)" -/*-------------------------------------------------------------------------*/ - -/* - * 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 "u_serial.c" -#include "f_acm.c" -#include "f_ecm.c" -#include "f_obex.c" -#include "f_serial.c" -#include "f_phonet.c" -#include "u_ether.c" - -/*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); +USB_ETHERNET_MODULE_PARAMETERS(); + #define NOKIA_VENDOR_ID 0x0421 /* Nokia */ #define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ @@ -98,42 +84,24 @@ MODULE_AUTHOR("Felipe Balbi"); MODULE_LICENSE("GPL"); /*-------------------------------------------------------------------------*/ +static struct usb_function *f_acm_cfg1; +static struct usb_function *f_acm_cfg2; +static struct usb_function *f_ecm_cfg1; +static struct usb_function *f_ecm_cfg2; +static struct usb_function *f_obex1_cfg1; +static struct usb_function *f_obex2_cfg1; +static struct usb_function *f_obex1_cfg2; +static struct usb_function *f_obex2_cfg2; +static struct usb_function *f_phonet_cfg1; +static struct usb_function *f_phonet_cfg2; -static u8 hostaddr[ETH_ALEN]; - -static int __init nokia_bind_config(struct usb_configuration *c) -{ - int status = 0; - - status = phonet_bind_config(c); - if (status) - printk(KERN_DEBUG "could not bind phonet config\n"); - - status = obex_bind_config(c, 0); - if (status) - printk(KERN_DEBUG "could not bind obex config %d\n", 0); - - status = obex_bind_config(c, 1); - if (status) - printk(KERN_DEBUG "could not bind obex config %d\n", 0); - - status = acm_bind_config(c, 2); - if (status) - printk(KERN_DEBUG "could not bind acm config\n"); - - status = ecm_bind_config(c, hostaddr); - if (status) - printk(KERN_DEBUG "could not bind ecm config\n"); - - return status; -} static struct usb_configuration nokia_config_500ma_driver = { .label = "Bus Powered", .bConfigurationValue = 1, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = 250, /* 500mA */ + .MaxPower = 500, }; static struct usb_configuration nokia_config_100ma_driver = { @@ -141,26 +109,126 @@ static struct usb_configuration nokia_config_100ma_driver = { .bConfigurationValue = 2, /* .iConfiguration = DYNAMIC */ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 50, /* 100 mA */ + .MaxPower = 100, }; +static struct usb_function_instance *fi_acm; +static struct usb_function_instance *fi_ecm; +static struct usb_function_instance *fi_obex1; +static struct usb_function_instance *fi_obex2; +static struct usb_function_instance *fi_phonet; + +static int __init nokia_bind_config(struct usb_configuration *c) +{ + struct usb_function *f_acm; + struct usb_function *f_phonet = NULL; + struct usb_function *f_obex1 = NULL; + struct usb_function *f_ecm; + struct usb_function *f_obex2 = NULL; + int status = 0; + int obex1_stat = -1; + int obex2_stat = -1; + int phonet_stat = -1; + + if (!IS_ERR(fi_phonet)) { + f_phonet = usb_get_function(fi_phonet); + if (IS_ERR(f_phonet)) + pr_debug("could not get phonet function\n"); + } + + if (!IS_ERR(fi_obex1)) { + f_obex1 = usb_get_function(fi_obex1); + if (IS_ERR(f_obex1)) + pr_debug("could not get obex function 0\n"); + } + + if (!IS_ERR(fi_obex2)) { + f_obex2 = usb_get_function(fi_obex2); + if (IS_ERR(f_obex2)) + pr_debug("could not get obex function 1\n"); + } + + f_acm = usb_get_function(fi_acm); + if (IS_ERR(f_acm)) { + status = PTR_ERR(f_acm); + goto err_get_acm; + } + + f_ecm = usb_get_function(fi_ecm); + if (IS_ERR(f_ecm)) { + status = PTR_ERR(f_ecm); + goto err_get_ecm; + } + + if (!IS_ERR_OR_NULL(f_phonet)) { + phonet_stat = usb_add_function(c, f_phonet); + if (phonet_stat) + pr_debug("could not add phonet function\n"); + } + + if (!IS_ERR_OR_NULL(f_obex1)) { + obex1_stat = usb_add_function(c, f_obex1); + if (obex1_stat) + pr_debug("could not add obex function 0\n"); + } + + if (!IS_ERR_OR_NULL(f_obex2)) { + obex2_stat = usb_add_function(c, f_obex2); + if (obex2_stat) + pr_debug("could not add obex function 1\n"); + } + + status = usb_add_function(c, f_acm); + if (status) + goto err_conf; + + status = usb_add_function(c, f_ecm); + if (status) { + pr_debug("could not bind ecm config %d\n", status); + goto err_ecm; + } + if (c == &nokia_config_500ma_driver) { + f_acm_cfg1 = f_acm; + f_ecm_cfg1 = f_ecm; + f_phonet_cfg1 = f_phonet; + f_obex1_cfg1 = f_obex1; + f_obex2_cfg1 = f_obex2; + } else { + f_acm_cfg2 = f_acm; + f_ecm_cfg2 = f_ecm; + f_phonet_cfg2 = f_phonet; + f_obex1_cfg2 = f_obex1; + f_obex2_cfg2 = f_obex2; + } + + return status; +err_ecm: + usb_remove_function(c, f_acm); +err_conf: + if (!obex2_stat) + usb_remove_function(c, f_obex2); + if (!obex1_stat) + usb_remove_function(c, f_obex1); + if (!phonet_stat) + usb_remove_function(c, f_phonet); + usb_put_function(f_ecm); +err_get_ecm: + usb_put_function(f_acm); +err_get_acm: + if (!IS_ERR_OR_NULL(f_obex2)) + usb_put_function(f_obex2); + if (!IS_ERR_OR_NULL(f_obex1)) + usb_put_function(f_obex1); + if (!IS_ERR_OR_NULL(f_phonet)) + usb_put_function(f_phonet); + return status; +} + static int __init nokia_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; int status; - status = gphonet_setup(cdev->gadget); - if (status < 0) - goto err_phonet; - - status = gserial_setup(cdev->gadget, 3); - if (status < 0) - goto err_serial; - - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - goto err_ether; - status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto err_usb; @@ -170,40 +238,102 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) nokia_config_500ma_driver.iConfiguration = status; nokia_config_100ma_driver.iConfiguration = status; - if (!gadget_supports_altsettings(gadget)) + if (!gadget_supports_altsettings(gadget)) { + status = -ENODEV; goto err_usb; + } + + fi_phonet = usb_get_function_instance("phonet"); + if (IS_ERR(fi_phonet)) + pr_debug("could not find phonet function\n"); + + fi_obex1 = usb_get_function_instance("obex"); + if (IS_ERR(fi_obex1)) + pr_debug("could not find obex function 1\n"); + + fi_obex2 = usb_get_function_instance("obex"); + if (IS_ERR(fi_obex2)) + pr_debug("could not find obex function 2\n"); + + fi_acm = usb_get_function_instance("acm"); + if (IS_ERR(fi_acm)) { + status = PTR_ERR(fi_acm); + goto err_obex2_inst; + } + + fi_ecm = usb_get_function_instance("ecm"); + if (IS_ERR(fi_ecm)) { + status = PTR_ERR(fi_ecm); + goto err_acm_inst; + } /* finally register the configuration */ status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) - goto err_usb; + goto err_ecm_inst; status = usb_add_config(cdev, &nokia_config_100ma_driver, nokia_bind_config); if (status < 0) - goto err_usb; + goto err_put_cfg1; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); return 0; +err_put_cfg1: + usb_put_function(f_acm_cfg1); + if (!IS_ERR_OR_NULL(f_obex1_cfg1)) + usb_put_function(f_obex1_cfg1); + if (!IS_ERR_OR_NULL(f_obex2_cfg1)) + usb_put_function(f_obex2_cfg1); + if (!IS_ERR_OR_NULL(f_phonet_cfg1)) + usb_put_function(f_phonet_cfg1); + usb_put_function(f_ecm_cfg1); +err_ecm_inst: + usb_put_function_instance(fi_ecm); +err_acm_inst: + usb_put_function_instance(fi_acm); +err_obex2_inst: + if (!IS_ERR(fi_obex2)) + usb_put_function_instance(fi_obex2); + if (!IS_ERR(fi_obex1)) + usb_put_function_instance(fi_obex1); + if (!IS_ERR(fi_phonet)) + usb_put_function_instance(fi_phonet); err_usb: - gether_cleanup(); -err_ether: - gserial_cleanup(); -err_serial: - gphonet_cleanup(); -err_phonet: return status; } static int __exit nokia_unbind(struct usb_composite_dev *cdev) { - gphonet_cleanup(); - gserial_cleanup(); - gether_cleanup(); + if (!IS_ERR_OR_NULL(f_obex1_cfg2)) + usb_put_function(f_obex1_cfg2); + if (!IS_ERR_OR_NULL(f_obex2_cfg2)) + usb_put_function(f_obex2_cfg2); + if (!IS_ERR_OR_NULL(f_obex1_cfg1)) + usb_put_function(f_obex1_cfg1); + if (!IS_ERR_OR_NULL(f_obex2_cfg1)) + usb_put_function(f_obex2_cfg1); + if (!IS_ERR_OR_NULL(f_phonet_cfg1)) + usb_put_function(f_phonet_cfg1); + if (!IS_ERR_OR_NULL(f_phonet_cfg2)) + usb_put_function(f_phonet_cfg2); + usb_put_function(f_acm_cfg1); + usb_put_function(f_acm_cfg2); + usb_put_function(f_ecm_cfg1); + usb_put_function(f_ecm_cfg2); + + usb_put_function_instance(fi_ecm); + if (!IS_ERR(fi_obex2)) + usb_put_function_instance(fi_obex2); + if (!IS_ERR(fi_obex1)) + usb_put_function_instance(fi_obex1); + if (!IS_ERR(fi_phonet)) + usb_put_function_instance(fi_phonet); + usb_put_function_instance(fi_acm); return 0; } @@ -228,4 +358,3 @@ static void __exit nokia_cleanup(void) usb_composite_unregister(&nokia_driver); } module_exit(nokia_cleanup); - |
