linux usb-serial options

1. 前言

...

2. 流程图


3. usb serial源码分析

3.1  usb serial驱动加载

module_init(usb_serial_init);
module_exit(usb_serial_exit);

3.2 usb serial初始化

static int __init usb_serial_init(void)
{
	int i;
	int result;

	usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); //分配一个usb tty driver结构体
	if (!usb_serial_tty_driver)
		return -ENOMEM;

	/* Initialize our global data */
	for (i = 0; i < SERIAL_TTY_MINORS; ++i) //为tty次设备usb-serial结构体初始化,在usb口热插拔创建设备/dev/ttyUSBx时就会使用一个serial_table[x]
		serial_table[i] = NULL;

	result = bus_register(&usb_serial_bus_type); //"usb-serial"总线注册
	if (result) {
		pr_err("%s - registering bus driver failed\n", __func__);
		goto exit_bus;
	}

	usb_serial_tty_driver->driver_name = "usbserial"; //以下是初始化tty 核心层,包括设备名、驱动名
	usb_serial_tty_driver->name = "ttyUSB";
	usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
	usb_serial_tty_driver->minor_start = 0;
	usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
						TTY_DRIVER_DYNAMIC_DEV;
	usb_serial_tty_driver->init_termios = tty_std_termios;
	usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
							| HUPCL | CLOCAL;
	usb_serial_tty_driver->init_termios.c_ispeed = 9600;
	usb_serial_tty_driver->init_termios.c_ospeed = 9600;
	tty_set_operations(usb_serial_tty_driver, &serial_ops); //绑定tty核心层的操作句柄
	result = tty_register_driver(usb_serial_tty_driver); //tty驱动注册
	if (result) {
		pr_err("%s - tty_register_driver failed\n", __func__);
		goto exit_reg_driver;
	}

	/* register the USB driver */
	result = usb_register(&usb_serial_driver); //usb驱动注册
	if (result < 0) {
		pr_err("%s - usb_register failed\n", __func__);
		goto exit_tty;
	}

	/* register the generic driver, if we should */
	result = usb_serial_generic_register();
	if (result < 0) {
		pr_err("%s - registering generic driver failed\n", __func__);
		goto exit_generic;
	}

	return result;

exit_generic:
	usb_deregister(&usb_serial_driver);

exit_tty:
	tty_unregister_driver(usb_serial_tty_driver);

exit_reg_driver:
	bus_unregister(&usb_serial_bus_type);

exit_bus:
	pr_err("%s - returning with error %d\n", __func__, result);
	put_tty_driver(usb_serial_tty_driver);
	return result;
}

usb_serial_init()初始化函数主要包括如下几个重要部分:

1> 动态分配一个tty驱动,usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);

2> "usb-serial"总线注册,result = bus_register(&usb_serial_bus_type);

3> tty驱动注册,result = tty_register_driver(usb_serial_tty_driver);

4> usb串口驱动注册,result = usb_register(&usb_serial_driver);

下面逐个分析...

3.3 动态分配一个tty驱动结构体

usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); //SERIAL_TTY_MINORS为254
if (!usb_serial_tty_driver)
	return -ENOMEM;
static inline struct tty_driver *alloc_tty_driver(unsigned int lines)
{
	struct tty_driver *ret = tty_alloc_driver(lines, 0);
	if (IS_ERR(ret))
		return NULL;
	return ret;
}
#define tty_alloc_driver(lines, flags) \
		__tty_alloc_driver(lines, THIS_MODULE, flags)
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
		unsigned long flags)
{
	struct tty_driver *driver;
	unsigned int cdevs = 1;
	int err;

	if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
		return ERR_PTR(-EINVAL);

	driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); //动态分配一个tty_driver内存空间
	if (!driver)
		return ERR_PTR(-ENOMEM);

	kref_init(&driver->kref);
	driver->magic = TTY_DRIVER_MAGIC;
	driver->num = lines; //绑定tty_driver驱动个数
	driver->owner = owner;
	driver->flags = flags; //flags=0

	if (!(flags & TTY_DRIVER_DEVPTS_MEM)) { //条件成立
		driver->ttys = kcalloc(lines, sizeof(*driver->ttys), //分配lines个tty_struct设备
				GFP_KERNEL);
		driver->termios = kcalloc(lines, sizeof(*driver->termios), //分配lines个ktermios内核终端输入、输出配置
				GFP_KERNEL);
		if (!driver->ttys || !driver->termios) {
			err = -ENOMEM;
			goto err_free_all;
		}
	}

	if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) { //条件成立
		driver->ports = kcalloc(lines, sizeof(*driver->ports), //分配lines个tty_port结构体
				GFP_KERNEL);
		if (!driver->ports) {
			err = -ENOMEM;
			goto err_free_all;
		}
		cdevs = lines; //初始化字符设备的个数
	}

	driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL); //分配lines个cedv字符设备
	if (!driver->cdevs) {
		err = -ENOMEM;
		goto err_free_all;
	}

	return driver;
err_free_all:
	kfree(driver->ports);
	kfree(driver->ttys);
	kfree(driver->termios);
	kfree(driver);
	return ERR_PTR(err);
}
EXPORT_SYMBOL(__tty_alloc_driver);

3.4 “usb-serial”总线注册

struct bus_type usb_serial_bus_type = { 
	.name =		"usb-serial", //总线名称
	.match =	usb_serial_device_match, //总线上驱动和设备匹配接口
	.probe =	usb_serial_device_probe, //匹配成功调用的探测接口
	.remove =	usb_serial_device_remove,
	.drv_attrs = 	drv_attrs,
};
result = bus_register(&usb_serial_bus_type);
if (result) {
	pr_err("%s - registering bus driver failed\n", __func__);
	goto exit_bus;
}
int bus_register(struct bus_type *bus)
{
	int retval;
	struct subsys_private *priv;
	struct lock_class_key *key = &bus->lock_key;

	priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); //分配一个内核对象子系统
	if (!priv)
		return -ENOMEM;

	priv->bus = bus; //初始化子系统的当前总线
	bus->p = priv; //绑定当前总线的子系统

	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //初始化一个阻塞通知链

	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //给当前子系统的内核对象命名
	if (retval)
		goto out;

	priv->subsys.kobj.kset = bus_kset; //初始化当前子系统的父内核集合为bus_kset
	priv->subsys.kobj.ktype = &bus_ktype; //初始化当前子系统内核对象属性(内核对象属性就是表示对文件的操作)
	priv->drivers_autoprobe = 1; //设置设备和驱动匹配为自动,即从总线上获取对应相同的名称

	retval = kset_register(&priv->subsys); //子系统内核集合初始化
	if (retval)
		goto out;

	retval = bus_create_file(bus, &bus_attr_uevent); //创建当前总线的事件属性文件
	if (retval)
		goto bus_uevent_fail;

	priv->devices_kset = kset_create_and_add("devices", NULL, //创建当前总线的“设备”内核集合,即该总线下的设备都把它作为父集合对象
						 &priv->subsys.kobj);
	if (!priv->devices_kset) {
		retval = -ENOMEM;
		goto bus_devices_fail;
	}

	priv->drivers_kset = kset_create_and_add("drivers", NULL, //创建当前总线下的“驱动”内核集合,即该总线下的驱动都把它作为集合对象
						 &priv->subsys.kobj);
	if (!priv->drivers_kset) {
		retval = -ENOMEM;
		goto bus_drivers_fail;
	}

	INIT_LIST_HEAD(&priv->interfaces); //初始化接口链表
	__mutex_init(&priv->mutex, "subsys mutex", key);  //初始化子系统互斥锁
	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //创建一个设备链表,即当前总线下的设备都挂接在该链表上
	klist_init(&priv->klist_drivers, NULL, NULL); //创建一个驱动链表,即当前总线下的驱动都挂接在该链表上

	retval = add_probe_files(bus); //增加当前总线的属性文件(如driver_auto_probe、drivers_probe)到sys文件系统
	if (retval)
		goto bus_probe_files_fail;

	retval = bus_add_attrs(bus); //为当前总线增加属性文件
	if (retval)
		goto bus_attrs_fail;

	pr_debug("bus: '%s': registered\n", bus->name);
	return 0;

bus_attrs_fail:
	remove_probe_files(bus);
bus_probe_files_fail:
	kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
	kset_unregister(bus->p->devices_kset);
bus_devices_fail:
	bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
	kset_unregister(&bus->p->subsys);
out:
	kfree(bus->p);
	bus->p = NULL;
	return retval;
}
EXPORT_SYMBOL_GPL(bus_register);

3.5 tty驱动注册

	usb_serial_tty_driver->driver_name = "usbserial"; //设置驱动名称,在总线上用来与设备相匹配
	usb_serial_tty_driver->name = "ttyUSB"; //初始化tty设备的名称
	usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; //tty主设备号188
	usb_serial_tty_driver->minor_start = 0; //次设备的起始值为0,表示动态分配次设备
	usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; //tty驱动类型为串口(tty的类型有很多,如console、pty...)
	usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; //tty驱动子类型
	usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
						TTY_DRIVER_DYNAMIC_DEV;
	usb_serial_tty_driver->init_termios = tty_std_termios;
	usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
							| HUPCL | CLOCAL;
	usb_serial_tty_driver->init_termios.c_ispeed = 9600;
	usb_serial_tty_driver->init_termios.c_ospeed = 9600;
	tty_set_operations(usb_serial_tty_driver, &serial_ops); //绑定tty操作集,即tty核心层的接口
	result = tty_register_driver(usb_serial_tty_driver); //tty驱动注册
	if (result) {
		pr_err("%s - tty_register_driver failed\n", __func__);
		goto exit_reg_driver;
	}

tty核心层操作接口:

