Usb + Serial + Net --- Linux Kernel 实现欣赏

这里写图片描述

/*
    该函数做了一下事情 : 
                    1 : 分配tty_driver 并且注册它
                    2 : 注册usb转串口总线
*/
static int __init usb_serial_init(void)
{
    /*
        这里分配一个tty_driver
        下面要给他赋值,接着要注册它
        分配 -->赋值 --> 注册   又耍这套手段,万变不离其宗 !

        该模块上来第一任务就要注册tty_driver,usb转虚拟串口中 uart面向用户,usb深藏幕后默默工作

        该函数的参数很有意思, 它是表示次设备的数量 
        有什么依据吗 ?
        alloc_tty_driver(unsigned int lines)
        {
            tty_alloc_driver(lines, 0);
            {
                __tty_alloc_driver(lines, THIS_MODULE, flags);
                {
                    ....
                    /*
                        看,下面注册字符设备的时候 会使用到这个driver->num
                        下面有分析
                    */
                    driver->num = lines;  
                }
            }
        }
    */
    usb_serial_tty_driver =  alloc_tty_driver(USB_SERIAL_TTY_MINORS);
    if (!usb_serial_tty_driver)
        return -ENOMEM;

    /**
        注册usb转串口总线.

        该总线提供了probe()函数,类似的还有IIC总线, 但是USB总线,平台总线 却没有提供probe()函数
        IIC总线的probe()函数调用了driver的 probe()函数,但是该总线也这样做了, 看下面

        具体该总线的probe()方法做了那些事情,下面有说明

        struct bus_type usb_serial_bus_type = {
            .name =     "usb-serial",
            .match =    usb_serial_device_match,
            .probe =    usb_serial_device_probe,
            {
                if (type->probe)  //如果该driver提供了 probe函数 
                {
                    ....
                }
            }
            .....
        };

        iic总线 probe :
            http://blog.csdn.net/leesagacious/article/details/50488949
    */  
    result = bus_register(&usb_serial_bus_type);
    if (result) {
        pr_err("%s - registering bus driver failed\n", __func__);
        goto exit_bus;
    }

    /*
        一块堆内存,已经赋值了,在这里再次 做 “整容手术”
        主设备号 : 118   188看错了 

        具体赋值的是什么含义,用到再说吧 
    */
    usb_serial_tty_driver->driver_name = "usbserial";
    usb_serial_tty_driver->name = "ttyUSB";
    usb_serial_tty_driver->major = USB_SERIAL_TTY_MAJOR; //118
    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;
}
/*
    好了,收发流程的入口来了

    操作设备文件,最终会调用serial_ops集合中对应的函数

    “一切皆文件” 底层是VFS机制的贡献, Linux Kernel的精华所在!
    它仿佛是一个黑洞,signal, socket 也逃脱不了!  也不知道当初是谁创造出来这么优秀的机制

    但是通过设备文件沟通kernel space 与 user space 收发数据, netlink,signal实现的更优雅
*/
tty_set_operations(usb_serial_tty_driver, &serial_ops);
/**
    开始要注册了

    1 :看看上面说到的那个次设备号的个数,driver->num

    int tty_register_driver(struct tty_driver *driver)
    {
        if (!driver->major) {
            .....
        } else {
            register_chrdev_region(dev, driver->num, driver->name); 
        }   
    }

    2 : 将该driver挂接到全局链表 tty_drivers 上
        usb gadget 最低层的udc 也是挂接到全局链表上
        这样的做法当然是为了以后遍历查找了, 

    3 : 注册 tty device
        for (i = 0; i < device->num; i++) {
            tty_register_device(driver, i, NULL);
        }   
*/
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
        pr_err("%s - tty_register_driver failed\n", __func__);
        goto exit_reg_driver;
}
/*
    usb_serial_probe()函数将会被调用
    这是设备驱动模型的内容了,Linux Kernel driver 的基石所在 !
    详细 : 
            http://blog.csdn.net/leesagacious/article/details/50488949 匹配流程图

    在这个probe函数中最多生成 8 个ttyUSB 设备文件,ttyUSB%d         
    这个 8 数字在Kernel USB 中 很有有意思,且 超过了这个数字都是强制为 8 
    比如 : 看获取配置描述符中的实现

    #define  USB_MAXCOFIG : 8 

    int usb_get_configuration(struct usb_device *dev)
    {
            ....
            int ncfg = dev->descriptor.bNumConfigurations;
            ....
            if (ncfg > USB_MAXCONFIG) {  
                ......  
            }
    }

    7 ↑ 8 ↓  哈哈 !

    在一个init函数中做了这么多的注册操作! 下面还有注册. 

    不是常说 : 雨常有,天不常蹋吗 ? 哈哈  作者究竟要未雨绸缪什么 ?    
*/
result = usb_register(&usb_serial_driver);
if (result < 0) {
        pr_err("%s - usb_register failed\n", __func__);
        goto exit_tty;
}

猜你喜欢

转载自blog.csdn.net/leesagacious/article/details/79189901