/*! net_fd_start_recv_ecm - start recv urb(s) * * @param function_instance - pointer to this function instance * @return none */ int net_fd_start_recv_ecm(struct usbd_function_instance *function_instance) { struct usb_network_private *npd = function_instance->privdata; int i; int network_start_urbs = NETWORK_START_URBS; int hs = usbd_high_speed(function_instance); int endpoint_index = BULK_OUT_A; if (hs) network_start_urbs = NETWORK_START_URBS * 3; for (i = 0; i < network_start_urbs; i++) { struct usbd_urb *urb; BREAK_IF(!(urb = usbd_alloc_urb(function_instance, endpoint_index, usbd_endpoint_transferSize(function_instance, endpoint_index, hs), net_fd_recv_urb))); TRACE_MSG5(NTT,"i: %d urb: %p priv: %p npd: %p function: %p", i, urb, urb->function_privdata, npd, function_instance); //urb->function_privdata = npd; if (usbd_start_out_urb(urb)) { urb->function_privdata = NULL; usbd_free_urb(urb); } } return 0; }
/*! * generic_cl_device_request - called to process a request to endpoint or interface * @param function * @param request * @return non-zero for failure, will cause endpoint zero stall */ static int generic_cl_device_request (struct usbd_function_instance *function, struct usbd_device_request *request) { TRACE_MSG5(GCLASS, "bmRequestType: %02x bRequest: %02x wValue: %04x wIndex: %04x wLength: %04x", request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength); return -EINVAL; }
/*! * inteltest_cl_device_request - called to process a request to endpoint or interface * @param function * @param request * @return non-zero for failure, will cause endpoint zero stall */ static int inteltest_cl_device_request (struct usbd_function_instance *function, struct usbd_device_request *request) { struct usbd_urb *urb; u16 wLength = le16_to_cpu(request->wLength); TRACE_MSG5(GCLASS, "bmRequestType: %02x bRequest: %02x wValue: %04x wIndex: %04x wLength: %04x", request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength); /* XXX it should be this, need to verify */ RETURN_EINVAL_UNLESS(USB_REQ_RECIPIENT_DEVICE == (request->bmRequestType & USB_REQ_RECIPIENT_MASK)); switch (ctrl->bRequest) { switch (request->bmRequestType & USB_REQ_DIRECTION_MASK) { case USB_REQ_DEVICE2HOST: switch (request->bRequest) { case 0x5c: /* read test */ RETURN_EINVAL_UNLESS((urb = usbd_alloc_urb_ep0 (function, wLength, NULL))); RETURN_ZERO_UNLESS(rc || usbd_start_in_urb(urb)); break; } break; case USB_REQ_HOST2DEVICE: switch (request->bRequest) { case 0x5b: /* write test */ RETURN_EINVAL_UNLESS((urb = usbd_alloc_urb_ep0 (function, wLength, NULL))); RETURN_ZERO_UNLESS(rc || usbd_start_out_urb(urb)); break; } break; } return -EINVAL; } /* ********************************************************************************************* */ #if !defined(OTG_C99) /*! function_ops - operations table for the USB Device Core */ static struct usbd_function_operations inteltest_function_ops; /*! inteltest_class_driver - USB Device Core function driver definition */ struct usbd_class_driver inteltest_class_driver; #else /* defined(OTG_C99) */ /*! function_ops - operations table for the USB Device Core */ static struct usbd_function_operations inteltest_function_ops = { .device_request = inteltest_cl_device_request, /*!< called for each received device request */ }; /*! inteltest_class_driver - USB Device Core function driver definition */ struct usbd_class_driver inteltest_class_driver = { .driver.name = "inteltest-class", /*!< driver name */ .driver.fops = &inteltest_function_ops, /*!< operations table */ }; #endif /* defined(OTG_C99) */ /* USB Module init/exit ***************************************************** */ //#if OTG_EPILOGUE /*! * inteltest_cl_modexit() - module init * * This is called by the Linux kernel; when the module is being unloaded * if compiled as a module. This function is never called if the * driver is linked into the kernel. * @return none */ static void inteltest_cl_modexit (void) { usbd_deregister_class_function (&inteltest_class_driver); otg_trace_invalidate_tag(GCLASS); } module_exit (inteltest_cl_modexit); //#endif /*! * inteltest_cl_modinit() - module init * * This is called by the Linux kernel; either when the module is loaded * if compiled as a module, or during the system intialization if the * driver is linked into the kernel. * * This function will parse module parameters if required and then register * the inteltest driver with the USB Device software. * */ static int inteltest_cl_modinit (void) { #if !defined(OTG_C99) /*! function_ops - operations table for the USB Device Core */ ZERO(inteltest_function_ops); inteltest_function_ops.device_request=inteltest_cl_device_request; /*! called for each received device request */ /*! class_driver - USB Device Core function driver definition */ ZERO(inteltest_class_driver); inteltest_class_driver.driver.name = "inteltest-class"; /*! driver name */ inteltest_class_driver.driver.fops = &inteltest_function_ops; /*! operations table */ #endif /* defined(OTG_C99) */ GCLASS = otg_trace_obtain_tag(NULL, "inteltest-cf"); // register as usb function driver TRACE_MSG0(GCLASS, "REGISTER CLASS"); THROW_IF (usbd_register_class_function (&inteltest_class_driver, "inteltest-class", NULL), error); TRACE_MSG0(GCLASS, "REGISTER FINISHED"); CATCH(error) { inteltest_cl_modexit(); return -EINVAL; } return 0; }
/*! * generic_cf_modinit() - module init * * This is called by the Linux kernel; either when the module is loaded * if compiled as a module, or during the system intialization if the * driver is linked into the kernel. * * This function will parse module parameters if required and then register * the generic driver with the USB Device software. * */ static int generic_cf_modinit (void) { int i; #if !defined(OTG_C99) //generic_cf_global_init(); #endif /* defined(OTG_C99) */ GENERIC = otg_trace_obtain_tag(); i = MODPARM(idVendor); printk (KERN_INFO "Model ID is %s",MODPARM(iProduct)); #if 0 TRACE_MSG4(GENERIC, "config_name: \"%s\" load_all: %d class_name: \"%s\" interface_names: \"%s\"", MODPARM(config_name) ? MODPARM(config_name) : "", MODPARM(load_all), MODPARM(class_name) ? MODPARM(class_name) : "", MODPARM(interface_names) ? MODPARM(interface_names) : ""); #else TRACE_MSG5(GENERIC, "config_name: \"%s\" load_all: %d class_name: \"%s\" interface_names: \"%s\" Serial: \"%s\"", generic_config_name(), MODPARM(load_all), MODPARM(class_name) ? MODPARM(class_name) : "", MODPARM(interface_names) ? MODPARM(interface_names) : "", MODPARM(iSerialNumber) ? MODPARM(iSerialNumber) : ""); #endif /* load config or configs */ if (preset_config_name() || MODPARM(load_all)) { if (preset_config_name()){ MODPARM(load_all) = 0; } printk (KERN_INFO "%s: config_name: \"%s\" load_all: %d\n", __FUNCTION__, generic_config_name() , MODPARM(load_all)); /* search for named config */ for (i = 0; ; i++) { struct generic_config *config = generic_configs + i; BREAK_UNLESS(config->interface_names); printk(KERN_INFO"%s: checking[%d] \"%s\"\n", __FUNCTION__, i, config->composite_driver.driver.name); if (MODPARM(iSerialNumber) && strlen(MODPARM(iSerialNumber)) && /* For the moment, we will only use serial number for msc and mtp. I suggest we come up with a more generic way to determine if a function driver needs to use the serial number. (for instance another function member. */ ( ( !strcmp(config->composite_driver.driver.name, "mtp")) || !strcmp(config->composite_driver.driver.name, "msc")) ){ config->device_description.iSerialNumber = MODPARM(iSerialNumber); } config->device_description.iProduct = MODPARM(iProduct); generic_cf_register(config, generic_config_name()); //printk(KERN_INFO"%s: loaded %s\n", __FUNCTION__, config->composite_driver.driver.name); } } else { struct generic_config *config = &generic_config; //printk (KERN_INFO "%s: idVendor: %04x idProduct: %04x\n", __FUNCTION__, MODPARM(idVendor), MODPARM(idProduct)); //printk (KERN_INFO "%s: class_name: \"%s\" _interface_names: \"%s\"\n", // __FUNCTION__, MODPARM(class_name), MODPARM(interface_names)); if (MODPARM(driver_name) && strlen(MODPARM(driver_name))) config->composite_driver.driver.name = MODPARM(driver_name); if (MODPARM(class_name) && strlen(MODPARM(class_name))) config->class_name = MODPARM(class_name); if (MODPARM(interface_names) && strlen(MODPARM(interface_names))) config->interface_names = MODPARM(interface_names); if (MODPARM(iConfiguration) && strlen(MODPARM(iConfiguration))) config->configuration_description.iConfiguration = MODPARM(iConfiguration); if (MODPARM(bDeviceClass)) config->device_description.bDeviceClass = MODPARM(bDeviceClass); if (MODPARM(bDeviceSubClass)) config->device_description.bDeviceSubClass = MODPARM(bDeviceSubClass); if (MODPARM(bDeviceProtocol)) config->device_description.bDeviceProtocol = MODPARM(bDeviceProtocol); if (MODPARM(idVendor)) config->device_description.idVendor = MODPARM(idVendor); else config->device_description.idVendor = CONFIG_OTG_GENERIC_VENDORID; if (MODPARM(idProduct)) config->device_description.idProduct = MODPARM(idProduct); else config->device_description.idProduct = CONFIG_OTG_GENERIC_PRODUCTID; if (MODPARM(bcdDevice)) config->device_description.bcdDevice = MODPARM(bcdDevice); else config->device_description.bcdDevice = CONFIG_OTG_GENERIC_BCDDEVICE; if (MODPARM(iManufacturer) && strlen(MODPARM(iManufacturer))) config->device_description.iManufacturer = MODPARM(iManufacturer); else config->device_description.iManufacturer = CONFIG_OTG_GENERIC_MANUFACTURER; if (MODPARM(iProduct) && strlen(MODPARM(iProduct))) config->device_description.iProduct = MODPARM(iProduct); else config->device_description.iProduct = CONFIG_OTG_GENERIC_PRODUCT_NAME; if (MODPARM(iSerialNumber) && strlen(MODPARM(iSerialNumber))){ config->device_description.iSerialNumber = MODPARM(iSerialNumber); } if (MODPARM(interface_names)) config->interface_names = MODPARM(interface_names); generic_cf_register(config, NULL); } return 0; }
/*! * generic_cf_register() * */ void generic_cf_register(struct generic_config *config, char *match) { char *cp, *sp, *lp; int i; char **interface_list = NULL; int interfaces = 0; //printk(KERN_INFO"%s: Driver: \"%s\" idVendor: %04x idProduct: %04x interface_names: \"%s\" match: \"%s\"\n", // __FUNCTION__, // config->composite_driver.driver.name, MODPARM(idVendor), MODPARM(idProduct), config->interface_names, // match ? match : ""); TRACE_MSG5(GENERIC, "Driver: \"%s\" idVendor: %04x idProduct: %04x interface_names: \"%s\" match: \"%s\"", config->composite_driver.driver.name, MODPARM(idVendor), MODPARM(idProduct), config->interface_names, match ? match : ""); RETURN_IF (match && strlen(match) && strcmp(match, config->composite_driver.driver.name)); //printk(KERN_INFO"%s: MATCHED\n", __FUNCTION__); /* decompose interface names to construct interface_list */ RETURN_UNLESS (config->interface_names && strlen(config->interface_names)); /* count interface names and allocate _interface_names array */ for (cp = sp = config->interface_names, interfaces = 0; cp && *cp; ) { for (; *cp && *cp == ':'; cp++); // skip white space sp = cp; // save start of token for (; *cp && *cp != ':'; cp++); // find end of token BREAK_IF (sp == cp); if (*cp) cp++; interfaces++; } THROW_UNLESS(interfaces, error); TRACE_MSG1(GENERIC, "interfaces: %d", interfaces); THROW_UNLESS((interface_list = (char **) CKMALLOC (sizeof (char *) * (interfaces + 1), GFP_KERNEL)), error); for (cp = sp = config->interface_names, interfaces = 0; cp && *cp; interfaces++) { for (; *cp && *cp == ':'; cp++); // skip white space sp = cp; // save start of token for (; *cp && *cp != ':'; cp++); // find end of token BREAK_IF (sp == cp); lp = cp; if (*cp) cp++; *lp = '\0'; lp = CKMALLOC(strlen(sp), GFP_KERNEL); strcpy(lp, sp); interface_list[interfaces] = lp; TRACE_MSG3(GENERIC, "INTERFACE[%2d] %x \"%s\"", interfaces, interface_list[interfaces], interface_list[interfaces]); } config->composite_driver.device_description = &config->device_description; config->composite_driver.configuration_description = &config->configuration_description; config->composite_driver.driver.fops = &generic_function_ops; config->interface_list = interface_list; THROW_IF (usbd_register_composite_function ( &config->composite_driver, config->composite_driver.driver.name, config->class_name, config->interface_list, NULL), error); config->registered++; TRACE_MSG0(GENERIC, "REGISTER FINISHED"); CATCH(error) { otg_trace_invalidate_tag(GENERIC); } }
/*! blan_fd_device_request * @brief process a received SETUP URB * * Processes a received setup packet and CONTROL WRITE data. * Results for a CONTROL READ are placed in urb->buffer. * * @param function_instance - pointer to this function instance * @param request - received request to interface or endpoint * @return non-zero for failure. */ int blan_fd_device_request (struct usbd_function_instance *function_instance, struct usbd_device_request *request) { struct usb_network_private *npd = function_instance->privdata; struct usbd_urb *urb; int index; /* Verify that this is a USB Class request per CDC specification or a vendor request. */ RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR))); /* Determine the request direction and process accordingly */ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) { case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR: switch (request->bRequest) { case MCCI_ENABLE_CRC: //if (make_crc_table()) // return -EINVAL; //npd->encapsulation = simple_crc; return 0; case BELCARRA_PING: TRACE_MSG1(NTT,"H2D VENDOR IP: %08x", npd->ip_addr); if ((npd->network_type == network_blan)) net_os_send_notification_later(function_instance); break; #if !defined(CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME) || !defined(CONFIG_OTG_NETWORK_SAFE_DO_NOT_SETTIME) case BELCARRA_SETTIME: npd->rfc868time = ntohl( request->wValue << 16 | request->wIndex); net_os_settime(function_instance, npd->rfc868time); break; #endif case BELCARRA_SETIP: #ifdef OTG_BIG_ENDIAN npd->ip_addr = ntohl( request->wValue | request->wIndex<< 16 ); #else /* OTG_BIG_ENDIAN */ npd->ip_addr = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ TRACE_MSG1(NTT, "npd->ip_addr: %08x", npd->ip_addr); // XXX need to get in correct order here // XXX what about locally set mac addr // XXX UNLESS(npd->local_dev_set) { if (!(npd->override_MAC)) { npd->local_dev_addr[0] = 0xfe | 0x02; /* locally administered */ npd->local_dev_addr[1] = 0x00; npd->local_dev_addr[2] = (npd->ip_addr >> 24) & 0xff; npd->local_dev_addr[3] = (npd->ip_addr >> 16) & 0xff; npd->local_dev_addr[4] = (npd->ip_addr >> 8) & 0xff; npd->local_dev_addr[5] = (npd->ip_addr >> 0) & 0xff; } // XXX } break; case BELCARRA_SETMSK: #ifdef OTG_BIG_ENDIAN npd->network_mask = ntohl( request->wValue | request->wIndex << 16); #else /* OTG_BIG_ENDIAN */ npd->network_mask = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ TRACE_MSG1(NTT, "npd->network_mask: %08x", npd->network_mask); break; case BELCARRA_SETROUTER: #ifdef OTG_BIG_ENDIAN npd->router_ip = ntohl( request->wValue | request->wIndex << 16); #else /* OTG_BIG_ENDIAN */ npd->router_ip = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ TRACE_MSG1(NTT, "npd->router_ip: %08x", npd->router_ip); break; case BELCARRA_SETDNS: #ifdef OTG_BIG_ENDIAN npd->dns_server_ip = ntohl( request->wValue | request->wIndex < 16); #else /* OTG_BIG_ENDIAN */ npd->dns_server_ip = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ break; #ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT case BELCARRA_SETFERMAT: npd->fermat = 1; break; #endif #ifdef CONFIG_OTG_NETWORK_BLAN_HOSTNAME case BELCARRA_HOSTNAME: TRACE_MSG0(NTT,"HOSTNAME"); RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function_instance, le16_to_cpu(request->wLength), blant_fd_urb_received_ep0) )); RETURN_ZERO_IF(!usbd_start_out_urb(urb)); // return if no error usbd_free_urb(urb); // de-alloc if error return -EINVAL; #endif #ifdef CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK case BELCARRA_DATA_NOTIFY: TRACE_MSG0(NTT,"DATA NOTIFY"); npd->data_notify = 1; return -EINVAL; #endif } switch (request->bRequest) { case BELCARRA_SETIP: case BELCARRA_SETMSK: case BELCARRA_SETROUTER: TRACE_MSG5(NTT, "npd->network_mask: %08x npd->ip_addr: %08x npd->router_ip: %08x flags: %08x %s", npd->network_mask, npd->ip_addr, npd->router_ip, npd->flags, (npd->flags & NETWORK_CONFIGURED) ? "CONFIGURED" : ""); BREAK_UNLESS (npd->network_mask && npd->ip_addr && npd->router_ip && (npd->flags & NETWORK_CONFIGURED)); // let the os layer know, if it's interested. #ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG net_os_config(function_instance); net_os_hotplug(function_instance); #endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */ break; } return 0; default: break; }
/*! * otg_pci_probe() - otg pci probe function * * Get the standard PCI resources allocated. * */ int __devinit otg_pci_probe (struct pci_dev *pci_dev, const struct pci_device_id *id, struct otg_pci_driver *otg_pci_driver) { struct otg_driver *otg_driver; struct otg_dev *otg_dev = NULL; int enabled = 0; int irq = 0; int region; u8 latency, limit; /* allocate otg_dev structure and fill in standard fields */ THROW_UNLESS((otg_dev = kmalloc(sizeof(struct otg_dev), SLAB_KERNEL)), error); memset(otg_dev, 0, sizeof(struct otg_dev)); otg_dev->PCI = otg_trace_obtain_tag(); //printk(KERN_INFO"%s: PCI %d\n", __FUNCTION__, otg_dev->PCI); //TRACE_MSG0(otg_dev->PCI, "TEST"); THROW_UNLESS((enabled = !pci_enable_device(pci_dev)), error); otg_dev->otg_pci_driver = otg_pci_driver; otg_dev->pci_regions = otg_pci_driver->pci_regions; pci_set_drvdata(pci_dev, otg_dev); printk(KERN_INFO"%s: pci_dev: %x otg_dev: %x drv_data: %x\n", __FUNCTION__, pci_dev, otg_dev, pci_get_drvdata(pci_dev)); for (region = 0; region < DEVICE_COUNT_RESOURCE; region++) { unsigned long resource_start; unsigned long resource_len; TRACE_MSG5(otg_dev->PCI, "[%2d] flags: %08x start: %08x end: %08x len: %08x", region, pci_resource_flags(pci_dev, region), pci_resource_start(pci_dev, region), pci_resource_end(pci_dev, region), pci_resource_len(pci_dev, region) ); CONTINUE_UNLESS(otg_dev->pci_regions & (1 << region)); resource_start = pci_resource_start(pci_dev, region); resource_len = pci_resource_len(pci_dev, region); TRACE_MSG5(otg_dev->PCI, "pci_dev: %x otg_dev: %x start: %lx len: %lx name: %s", pci_dev, otg_dev, resource_start, resource_len, otg_pci_driver->name); THROW_UNLESS(request_mem_region(resource_start, resource_len, otg_pci_driver->name), error); THROW_UNLESS((otg_dev->regs[region] = ioremap_nocache(resource_start, resource_len)), error); TRACE_MSG2(otg_dev->PCI, "regs[%d] %x", region, otg_dev->regs[region]); } THROW_UNLESS((irq = !request_irq(pci_dev->irq, otg_pci_isr, SA_SHIRQ, otg_pci_driver->name, pci_dev)), error); TRACE_MSG1(otg_dev->PCI, "irq: %d", pci_dev->irq); /* bad pci latencies can contribute to overruns - but where ?? */ pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &latency); pci_read_config_byte (pci_dev, PCI_MAX_LAT, &limit); TRACE_MSG2(otg_dev->PCI, "latency: %02x limit: %02x", latency, limit); if (latency && /* limit &&*/ (limit < latency)) { pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, limit); pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &latency); TRACE_MSG2(otg_dev->PCI, "latency: %02x limit: %02x", latency, limit); } /* XXX lock? */ otg_dev->id = otg_get_id(pci_dev); TRACE_MSG1(otg_dev->PCI, "id: %d", otg_dev->id); if (otg_devs) { TRACE_MSG2(otg_dev->PCI, "otg_devs: %x new: %x", otg_devs, otg_dev); otg_dev->next = otg_devs; } otg_devs = otg_dev; return 0; CATCH(error) { printk(KERN_INFO"%s: FAILED\n", __FUNCTION__); pci_set_drvdata(pci_dev, NULL); if (irq) free_irq(pci_dev->irq, otg_dev); otg_pci_free_dev(pci_dev, otg_dev); if (otg_dev) kfree(otg_dev); if (enabled) pci_disable_device(pci_dev); return -EINVAL; } }