static const struct tty_operations serial_ops = {
	.open =			serial_open,
	.close =		serial_close,
	.write =		serial_write,
	.hangup =		serial_hangup,
	.write_room =		serial_write_room,
	.ioctl =		serial_ioctl,
	.set_termios =		serial_set_termios,
	.throttle =		serial_throttle,
	.unthrottle =		serial_unthrottle,
	.break_ctl =		serial_break,
	.chars_in_buffer =	serial_chars_in_buffer,
	.wait_until_sent =	serial_wait_until_sent,
	.tiocmget =		serial_tiocmget,
	.tiocmset =		serial_tiocmset,
	.get_icount =		serial_get_icount,
	.cleanup =		serial_cleanup,
	.install =		serial_install,
	.proc_fops =		&serial_proc_fops,
};
result = tty_register_driver(usb_serial_tty_driver);
int tty_register_driver(struct tty_driver *driver)
{
	int error;
	int i;
	dev_t dev;
	struct device *d;

	if (!driver->major) { //major=188
		error = alloc_chrdev_region(&dev, driver->minor_start,
						driver->num, driver->name);
		if (!error) {
			driver->major = MAJOR(dev);
			driver->minor_start = MINOR(dev);
		}
	} else {
		dev = MKDEV(driver->major, driver->minor_start); //创建主、次设备号
		error = register_chrdev_region(dev, driver->num, driver->name); //注册num个字符设备
	}
	if (error < 0)
		goto err;

	if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
		error = tty_cdev_add(driver, dev, 0, driver->num); //tty字符设备增加(会绑定tty_io层的操作集),这个函数内部详见下面
		if (error)
			goto err_unreg_char;
	}

	mutex_lock(&tty_mutex);
	list_add(&driver->tty_drivers, &tty_drivers); //将当前驱动加入到全局链表tty_drivers
	mutex_unlock(&tty_mutex);

	if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
		for (i = 0; i < driver->num; i++) {
			d = tty_register_device(driver, i, NULL); //注册tty字符设备
			if (IS_ERR(d)) {
				error = PTR_ERR(d);
				goto err_unreg_devs;
			}
		}
	}
	proc_tty_register_driver(driver); //tty proc文件系统注册
	driver->flags |= TTY_DRIVER_INSTALLED;
	return 0;

err_unreg_devs:
	for (i--; i >= 0; i--)
		tty_unregister_device(driver, i);

	mutex_lock(&tty_mutex);
	list_del(&driver->tty_drivers);
	mutex_unlock(&tty_mutex);

err_unreg_char:
	unregister_chrdev_region(dev, driver->num);
err:
	return error;
}
EXPORT_SYMBOL(tty_register_driver);

字符设备增加:

error = tty_cdev_add(driver, dev, 0, driver->num);
static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
		unsigned int index, unsigned int count)
{
	/* init here, since reused cdevs cause crashes */
	cdev_init(&driver->cdevs[index], &tty_fops); //绑定tty_io层的操作集
	driver->cdevs[index].owner = driver->owner;
	return cdev_add(&driver->cdevs[index], dev, count);
}
static const struct file_operations tty_fops = {
	.llseek		= no_llseek,
	.read		= tty_read,
	.write		= tty_write,
	.poll		= tty_poll,
	.unlocked_ioctl	= tty_ioctl,
	.compat_ioctl	= tty_compat_ioctl,
	.open		= tty_open,
	.release	= tty_release,
	.fasync		= tty_fasync,
};

这个是文件操作集合,对应系统调用的第一层。

3.6 usb驱动注册

static struct usb_driver usb_serial_driver = {
	.name =		"usbserial", //驱动名称
	.probe =	usb_serial_probe, //驱动探测接口
	.disconnect =	usb_serial_disconnect,
	.suspend =	usb_serial_suspend,
	.resume =	usb_serial_resume,
	.no_dynamic_id =	1,
	.supports_autosuspend =	1,
};
result = usb_register(&usb_serial_driver);
#define usb_register(driver) \
	usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
			const char *mod_name)
{
	int retval = 0;

	if (usb_disabled())
		return -ENODEV;

	new_driver->drvwrap.for_devices = 0;
	new_driver->drvwrap.driver.name = (char *) new_driver->name; //“usbserial”
	new_driver->drvwrap.driver.bus = &usb_bus_type; //绑定总线为“usb”
	new_driver->drvwrap.driver.probe = usb_probe_interface; //绑定接口
	new_driver->drvwrap.driver.remove = usb_unbind_interface;
	new_driver->drvwrap.driver.owner = owner;
	new_driver->drvwrap.driver.mod_name = mod_name;
	spin_lock_init(&new_driver->dynids.lock);
	INIT_LIST_HEAD(&new_driver->dynids.list);

	retval = driver_register(&new_driver->drvwrap.driver); //驱动注册
	if (retval)
		goto out;

	retval = usb_create_newid_files(new_driver);
	if (retval)
		goto out_newid;

	pr_info("%s: registered new interface driver %s\n",
			usbcore_name, new_driver->name);

out:
	return retval;

out_newid:
	driver_unregister(&new_driver->drvwrap.driver);

	printk(KERN_ERR "%s: error %d registering interface "
			"	driver %s\n",
			usbcore_name, retval, new_driver->name);
	goto out;
}
EXPORT_SYMBOL_GPL(usb_register_driver);
至此,就完成了"usb-serial"的总线注册,usb tty(254个tty【ttyUSBx】)驱动"usbserial"的注册,usb串口驱动"usbserial"注册。










  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值