dev_info(dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
dev_info(dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n");
/** * usb_serial_generic_write_start - start writing buffered data * @port: usb-serial port * @mem_flags: flags to use for memory allocations * * Serialised using USB_SERIAL_WRITE_BUSY flag. * * Return: Zero on success or if busy, otherwise a negative errno value.
*/ int usb_serial_generic_write_start(struct usb_serial_port *port,
gfp_t mem_flags)
{ struct urb *urb; int count, result; unsignedlong flags; int i;
if (test_and_set_bit_lock(USB_SERIAL_WRITE_BUSY, &port->flags)) return 0;
retry:
spin_lock_irqsave(&port->lock, flags); if (!port->write_urbs_free || !kfifo_len(&port->write_fifo)) {
clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
spin_unlock_irqrestore(&port->lock, flags); return 0;
}
i = (int)find_first_bit(&port->write_urbs_free,
ARRAY_SIZE(port->write_urbs));
spin_unlock_irqrestore(&port->lock, flags);
goto retry; /* try sending off another urb */
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write_start);
/** * usb_serial_generic_write - generic write function * @tty: tty for the port * @port: usb-serial port * @buf: data to write * @count: number of bytes to write * * Return: The number of characters buffered, which may be anything from * zero to @count, or a negative errno value.
*/ int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, constunsignedchar *buf, int count)
{ int result;
if (!port->bulk_out_size) return -ENODEV;
if (!count) return 0;
count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
result = usb_serial_generic_write_start(port, GFP_ATOMIC); if (result) return result;
bps = tty_get_baud_rate(tty); if (!bps)
bps = 9600; /* B0 */ /* * Use a poll-period of roughly the time it takes to send one * character or at least one jiffy.
*/
period = max_t(unsignedlong, (10 * HZ / bps), 1); if (timeout)
period = min_t(unsignedlong, period, timeout);
dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
__func__, jiffies_to_msecs(timeout),
jiffies_to_msecs(period));
expire = jiffies + timeout; while (!port->serial->type->tx_empty(port)) {
schedule_timeout_interruptible(period); if (signal_pending(current)) break; if (timeout && time_after(jiffies, expire)) break;
}
}
EXPORT_SYMBOL_GPL(usb_serial_generic_wait_until_sent);
staticint usb_serial_generic_submit_read_urb(struct usb_serial_port *port, int index, gfp_t mem_flags)
{ int res;
if (!test_and_clear_bit(index, &port->read_urbs_free)) return 0;
if (!urb->actual_length) return; /* * The per character mucking around with sysrq path it too slow for * stuff like 3G modems, so shortcircuit it in the 99.9999999% of * cases where the USB serial is not a console anyway.
*/ if (port->sysrq) { for (i = 0; i < urb->actual_length; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch))
tty_insert_flip_char(&port->port, *ch, TTY_NORMAL);
}
} else {
tty_insert_flip_string(&port->port, ch, urb->actual_length);
}
tty_flip_buffer_push(&port->port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb);
void usb_serial_generic_read_bulk_callback(struct urb *urb)
{ struct usb_serial_port *port = urb->context; unsignedchar *data = urb->transfer_buffer; bool stopped = false; int status = urb->status; int i;
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { if (urb == port->read_urbs[i]) break;
}
dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
urb->actual_length); switch (status) { case 0:
usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
data);
port->serial->type->process_read_urb(urb); break; case -ENOENT: case -ECONNRESET: case -ESHUTDOWN:
dev_dbg(&port->dev, "%s - urb stopped: %d\n",
__func__, status);
stopped = true; break; case -EPIPE:
dev_err(&port->dev, "%s - urb stopped: %d\n",
__func__, status);
stopped = true; break; default:
dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
__func__, status); break;
}
/* * Make sure URB processing is done before marking as free to avoid * racing with unthrottle() on another CPU. Matches the barriers * implied by the test_and_clear_bit() in * usb_serial_generic_submit_read_urb().
*/
smp_mb__before_atomic();
set_bit(i, &port->read_urbs_free); /* * Make sure URB is marked as free before checking the throttled flag * to avoid racing with unthrottle() on another CPU. Matches the * smp_mb__after_atomic() in unthrottle().
*/
smp_mb__after_atomic();
if (stopped) return;
if (test_bit(USB_SERIAL_THROTTLED, &port->flags)) return;
usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
void usb_serial_generic_write_bulk_callback(struct urb *urb)
{ unsignedlong flags; struct usb_serial_port *port = urb->context; int status = urb->status; int i;
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { if (port->write_urbs[i] == urb) break;
}
spin_lock_irqsave(&port->lock, flags);
port->tx_bytes -= urb->transfer_buffer_length;
set_bit(i, &port->write_urbs_free);
spin_unlock_irqrestore(&port->lock, flags);
switch (status) { case 0: break; case -ENOENT: case -ECONNRESET: case -ESHUTDOWN:
dev_dbg(&port->dev, "%s - urb stopped: %d\n",
__func__, status); return; case -EPIPE:
dev_err_console(port, "%s - urb stopped: %d\n",
__func__, status); return; default:
dev_err_console(port, "%s - nonzero urb status: %d\n",
__func__, status); break;
}
/* * Use tty-port initialised flag to detect all hangups including the * one generated at USB-device disconnect.
*/ if (!tty_port_initialized(&port->port)) returntrue;
ret = wait_event_interruptible(port->port.delta_msr_wait,
usb_serial_generic_msr_changed(tty, arg, &cnow)); if (!ret && !tty_port_initialized(&port->port))
ret = -EIO;
/** * usb_serial_handle_dcd_change - handle a change of carrier detect state * @port: usb-serial port * @tty: tty for the port * @status: new carrier detect status, nonzero if active
*/ void usb_serial_handle_dcd_change(struct usb_serial_port *port, struct tty_struct *tty, unsignedint status)
{
dev_dbg(&port->dev, "%s - status %d\n", __func__, status);
if (tty) { struct tty_ldisc *ld = tty_ldisc_ref(tty);
if (ld) { if (ld->ops->dcd_change)
ld->ops->dcd_change(tty, status);
tty_ldisc_deref(ld);
}
}
if (status)
wake_up_interruptible(&port->port.open_wait); elseif (tty && !C_CLOCAL(tty))
tty_hangup(tty);
}
EXPORT_SYMBOL_GPL(usb_serial_handle_dcd_change);
int usb_serial_generic_resume(struct usb_serial *serial)
{ struct usb_serial_port *port; int i, c = 0, r;
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i]; if (!tty_port_initialized(&port->port)) continue;
if (port->bulk_in_size) {
r = usb_serial_generic_submit_read_urbs(port,
GFP_NOIO); if (r < 0)
c++;
}
if (port->bulk_out_size) {
r = usb_serial_generic_write_start(port, GFP_NOIO); if (r < 0)
c++;
}
}
return c ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.