static void acm_port_down(struct acm *acm, int drain) { int i, nr = acm->rx_buflimit; mutex_lock(&open_mutex); if (acm->dev) { usb_autopm_get_interface(acm->control); acm_set_control(acm, acm->ctrlout = 0); /* try letting the last writes drain naturally */ if (drain) { wait_event_interruptible_timeout(acm->drain_wait, (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev, ACM_CLOSE_TIMEOUT * HZ); } usb_kill_urb(acm->ctrlurb); for (i = 0; i < ACM_NW; i++) usb_kill_urb(acm->wb[i].urb); tasklet_disable(&acm->urb_task); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); tasklet_enable(&acm->urb_task); acm->control->needs_remote_wakeup = 0; usb_autopm_put_interface(acm->control); } mutex_unlock(&open_mutex); }
static void acm_tty_close(struct tty_struct *tty, struct file *filp) { struct acm *acm = tty->driver_data; int i,nr; if (!acm || !acm->used) return; nr = acm->rx_buflimit; mutex_lock(&open_mutex); if (!--acm->used) { if (acm->dev) { usb_autopm_get_interface(acm->control); acm_set_control(acm, acm->ctrlout = 0); /* try letting the last writes drain naturally */ wait_event_interruptible_timeout(acm->drain_wait, (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev, ACM_CLOSE_TIMEOUT * HZ); usb_kill_urb(acm->ctrlurb); for (i = 0; i < ACM_NW; i++) usb_kill_urb(acm->wb[i].urb); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); acm->control->needs_remote_wakeup = 0; usb_autopm_put_interface(acm->control); } else acm_tty_unregister(acm); } mutex_unlock(&open_mutex); }
static int acm_tty_chars_in_buffer(struct tty_struct *tty) { struct acm *acm = tty->driver_data; if (acm->disconnected) return 0; return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; }
static int acm_tty_write_room(struct tty_struct *tty) { struct acm *acm = tty->driver_data; /* * Do not let the line discipline to know that we have a reserve, * or it might get too enthusiastic. */ return acm_wb_is_avail(acm) ? acm->writesize : 0; }
static int acm_tty_chars_in_buffer(struct tty_struct *tty) { struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return -EINVAL; /* * This is inaccurate (overcounts), but it works. */ return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; }
static int acm_tty_chars_in_buffer(struct tty_struct *tty) { struct acm *acm = tty->driver_data; /* * if the device was unplugged then any remaining characters fell out * of the connector ;) */ if (acm->disconnected) return 0; /* * This is inaccurate (overcounts), but it works. */ return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; }
static int acm_write_start(struct acm *acm, int wbn) { unsigned long flags; struct acm_wb *wb; int rc; spin_lock_irqsave(&acm->write_lock, flags); if (!acm->dev) { spin_unlock_irqrestore(&acm->write_lock, flags); return -ENODEV; } if (!acm->write_ready) { spin_unlock_irqrestore(&acm->write_lock, flags); return 0; /* A white lie */ } wb = &acm->wb[wbn]; if(acm_wb_is_avail(acm) <= 1) acm->write_ready = 0; dbg("%s susp_count: %d", __FUNCTION__, acm->susp_count); if (acm->susp_count) { acm->old_ready = acm->write_ready; acm->delayed_wb = wb; acm->write_ready = 0; schedule_work(&acm->waker); spin_unlock_irqrestore(&acm->write_lock, flags); return 0; /* A white lie */ } usb_mark_last_busy(acm->dev); if (!acm_wb_is_used(acm, wbn)) { spin_unlock_irqrestore(&acm->write_lock, flags); return 0; } rc = acm_start_wb(acm, wb); spin_unlock_irqrestore(&acm->write_lock, flags); return rc; }
/* * Poke write. */ static int acm_write_start(struct acm *acm, int wbn) { unsigned long flags; struct acm_wb *wb; int rc; spin_lock_irqsave(&acm->write_lock, flags); if (!acm->dev) { spin_unlock_irqrestore(&acm->write_lock, flags); return -ENODEV; } if (!acm->write_ready) { spin_unlock_irqrestore(&acm->write_lock, flags); return 0; /* A white lie */ } if (!acm_wb_is_used(acm, wbn)) { spin_unlock_irqrestore(&acm->write_lock, flags); return 0; } wb = &acm->wb[wbn]; if(acm_wb_is_avail(acm) <= 1) acm->write_ready = 0; spin_unlock_irqrestore(&acm->write_lock, flags); wb->urb->transfer_buffer = wb->buf; wb->urb->transfer_dma = wb->dmah; wb->urb->transfer_buffer_length = wb->len; wb->urb->dev = acm->dev; if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { dbg("usb_submit_urb(write bulk) failed: %d", rc); acm_write_done(acm, wb); } return rc; }
static int acm_tty_write_room(struct tty_struct *tty) { struct acm *acm = tty->driver_data; return acm_wb_is_avail(acm) ? acm->writesize : 0; }