📄 usbatm.c
字号:
static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user * arg){ struct usbatm_data *instance = atm_dev->dev_data; if (!instance || instance->disconnected) { dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance"); return -ENODEV; } switch (cmd) { case ATM_QUERYLOOP: return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; }}static int usbatm_atm_init(struct usbatm_data *instance){ struct atm_dev *atm_dev; int ret, i; /* ATM init. The ATM initialization scheme suffers from an intrinsic race * condition: callbacks we register can be executed at once, before we have * initialized the struct atm_dev. To protect against this, all callbacks * abort if atm_dev->dev_data is NULL. */ atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL); if (!atm_dev) { usb_err(instance, "%s: failed to register ATM device!\n", __func__); return -1; } instance->atm_dev = atm_dev; atm_dev->ci_range.vpi_bits = ATM_CI_MAX; atm_dev->ci_range.vci_bits = ATM_CI_MAX; atm_dev->signal = ATM_PHY_SIG_UNKNOWN; /* temp init ATM device, set to 128kbit */ atm_dev->link_rate = 128 * 1000 / 424; if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) { atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret); goto fail; } usbatm_get_instance(instance); /* dropped in usbatm_atm_dev_close */ /* ready for ATM callbacks */ mb(); atm_dev->dev_data = instance; /* submit all rx URBs */ for (i = 0; i < num_rcv_urbs; i++) usbatm_submit_urb(instance->urbs[i]); return 0; fail: instance->atm_dev = NULL; atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */ return ret;}/************ USB ************/static int usbatm_do_heavy_init(void *arg){ struct usbatm_data *instance = arg; int ret; daemonize(instance->driver->driver_name); allow_signal(SIGTERM); complete(&instance->thread_started); ret = instance->driver->heavy_init(instance, instance->usb_intf); if (!ret) ret = usbatm_atm_init(instance); mutex_lock(&instance->serialize); instance->thread_pid = -1; mutex_unlock(&instance->serialize); complete_and_exit(&instance->thread_exited, ret);}static int usbatm_heavy_init(struct usbatm_data *instance){ int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL); if (ret < 0) { usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret); return ret; } mutex_lock(&instance->serialize); instance->thread_pid = ret; mutex_unlock(&instance->serialize); wait_for_completion(&instance->thread_started); return 0;}static void usbatm_tasklet_schedule(unsigned long data){ tasklet_schedule((struct tasklet_struct *) data);}static inline void usbatm_init_channel(struct usbatm_channel *channel){ spin_lock_init(&channel->lock); INIT_LIST_HEAD(&channel->list); channel->delay.function = usbatm_tasklet_schedule; channel->delay.data = (unsigned long) &channel->tasklet; init_timer(&channel->delay);}int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, struct usbatm_driver *driver){ struct device *dev = &intf->dev; struct usb_device *usb_dev = interface_to_usbdev(intf); struct usbatm_data *instance; char *buf; int error = -ENOMEM; int i, length; unsigned int maxpacket, num_packets; dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n", __func__, driver->driver_name, le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), intf->altsetting->desc.bInterfaceNumber); /* instance init */ instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); if (!instance) { dev_err(dev, "%s: no memory for instance data!\n", __func__); return -ENOMEM; } /* public fields */ instance->driver = driver; snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name); instance->usb_dev = usb_dev; instance->usb_intf = intf; buf = instance->description; length = sizeof(instance->description); if ((i = usb_string(usb_dev, usb_dev->descriptor.iProduct, buf, length)) < 0) goto bind; buf += i; length -= i; i = scnprintf(buf, length, " ("); buf += i; length -= i; if (length <= 0 || (i = usb_make_path(usb_dev, buf, length)) < 0) goto bind; buf += i; length -= i; snprintf(buf, length, ")"); bind: if (driver->bind && (error = driver->bind(instance, intf, id)) < 0) { dev_err(dev, "%s: bind failed: %d!\n", __func__, error); goto fail_free; } /* private fields */ kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */ mutex_init(&instance->serialize); instance->thread_pid = -1; init_completion(&instance->thread_started); init_completion(&instance->thread_exited); INIT_LIST_HEAD(&instance->vcc_list); skb_queue_head_init(&instance->sndqueue); usbatm_init_channel(&instance->rx_channel); usbatm_init_channel(&instance->tx_channel); tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance); tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance); instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding; instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding; instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance; if ((instance->flags & UDSL_USE_ISOC) && driver->isoc_in) instance->rx_channel.endpoint = usb_rcvisocpipe(usb_dev, driver->isoc_in); else instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->bulk_in); instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->bulk_out); /* tx buffer size must be a positive multiple of the stride */ instance->tx_channel.buf_size = max (instance->tx_channel.stride, snd_buf_bytes - (snd_buf_bytes % instance->tx_channel.stride)); /* rx buffer size must be a positive multiple of the endpoint maxpacket */ maxpacket = usb_maxpacket(usb_dev, instance->rx_channel.endpoint, 0); if ((maxpacket < 1) || (maxpacket > UDSL_MAX_BUF_SIZE)) { dev_err(dev, "%s: invalid endpoint %02x!\n", __func__, usb_pipeendpoint(instance->rx_channel.endpoint)); error = -EINVAL; goto fail_unbind; } num_packets = max (1U, (rcv_buf_bytes + maxpacket / 2) / maxpacket); /* round */ if (num_packets * maxpacket > UDSL_MAX_BUF_SIZE) num_packets--; instance->rx_channel.buf_size = num_packets * maxpacket; instance->rx_channel.packet_size = maxpacket;#ifdef DEBUG for (i = 0; i < 2; i++) { struct usbatm_channel *channel = i ? &instance->tx_channel : &instance->rx_channel; dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel); }#endif /* initialize urbs */ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { u8 *buffer; struct usbatm_channel *channel = i < num_rcv_urbs ? &instance->rx_channel : &instance->tx_channel; struct urb *urb; unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0; UDSL_ASSERT(!usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint)); urb = usb_alloc_urb(iso_packets, GFP_KERNEL); if (!urb) { dev_err(dev, "%s: no memory for urb %d!\n", __func__, i); error = -ENOMEM; goto fail_unbind; } instance->urbs[i] = urb; /* zero the tx padding to avoid leaking information */ buffer = kzalloc(channel->buf_size, GFP_KERNEL); if (!buffer) { dev_err(dev, "%s: no memory for buffer %d!\n", __func__, i); error = -ENOMEM; goto fail_unbind; } usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint, buffer, channel->buf_size, usbatm_complete, channel); if (iso_packets) { int j; urb->interval = 1; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = iso_packets; for (j = 0; j < iso_packets; j++) { urb->iso_frame_desc[j].offset = channel->packet_size * j; urb->iso_frame_desc[j].length = channel->packet_size; } } /* put all tx URBs on the list of spares */ if (i >= num_rcv_urbs) list_add_tail(&urb->urb_list, &channel->list); vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p", __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); } instance->cached_vpi = ATM_VPI_UNSPEC; instance->cached_vci = ATM_VCI_UNSPEC; instance->cell_buf = kmalloc(instance->rx_channel.stride, GFP_KERNEL); if (!instance->cell_buf) { dev_err(dev, "%s: no memory for cell buffer!\n", __func__); error = -ENOMEM; goto fail_unbind; } if (!(instance->flags & UDSL_SKIP_HEAVY_INIT) && driver->heavy_init) { error = usbatm_heavy_init(instance); } else { complete(&instance->thread_exited); /* pretend that heavy_init was run */ error = usbatm_atm_init(instance); } if (error < 0) goto fail_unbind; usb_get_dev(usb_dev); usb_set_intfdata(intf, instance); return 0; fail_unbind: if (instance->driver->unbind) instance->driver->unbind(instance, intf); fail_free: kfree(instance->cell_buf); for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { if (instance->urbs[i]) kfree(instance->urbs[i]->transfer_buffer); usb_free_urb(instance->urbs[i]); } kfree (instance); return error;}EXPORT_SYMBOL_GPL(usbatm_usb_probe);void usbatm_usb_disconnect(struct usb_interface *intf){ struct device *dev = &intf->dev; struct usbatm_data *instance = usb_get_intfdata(intf); struct usbatm_vcc_data *vcc_data; int i; dev_dbg(dev, "%s entered\n", __func__); if (!instance) { dev_dbg(dev, "%s: NULL instance!\n", __func__); return; } usb_set_intfdata(intf, NULL); mutex_lock(&instance->serialize); instance->disconnected = 1; if (instance->thread_pid >= 0) kill_proc(instance->thread_pid, SIGTERM, 1); mutex_unlock(&instance->serialize); wait_for_completion(&instance->thread_exited); mutex_lock(&instance->serialize); list_for_each_entry(vcc_data, &instance->vcc_list, list) vcc_release_async(vcc_data->vcc, -EPIPE); mutex_unlock(&instance->serialize); tasklet_disable(&instance->rx_channel.tasklet); tasklet_disable(&instance->tx_channel.tasklet); for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) usb_kill_urb(instance->urbs[i]); del_timer_sync(&instance->rx_channel.delay); del_timer_sync(&instance->tx_channel.delay); /* turn usbatm_[rt]x_process into something close to a no-op */ /* no need to take the spinlock */ INIT_LIST_HEAD(&instance->rx_channel.list); INIT_LIST_HEAD(&instance->tx_channel.list); tasklet_enable(&instance->rx_channel.tasklet); tasklet_enable(&instance->tx_channel.tasklet); if (instance->atm_dev && instance->driver->atm_stop) instance->driver->atm_stop(instance, instance->atm_dev); if (instance->driver->unbind) instance->driver->unbind(instance, intf); instance->driver_data = NULL; for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { kfree(instance->urbs[i]->transfer_buffer); usb_free_urb(instance->urbs[i]); } kfree(instance->cell_buf); /* ATM finalize */ if (instance->atm_dev) atm_dev_deregister(instance->atm_dev); usbatm_put_instance(instance); /* taken in usbatm_usb_probe */}EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);/************* init *************/static int __init usbatm_usb_init(void){ dbg("%s: driver version %s", __func__, DRIVER_VERSION); if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) { printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name); return -EIO; } if ((num_rcv_urbs > UDSL_MAX_RCV_URBS) || (num_snd_urbs > UDSL_MAX_SND_URBS) || (rcv_buf_bytes < 1) || (rcv_buf_bytes > UDSL_MAX_BUF_SIZE) || (snd_buf_bytes < 1) || (snd_buf_bytes > UDSL_MAX_BUF_SIZE)) return -EINVAL; return 0;}module_init(usbatm_usb_init);static void __exit usbatm_usb_exit(void){ dbg("%s", __func__);}module_exit(usbatm_usb_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");MODULE_VERSION(DRIVER_VERSION);/************** debug **************/#ifdef VERBOSE_DEBUGstatic int usbatm_print_packet(const unsigned char *data, int len){ unsigned char buffer[256]; int i = 0, j = 0; for (i = 0; i < len;) { buffer[0] = '\0'; sprintf(buffer, "%.3d :", i); for (j = 0; (j < 16) && (i < len); j++, i++) { sprintf(buffer, "%s %2.2x", buffer, data[i]); } dbg("%s", buffer); } return i;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -