/*! * generic_cf_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. * * @param void * @return void */ static void generic_cf_modexit (void) { int i; otg_trace_invalidate_tag(GENERIC); for (i = 0; ; i++) { struct generic_config *config = generic_configs + i; BREAK_UNLESS(config->interface_names); //printk(KERN_INFO"%s: %s registered: %d\n", // __FUNCTION__, config->composite_driver.driver.name, config->registered); CONTINUE_UNLESS(config->registered); usbd_deregister_composite_function (&config->composite_driver); if (config->interface_list) LKFREE(config->interface_list); } if (generic_config.registered) usbd_deregister_composite_function (&generic_config.composite_driver); if (generic_config.interface_list) LKFREE(generic_config.interface_list); }
/*! 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; }
/*! * 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; }
/*! arc_add_buffer_to_dtd * * C.f. 39.16.5.3 - case 1: Link list is empty */ static void arc_add_buffer_to_dtd (struct pcd_instance *pcd, struct usbd_endpoint_instance *endpoint, int dir, int len, int offset) { struct otg_instance *otg = pcd->otg; struct usbd_urb *urb = endpoint->active_urb; struct arc_private_struct *privdata = endpoint->privdata; u8 hs = pcd->bus->high_speed; u8 physicalEndpoint = endpoint->physicalEndpoint[hs]; u8 bEndpointAddress = endpoint->bEndpointAddress[hs]; u8 epnum = bEndpointAddress & 0x3f; u16 wMaxPacketSize = endpoint->wMaxPacketSize[hs]; struct ep_queue_head *dQH = &udc_controller->ep_qh[2 * epnum + dir]; struct ep_td_struct *dtd = &(udc_controller->ep_dtd[2 * epnum + dir]); u32 mask = 0; int timeout1 = 0; int timeout2 = 0; u32 endptstat = -1; u32 endptprime = -1; u32 endptcomplete = -1; TRACE_MSG6(pcd->TAG, "[%2d] USBCMD: %08x ENDPTPRIME: %08x COMPLETE: %08x STATUS: %08x %s", 2*epnum+dir, UOG_USBCMD, UOG_ENDPTPRIME, UOG_ENDPTCOMPLETE, (u32)dQH->size_ioc_int_sts, (dir == ARC_DIR_OUT) ? "OUT" : "IN"); if (urb && urb->buffer) { TRACE_MSG4(pcd->TAG, "buffer: %x length: %d alloc: %d dir: %d ", urb->buffer, urb->actual_length, urb->buffer_length, dir); /* flush cache for IN */ if ((dir == ARC_DIR_IN) && urb->actual_length) dma_cache_maint(urb->buffer, urb->actual_length, DMA_TO_DEVICE); /* invalidate cache for OUT */ else if ((dir == ARC_DIR_OUT) && urb->buffer_length) dma_cache_maint(urb->buffer, urb->alloc_length, DMA_FROM_DEVICE); } /* Set size and interrupt on each dtd, Clear reserved field, * set pointers and flush from cache, and save in cur_dqh for dtd_releases() */ memset(dtd, 0, sizeof(struct ep_td_struct)); dtd->size_ioc_sts = cpu_to_le32(((len << DTD_LENGTH_BIT_POS) | DTD_IOC | DTD_STATUS_ACTIVE)); dtd->size_ioc_sts &= cpu_to_le32(~DTD_RESERVED_FIELDS); dtd->buff_ptr0 = cpu_to_le32(endpoint->active_urb ? (u32) (virt_to_phys (endpoint->active_urb->buffer + offset)) : 0); dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE); dtd->next_td_virt = NULL; dma_cache_maint(dtd, sizeof(struct ep_td_struct), DMA_TO_DEVICE); privdata->cur_dqh = dQH; /* Case 1 - Step 1 - Write dQH next pointer and dQH terminate bit to 0 as single DWord */ dQH->next_dtd_ptr = cpu_to_le32( virt_to_phys((void *)dtd) & EP_QUEUE_HEAD_NEXT_POINTER_MASK); /* Case 1 - Step 2 - Clear active and halt bit */ dQH->size_ioc_int_sts &= le32_to_cpu(~(EP_QUEUE_HEAD_STATUS_ACTIVE | EP_QUEUE_HEAD_STATUS_HALT)); dma_cache_maint(dQH, sizeof(struct ep_queue_head), DMA_TO_DEVICE); /* Case 1 - Step 3 - Prime endpoint by writing ENDPTPRIME */ mask = (dir == ARC_DIR_OUT) ? (1 << epnum) : (1 << (epnum + 16)); /* Verify that endpoint PRIME is not set, wait if necessary. */ for (timeout1 = 0; (UOG_ENDPTPRIME & mask) && (timeout1 ++ < 100); udelay(1)); /* ep0 needs extra tests */ UNLESS(epnum) { /* C.f. 39.16.3.2.2 Data Phase */ UOG_ENDPTPRIME |= mask; for (timeout2 = 0; timeout2++ < 100; ) { endptprime = UOG_ENDPTPRIME; // order may be important endptstat = UOG_ENDPTSTAT; // we check stat after prime BREAK_IF(endptstat & mask); BREAK_UNLESS(endptprime & mask); } if (!(endptstat & mask) && !(endptprime & mask)) { TRACE_MSG2(pcd->TAG, "[%2d] ENDPTSETUPSTAT: %04x PREMATURE FAILUURE", 2*epnum+dir, UOG_ENDPTSETUPSTAT); } TRACE_MSG6(pcd->TAG, "[%2d] ENDPTPRIME %08x ENPTSTAT: %08x mask: %08x timeout: %d:%d SET", 2*epnum+dir, UOG_ENDPTPRIME, UOG_ENDPTSTAT, mask, timeout1, timeout2);; } /* epn general case */ else {