Loading drivers/usb/class/cdc-acm.c +77 −15 Original line number Diff line number Diff line Loading @@ -496,10 +496,19 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) otherwise it is scheduled, and with high data rates data can get lost. */ tty->low_latency = 1; if (usb_autopm_get_interface(acm->control)) { mutex_unlock(&open_mutex); return -EIO; } mutex_lock(&acm->mutex); mutex_unlock(&open_mutex); if (acm->used++) { usb_autopm_put_interface(acm->control); goto done; } acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { dbg("usb_submit_urb(ctrl irq) failed"); Loading @@ -526,14 +535,15 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) done: err_out: mutex_unlock(&open_mutex); mutex_unlock(&acm->mutex); return rv; full_bailout: usb_kill_urb(acm->ctrlurb); bail_out: usb_autopm_put_interface(acm->control); acm->used--; mutex_unlock(&open_mutex); mutex_unlock(&acm->mutex); return -EIO; } Loading Loading @@ -570,6 +580,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->writeurb); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); usb_autopm_put_interface(acm->control); } else acm_tty_unregister(acm); } Loading Loading @@ -980,6 +991,7 @@ static int acm_probe (struct usb_interface *intf, spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->write_ready = 1; acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); Loading Loading @@ -1096,6 +1108,25 @@ static int acm_probe (struct usb_interface *intf, return -ENOMEM; } static void stop_data_traffic(struct acm *acm) { int i; tasklet_disable(&acm->urb_task); usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); for (i = 0; i < acm->rx_buflimit; i++) usb_kill_urb(acm->ru[i].urb); INIT_LIST_HEAD(&acm->filled_read_bufs); INIT_LIST_HEAD(&acm->spare_read_bufs); tasklet_enable(&acm->urb_task); cancel_work_sync(&acm->work); } static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); Loading Loading @@ -1123,19 +1154,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->data, NULL); tasklet_disable(&acm->urb_task); usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); for (i = 0; i < acm->rx_buflimit; i++) usb_kill_urb(acm->ru[i].urb); INIT_LIST_HEAD(&acm->filled_read_bufs); INIT_LIST_HEAD(&acm->spare_read_bufs); tasklet_enable(&acm->urb_task); flush_scheduled_work(); /* wait for acm_softint */ stop_data_traffic(acm); acm_write_buffers_free(acm); usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); Loading @@ -1156,6 +1175,46 @@ static void acm_disconnect(struct usb_interface *intf) tty_hangup(acm->tty); } static int acm_suspend(struct usb_interface *intf, pm_message_t message) { struct acm *acm = usb_get_intfdata(intf); if (acm->susp_count++) return 0; /* we treat opened interfaces differently, we must guard against open */ mutex_lock(&acm->mutex); if (acm->used) stop_data_traffic(acm); mutex_unlock(&acm->mutex); return 0; } static int acm_resume(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); int rv = 0; if (--acm->susp_count) return 0; mutex_lock(&acm->mutex); if (acm->used) { rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); if (rv < 0) goto err_out; tasklet_schedule(&acm->urb_task); } err_out: mutex_unlock(&acm->mutex); return rv; } /* * USB driver structure. */ Loading Loading @@ -1208,7 +1267,10 @@ static struct usb_driver acm_driver = { .name = "cdc_acm", .probe = acm_probe, .disconnect = acm_disconnect, .suspend = acm_suspend, .resume = acm_resume, .id_table = acm_ids, .supports_autosuspend = 1, }; /* Loading drivers/usb/class/cdc-acm.h +2 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ struct acm { int write_used; /* number of non-empty write buffers */ int write_ready; /* write urb is not running */ spinlock_t write_lock; struct mutex mutex; struct usb_cdc_line_coding line; /* bits, stop, parity */ struct work_struct work; /* work queue entry for line discipline waking up */ struct tasklet_struct urb_task; /* rx processing */ Loading @@ -120,6 +121,7 @@ struct acm { unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ unsigned int susp_count; /* number of suspended interfaces */ }; #define CDC_DATA_INTERFACE_TYPE 0x0a Loading Loading
drivers/usb/class/cdc-acm.c +77 −15 Original line number Diff line number Diff line Loading @@ -496,10 +496,19 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) otherwise it is scheduled, and with high data rates data can get lost. */ tty->low_latency = 1; if (usb_autopm_get_interface(acm->control)) { mutex_unlock(&open_mutex); return -EIO; } mutex_lock(&acm->mutex); mutex_unlock(&open_mutex); if (acm->used++) { usb_autopm_put_interface(acm->control); goto done; } acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { dbg("usb_submit_urb(ctrl irq) failed"); Loading @@ -526,14 +535,15 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) done: err_out: mutex_unlock(&open_mutex); mutex_unlock(&acm->mutex); return rv; full_bailout: usb_kill_urb(acm->ctrlurb); bail_out: usb_autopm_put_interface(acm->control); acm->used--; mutex_unlock(&open_mutex); mutex_unlock(&acm->mutex); return -EIO; } Loading Loading @@ -570,6 +580,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->writeurb); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); usb_autopm_put_interface(acm->control); } else acm_tty_unregister(acm); } Loading Loading @@ -980,6 +991,7 @@ static int acm_probe (struct usb_interface *intf, spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->write_ready = 1; acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); Loading Loading @@ -1096,6 +1108,25 @@ static int acm_probe (struct usb_interface *intf, return -ENOMEM; } static void stop_data_traffic(struct acm *acm) { int i; tasklet_disable(&acm->urb_task); usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); for (i = 0; i < acm->rx_buflimit; i++) usb_kill_urb(acm->ru[i].urb); INIT_LIST_HEAD(&acm->filled_read_bufs); INIT_LIST_HEAD(&acm->spare_read_bufs); tasklet_enable(&acm->urb_task); cancel_work_sync(&acm->work); } static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); Loading Loading @@ -1123,19 +1154,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->data, NULL); tasklet_disable(&acm->urb_task); usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); for (i = 0; i < acm->rx_buflimit; i++) usb_kill_urb(acm->ru[i].urb); INIT_LIST_HEAD(&acm->filled_read_bufs); INIT_LIST_HEAD(&acm->spare_read_bufs); tasklet_enable(&acm->urb_task); flush_scheduled_work(); /* wait for acm_softint */ stop_data_traffic(acm); acm_write_buffers_free(acm); usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); Loading @@ -1156,6 +1175,46 @@ static void acm_disconnect(struct usb_interface *intf) tty_hangup(acm->tty); } static int acm_suspend(struct usb_interface *intf, pm_message_t message) { struct acm *acm = usb_get_intfdata(intf); if (acm->susp_count++) return 0; /* we treat opened interfaces differently, we must guard against open */ mutex_lock(&acm->mutex); if (acm->used) stop_data_traffic(acm); mutex_unlock(&acm->mutex); return 0; } static int acm_resume(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); int rv = 0; if (--acm->susp_count) return 0; mutex_lock(&acm->mutex); if (acm->used) { rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); if (rv < 0) goto err_out; tasklet_schedule(&acm->urb_task); } err_out: mutex_unlock(&acm->mutex); return rv; } /* * USB driver structure. */ Loading Loading @@ -1208,7 +1267,10 @@ static struct usb_driver acm_driver = { .name = "cdc_acm", .probe = acm_probe, .disconnect = acm_disconnect, .suspend = acm_suspend, .resume = acm_resume, .id_table = acm_ids, .supports_autosuspend = 1, }; /* Loading
drivers/usb/class/cdc-acm.h +2 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ struct acm { int write_used; /* number of non-empty write buffers */ int write_ready; /* write urb is not running */ spinlock_t write_lock; struct mutex mutex; struct usb_cdc_line_coding line; /* bits, stop, parity */ struct work_struct work; /* work queue entry for line discipline waking up */ struct tasklet_struct urb_task; /* rx processing */ Loading @@ -120,6 +121,7 @@ struct acm { unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ unsigned int susp_count; /* number of suspended interfaces */ }; #define CDC_DATA_INTERFACE_TYPE 0x0a Loading