/** * Probe device * * @v func USB function * @v config Configuration descriptor * @ret rc Return status code */ static int acm_probe ( struct usb_function *func, struct usb_configuration_descriptor *config ) { struct usb_device *usb = func->usb; struct rndis_device *rndis; struct acm_device *acm; int rc; /* Allocate and initialise structure */ rndis = alloc_rndis ( sizeof ( *acm ) ); if ( ! rndis ) { rc = -ENOMEM; goto err_alloc; } rndis_init ( rndis, &acm_operations ); rndis->netdev->dev = &func->dev; acm = rndis->priv; acm->usb = usb; acm->bus = usb->port->hub->bus; acm->rndis = rndis; usbnet_init ( &acm->usbnet, func, &acm_intr_operations, &acm_in_operations, &acm_out_operations ); usb_refill_init ( &acm->usbnet.intr, 0, ACM_INTR_MAX_FILL ); usb_refill_init ( &acm->usbnet.in, ACM_IN_MTU, ACM_IN_MAX_FILL ); /* Describe USB network device */ if ( ( rc = usbnet_describe ( &acm->usbnet, config ) ) != 0 ) { DBGC ( acm, "ACM %p could not describe: %s\n", acm, strerror ( rc ) ); goto err_describe; } /* Register RNDIS device */ if ( ( rc = register_rndis ( rndis ) ) != 0 ) goto err_register; usb_func_set_drvdata ( func, acm ); return 0; unregister_rndis ( rndis ); err_register: err_describe: free_rndis ( rndis ); err_alloc: return rc; }
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer, struct eth_dev *dev) { struct f_rndis *rndis; int status; if (!can_support_rndis(c) || !ethaddr) return -EINVAL; /* setup RNDIS itself */ status = rndis_init(); if (status < 0) return status; if (rndis_string_defs[0].id == 0) { status = usb_string_ids_tab(c->cdev, rndis_string_defs); if (status) return status; rndis_control_intf.iInterface = rndis_string_defs[0].id; rndis_data_intf.iInterface = rndis_string_defs[1].id; rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; } /* allocate and initialize one new instance */ status = -ENOMEM; rndis = kzalloc(sizeof *rndis, GFP_KERNEL); if (!rndis) goto fail; __rndis = rndis; memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); rndis->vendorID = vendorID; rndis->manufacturer = manufacturer; rndis->port.ioport = dev; /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; /* RNDIS has special (and complex) framing */ rndis->port.header_len = sizeof(struct rndis_packet_msg_type); rndis->port.wrap = rndis_add_header; rndis->port.unwrap = rndis_rm_hdr; rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer; rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer; rndis->port.rx_trigger_enabled = rx_trigger_enabled; rndis->port.func.name = "rndis"; rndis->port.func.strings = rndis_strings; /* descriptors are per-instance copies */ rndis->port.func.bind = rndis_bind; rndis->port.func.unbind = rndis_unbind; rndis->port.func.set_alt = rndis_set_alt; rndis->port.func.setup = rndis_setup; rndis->port.func.disable = rndis_disable; status = usb_add_function(c, &rndis->port.func); if (status) { kfree(rndis); fail: rndis_exit(); } return status; }