Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
History: see the git log.
Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
This driver exists because the "normal" serial driver doesn't work too well with GSM modems. Issues: - data loss -- one single Receive URB is not nearly enough - controlling the baud rate doesn't make sense
*/
/* * Generate DTR/RTS signals on the port using the SET_CONTROL_LINE_STATE request * in CDC ACM.
*/ staticint usb_wwan_send_setup(struct usb_serial_port *port)
{ struct usb_serial *serial = port->serial; struct usb_wwan_port_private *portdata; int val = 0; int ifnum; int res;
portdata = usb_get_serial_port_data(port);
if (portdata->dtr_state)
val |= USB_CDC_CTRL_DTR; if (portdata->rts_state)
val |= USB_CDC_CTRL_RTS;
for (i = 0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i]; /* FIXME: This locking is insufficient as this_urb may
go unused during the test */ if (this_urb && test_bit(i, &portdata->out_busy))
data_len += this_urb->transfer_buffer_length;
}
dev_dbg(&port->dev, "%s: %u\n", __func__, data_len); return data_len;
}
EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
{ struct usb_wwan_port_private *portdata; struct usb_wwan_intf_private *intfdata; struct usb_serial *serial = port->serial; int i, err; struct urb *urb;
if (port->interrupt_in_urb) {
err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (err) {
dev_err(&port->dev, "%s: submit int urb failed: %d\n",
__func__, err);
}
}
/* Start reading from the IN endpoint */ for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i]; if (!urb) continue;
err = usb_submit_urb(urb, GFP_KERNEL); if (err) {
dev_err(&port->dev, "%s: submit read urb %d failed: %d\n",
__func__, i, err);
}
}
spin_lock_irq(&intfdata->susp_lock); if (++intfdata->open_ports == 1)
serial->interface->needs_remote_wakeup = 1;
spin_unlock_irq(&intfdata->susp_lock); /* this balances a get in the generic USB serial code */
usb_autopm_put_interface(serial->interface);
return0;
}
EXPORT_SYMBOL(usb_wwan_open);
staticvoid unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
{ int i;
for (i = 0; i < N_OUT_URB; i++) { if (urb == portdata->out_urbs[i]) {
clear_bit(i, &portdata->out_busy); break;
}
}
}
/* * Need to take susp_lock to make sure port is not already being * resumed, but no need to hold it due to the tty-port initialized * flag.
*/
spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0)
serial->interface->needs_remote_wakeup = 0;
spin_unlock_irq(&intfdata->susp_lock);
for (;;) {
urb = usb_get_from_anchor(&portdata->delayed); if (!urb) break;
unbusy_queued_urb(urb, portdata);
usb_autopm_put_interface_async(serial->interface);
}
for (i = 0; i < N_IN_URB; i++)
usb_kill_urb(portdata->in_urbs[i]); for (i = 0; i < N_OUT_URB; i++)
usb_kill_urb(portdata->out_urbs[i]);
usb_kill_urb(port->interrupt_in_urb);
bail_out_error2: for (i = 0; i < N_OUT_URB; i++) {
usb_free_urb(portdata->out_urbs[i]);
kfree(portdata->out_buffer[i]);
}
bail_out_error: for (i = 0; i < N_IN_URB; i++) {
usb_free_urb(portdata->in_urbs[i]);
free_page((unsignedlong)portdata->in_buffer[i]);
}
kfree(portdata);
for (i = 0; i < N_IN_URB; i++) {
usb_free_urb(portdata->in_urbs[i]);
free_page((unsignedlong)portdata->in_buffer[i]);
} for (i = 0; i < N_OUT_URB; i++) {
usb_free_urb(portdata->out_urbs[i]);
kfree(portdata->out_buffer[i]);
}
¤ 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.0.14Bemerkung:
(vorverarbeitet am 2026-06-06)
¤
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.