⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb-serial.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * USB Serial Converter driver * * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License version *	2 as published by the Free Software Foundation. * * This driver was originally based on the ACM driver by Armin Fuerst (which was * based on a driver by Brad Keryan) * * See Documentation/usb/usb-serial.txt for more information on using this driver * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <linux/usb.h>#include "usb-serial.h"#include "pl2303.h"/* * Version Information */#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"#define DRIVER_DESC "USB Serial Driver core"/* Driver structure we register with the USB core */static struct usb_driver usb_serial_driver = {	.owner =	THIS_MODULE,	.name =		"usbserial",	.probe =	usb_serial_probe,	.disconnect =	usb_serial_disconnect,};/* There is no MODULE_DEVICE_TABLE for usbserial.c.  Instead   the MODULE_DEVICE_TABLE declarations in each serial driver   cause the "hotplug" program to pull in whatever module is necessary   via modprobe, and modprobe will load usbserial because the serial   drivers depend on it.*/static int debug;static struct usb_serial *serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */static LIST_HEAD(usb_serial_driver_list);struct usb_serial *usb_serial_get_by_index(unsigned index){	struct usb_serial *serial = serial_table[index];	if (serial)		kref_get(&serial->kref);	return serial;}static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor){	unsigned int i, j;	int good_spot;	dbg("%s %d", __FUNCTION__, num_ports);	*minor = 0;	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {		if (serial_table[i])			continue;		good_spot = 1;		for (j = 1; j <= num_ports-1; ++j)			if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {				good_spot = 0;				i += j;				break;			}		if (good_spot == 0)			continue;		*minor = i;		dbg("%s - minor base = %d", __FUNCTION__, *minor);		for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)			serial_table[i] = serial;		return serial;	}	return NULL;}static void return_serial(struct usb_serial *serial){	int i;	dbg("%s", __FUNCTION__);	if (serial == NULL)		return;	for (i = 0; i < serial->num_ports; ++i) {		serial_table[serial->minor + i] = NULL;	}}static void destroy_serial(struct kref *kref){	struct usb_serial *serial;	struct usb_serial_port *port;	int i;	serial = to_usb_serial(kref);	dbg("%s - %s", __FUNCTION__, serial->type->description);	serial->type->shutdown(serial);	/* return the minor range that this device had */	return_serial(serial);	for (i = 0; i < serial->num_ports; ++i)		serial->port[i]->open_count = 0;	/* the ports are cleaned up and released in port_release() */	for (i = 0; i < serial->num_ports; ++i)		if (serial->port[i]->dev.parent != NULL) {			device_unregister(&serial->port[i]->dev);			serial->port[i] = NULL;		}	/* If this is a "fake" port, we have to clean it up here, as it will	 * not get cleaned up in port_release() as it was never registered with	 * the driver core */	if (serial->num_ports < serial->num_port_pointers) {		for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {			port = serial->port[i];			if (!port)				continue;			usb_kill_urb(port->read_urb);			usb_free_urb(port->read_urb);			usb_kill_urb(port->write_urb);			usb_free_urb(port->write_urb);			usb_kill_urb(port->interrupt_in_urb);			usb_free_urb(port->interrupt_in_urb);			usb_kill_urb(port->interrupt_out_urb);			usb_free_urb(port->interrupt_out_urb);			kfree(port->bulk_in_buffer);			kfree(port->bulk_out_buffer);			kfree(port->interrupt_in_buffer);			kfree(port->interrupt_out_buffer);		}	}	usb_put_dev(serial->dev);	/* free up any memory that we allocated */	kfree (serial);}/***************************************************************************** * Driver tty interface functions *****************************************************************************/static int serial_open (struct tty_struct *tty, struct file * filp){	struct usb_serial *serial;	struct usb_serial_port *port;	unsigned int portNumber;	int retval;		dbg("%s", __FUNCTION__);	/* get the serial object associated with this tty pointer */	serial = usb_serial_get_by_index(tty->index);	if (!serial) {		tty->driver_data = NULL;		return -ENODEV;	}	portNumber = tty->index - serial->minor;	port = serial->port[portNumber];	 	++port->open_count;	if (port->open_count == 1) {		/* set up our port structure making the tty driver		 * remember our port object, and us it */		tty->driver_data = port;		port->tty = tty;		/* lock this module before we call it		 * this may fail, which means we must bail out,		 * safe because we are called with BKL held */		if (!try_module_get(serial->type->driver.owner)) {			retval = -ENODEV;			goto bailout_kref_put;		}		/* only call the device specific open if this 		 * is the first time the port is opened */		retval = serial->type->open(port, filp);		if (retval)			goto bailout_module_put;	}	return 0;bailout_module_put:	module_put(serial->type->driver.owner);bailout_kref_put:	kref_put(&serial->kref, destroy_serial);	port->open_count = 0;	return retval;}static void serial_close(struct tty_struct *tty, struct file * filp){	struct usb_serial_port *port = tty->driver_data;	if (!port)		return;	dbg("%s - port %d", __FUNCTION__, port->number);	if (port->open_count == 0)		return;	--port->open_count;	if (port->open_count == 0) {		/* only call the device specific close if this 		 * port is being closed by the last owner */		port->serial->type->close(port, filp);		if (port->tty) {			if (port->tty->driver_data)				port->tty->driver_data = NULL;			port->tty = NULL;		}		module_put(port->serial->type->driver.owner);	}	kref_put(&port->serial->kref, destroy_serial);}static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count){	struct usb_serial_port *port = tty->driver_data;	int retval = -EINVAL;	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);	if (!port->open_count) {		dbg("%s - port not opened", __FUNCTION__);		goto exit;	}	/* pass on to the driver specific version of this function */	retval = port->serial->type->write(port, buf, count);exit:	return retval;}static int serial_write_room (struct tty_struct *tty) {	struct usb_serial_port *port = tty->driver_data;	int retval = -EINVAL;	dbg("%s - port %d", __FUNCTION__, port->number);	if (!port->open_count) {		dbg("%s - port not open", __FUNCTION__);		goto exit;	}	/* pass on to the driver specific version of this function */	retval = port->serial->type->write_room(port);exit:	return retval;}static int serial_chars_in_buffer (struct tty_struct *tty) {	struct usb_serial_port *port = tty->driver_data;	int retval = -EINVAL;	dbg("%s = port %d", __FUNCTION__, port->number);	if (!port->open_count) {		dbg("%s - port not open", __FUNCTION__);		goto exit;	}	/* pass on to the driver specific version of this function */	retval = port->serial->type->chars_in_buffer(port);exit:	return retval;}static void serial_throttle (struct tty_struct * tty){	struct usb_serial_port *port = tty->driver_data;	dbg("%s - port %d", __FUNCTION__, port->number);	if (!port->open_count) {		dbg ("%s - port not open", __FUNCTION__);		return;	}	/* pass on to the driver specific version of this function */	if (port->serial->type->throttle)		port->serial->type->throttle(port);}static void serial_unthrottle (struct tty_struct * tty){	struct usb_serial_port *port = tty->driver_data;	dbg("%s - port %d", __FUNCTION__, port->number);	if (!port->open_count) {		dbg("%s - port not open", __FUNCTION__);		return;	}	/* pass on to the driver specific version of this function */	if (port->serial->type->unthrottle)		port->serial->type->unthrottle(port);}static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){	struct usb_serial_port *port = tty->driver_data;	int retval = -ENODEV;	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);	if (!port->open_count) {		dbg ("%s - port not open", __FUNCTION__);		goto exit;	}	/* pass on to the driver specific version of this function if it is available */	if (port->serial->type->ioctl)		retval = port->serial->type->ioctl(port, file, cmd, arg);	else		retval = -ENOIOCTLCMD;exit:	return retval;}static void serial_set_termios (struct tty_struct *tty, struct termios * old){	struct usb_serial_port *port = tty->driver_data;	dbg("%s - port %d", __FUNCTION__, port->number);	if (!port->open_count) {		dbg("%s - port not open", __FUNCTION__);		return;	}	/* pass on to the driver specific version of this function if it is available */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -