📄 usbatm.c
字号:
clear_bit(ATM_VF_READY, &vcc->flags); clear_bit(ATM_VF_PARTIAL, &vcc->flags); clear_bit(ATM_VF_ADDR, &vcc->flags); up(&instance->serialize); atm_dbg(instance, "%s successful\n", __func__);}static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg){ 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 */ atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL); if (!atm_dev) { usb_dbg(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_dbg(instance, "%s: atm_start failed: %d!\n", __func__, ret); goto fail; } /* ready for ATM callbacks */ usbatm_get_instance(instance); /* dropped in usbatm_atm_dev_close */ 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; shutdown_atm_dev(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); down(&instance->serialize); instance->thread_pid = -1; up(&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_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret); return ret; } down(&instance->serialize); instance->thread_pid = ret; up(&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; int need_heavy; dev_dbg(dev, "%s: trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\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_dbg(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: need_heavy = 1; if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) { dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error); goto fail_free; } /* private fields */ kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */ init_MUTEX(&instance->serialize); instance->thread_pid = -1; init_completion(&instance->thread_started); init_completion(&instance->thread_exited); INIT_LIST_HEAD(&instance->vcc_list); 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.endpoint = usb_rcvbulkpipe(usb_dev, driver->in); instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out); instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding; instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding; instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride; instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride; instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance; skb_queue_head_init(&instance->sndqueue); for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { struct urb *urb; u8 *buffer; unsigned int iso_packets = 0, iso_size = 0; struct usbatm_channel *channel = i < num_rcv_urbs ? &instance->rx_channel : &instance->tx_channel; if (usb_pipeisoc(channel->endpoint)) { /* don't expect iso out endpoints */ iso_size = usb_maxpacket(instance->usb_dev, channel->endpoint, 0); iso_size -= iso_size % channel->stride; /* alignment */ BUG_ON(!iso_size); iso_packets = (channel->buf_size - 1) / iso_size + 1; } urb = usb_alloc_urb(iso_packets, GFP_KERNEL); if (!urb) { dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i); goto fail_unbind; } instance->urbs[i] = urb; buffer = kmalloc(channel->buf_size, GFP_KERNEL); if (!buffer) { dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i); goto fail_unbind; } memset(buffer, 0, channel->buf_size); 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 = iso_size * j; urb->iso_frame_desc[j].length = min_t(int, iso_size, channel->buf_size - urb->iso_frame_desc[j].offset); } } /* 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); } if (need_heavy && 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: 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); 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); down(&instance->serialize); if (instance->thread_pid >= 0) kill_proc(instance->thread_pid, SIGTERM, 1); up(&instance->serialize); wait_for_completion(&instance->thread_exited); 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); 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; /* turn usbatm_[rt]x_process into noop */ /* 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); for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { kfree(instance->urbs[i]->transfer_buffer); usb_free_urb(instance->urbs[i]); } /* ATM finalize */ if (instance->atm_dev) shutdown_atm_dev(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_size < 1) || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE) || (snd_buf_size < 1) || (snd_buf_size > UDSL_MAX_SND_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 + -