📄 usbserial.c
字号:
/* pass on to the driver specific version of this function if it is
available */
if(serial->type->break_ctl) {
serial->type->break_ctl(port, break_state);
}
}
/*****************************************************************************
* generic devices specific driver functions
*****************************************************************************/
static int generic_open(struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
unsigned long flags;
int result;
if(port_paranoia_check(port, __FUNCTION__))
return -ENODEV;
MOD_INC_USE_COUNT;
dbg(__FUNCTION__ " - port %d", port->number);
spin_lock_irqsave(&port->port_lock, flags);
++port->open_count;
if(!port->active) {
port->active = 1;
/* force low_latency on so that our tty_push actually forces the data through,
otherwise it is scheduled, and with high data rates (like with OHCI) data
can get lost. */
port->tty->low_latency = 1;
/* if we have a bulk interrupt, start reading from it */
if(serial->num_bulk_in) {
/* Start reading from the device */
FILL_BULK_URB(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : generic_read_bulk_callback),
port);
result = usb_submit_urb(port->read_urb);
if(result)
err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
}
}
spin_unlock_irqrestore(&port->port_lock, flags);
return 0;
}
static void generic_close(struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
unsigned long flags;
dbg(__FUNCTION__ " - port %d", port->number);
spin_lock_irqsave(&port->port_lock, flags);
--port->open_count;
if(port->open_count <= 0) {
/* shutdown any bulk reads that might be going on */
if(serial->num_bulk_out)
usb_unlink_urb(port->write_urb);
if(serial->num_bulk_in)
usb_unlink_urb(port->read_urb);
port->active = 0;
port->open_count = 0;
}
spin_unlock_irqrestore(&port->port_lock, flags);
MOD_DEC_USE_COUNT;
}
static int generic_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
struct usb_serial *serial = port->serial;
unsigned long flags;
int result;
dbg(__FUNCTION__ " - port %d", port->number);
if(count == 0) {
dbg(__FUNCTION__ " - write request of 0 bytes");
return(0);
}
/* only do something if we have a bulk out endpoint */
if(serial->num_bulk_out) {
if(port->write_urb->status == -EINPROGRESS) {
dbg(__FUNCTION__ " - already writing");
return(0);
}
spin_lock_irqsave(&port->port_lock, flags);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
if(from_user) {
copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
else {
memcpy(port->write_urb->transfer_buffer, buf, count);
}
/* set up our urb */
FILL_BULK_URB(port->write_urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer, count,
((serial->type->write_bulk_callback) ? serial->type->write_bulk_callback : generic_write_bulk_callback),
port);
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb);
if(result) {
err(__FUNCTION__ " - failed submitting write urb, error %d", result);
spin_unlock_irqrestore(&port->port_lock, flags);
return 0;
}
spin_unlock_irqrestore(&port->port_lock, flags);
return(count);
}
/* no bulk out, so return 0 bytes written */
return(0);
}
static int generic_write_room(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
int room = 0;
dbg(__FUNCTION__ " - port %d", port->number);
if(serial->num_bulk_out)
if(port->write_urb->status != -EINPROGRESS)
room = port->bulk_out_size;
dbg(__FUNCTION__ " - returns %d", room);
return(room);
}
static int generic_chars_in_buffer(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
int chars = 0;
dbg(__FUNCTION__ " - port %d", port->number);
if(serial->num_bulk_out)
if(port->write_urb->status == -EINPROGRESS)
chars = port->write_urb->transfer_buffer_length;
dbg(__FUNCTION__ " - returns %d", chars);
return(chars);
}
static void generic_read_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
int result;
dbg(__FUNCTION__ " - port %d", port->number);
if(!serial) {
dbg(__FUNCTION__ " - bad serial pointer, exiting");
return;
}
if(urb->status) {
dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
return;
}
usb_serial_debug_data(__FILE__, __FUNCTION__, urb->actual_length, data);
tty = port->tty;
if(urb->actual_length) {
for(i = 0; i < urb->actual_length; ++i) {
/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
}
/* this doesn't actually push the data through unless tty->low_latency is set */
tty_insert_flip_char(tty, data[i], 0);
}
tty_flip_buffer_push(tty);
}
/* Continue trying to always read */
FILL_BULK_URB(port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : generic_read_bulk_callback),
port);
result = usb_submit_urb(port->read_urb);
if(result)
err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
}
static void generic_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
dbg(__FUNCTION__ " - port %d", port->number);
if(!serial) {
dbg(__FUNCTION__ " - bad serial pointer, exiting");
return;
}
if(urb->status) {
dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
return;
}
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return;
}
#ifdef CONFIG_USB_SERIAL_GENERIC
static void generic_shutdown(struct usb_serial *serial)
{
int i;
dbg(__FUNCTION__);
/* stop reads and writes on all ports */
for(i = 0; i < serial->num_ports; ++i) {
while(serial->port[i].open_count > 0) {
generic_close(&serial->port[i], NULL);
}
}
}
#endif
static void port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
struct usb_serial *serial = get_usb_serial(port, __FUNCTION__);
struct tty_struct *tty;
dbg(__FUNCTION__ " - port %d", port->number);
if(!serial) {
return;
}
tty = port->tty;
if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
dbg(__FUNCTION__ " - write wakeup call.");
(tty->ldisc.write_wakeup) (tty);
}
wake_up_interruptible(&tty->write_wait);
}
static void *usb_serial_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
{
struct usb_serial *serial = NULL;
struct usb_serial_port *port;
struct usb_interface *interface;
struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *endpoint;
struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_device_type *type = NULL;
struct list_head *tmp;
int found;
int minor;
int buffer_size;
int i;
char interrupt_pipe;
char bulk_in_pipe;
char bulk_out_pipe;
int num_interrupt_in = 0;
int num_bulk_in = 0;
int num_bulk_out = 0;
int num_ports;
int max_endpoints;
const struct usb_device_id *id_pattern = NULL;
/* loop through our list of known serial converters, and see if this
device matches. */
found = 0;
interface = &dev->actconfig->interface[ifnum];
list_for_each(tmp, &usb_serial_driver_list) {
type = list_entry(tmp, struct usb_serial_device_type, driver_list);
id_pattern = usb_match_id(dev, interface, type->id_table);
if(id_pattern != NULL) {
dbg("descriptor matches");
found = 1;
break;
}
}
if(!found) {
/* no match */
dbg("none matched");
return(NULL);
}
/* descriptor matches, let's find the endpoints needed */
interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
/* check out the endpoints */
iface_desc = &interface->altsetting[0];
for(i = 0; i < iface_desc->bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i];
if((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk in endpoint */
dbg("found bulk in");
bulk_in_pipe = HAS;
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
if(((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk out endpoint */
dbg("found bulk out");
bulk_out_pipe = HAS;
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
if((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in");
interrupt_pipe = HAS;
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
}
/* verify that we found all of the endpoints that we need */
if
(
!(
(interrupt_pipe & type->needs_interrupt_in) &&
(bulk_in_pipe & type->needs_bulk_in) &&
(bulk_out_pipe & type->needs_bulk_out)
)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -