固定串口编号Linux Android

本系列调试说明记录了Linux在全志T113-S3/S4平台上的移植过程,说明过程中可能会技术瑕疵,希望大家提供宝贵意见。
本文移植的硬件平台来自于盈鹏飞嵌入式的SBC-T113S(处理器是T113-S3)主板。

SBC-T113S产品特性:

  • 采用Allwinner公司Cortex-A7双核T113-S3/S4处理器,运行最高速度为1.2GHZ;
  • 内置64-bit XuanTie C906 RISC-V协处理器(仅T113-S4支持);
  • 支持JPEG/MJPEG视频编码,最大分辨率1080p@60fps;支持多格式1080P@60fps视频解码 (H.265,H.264, MPEG-1/2/4);
  • 支持RGB666/LVDS/MIPI-DSI,分辨率最高1920x1080;
  • 支持128-256M Bytes DDR3 SDRAM,其中T113-S3内置128MB;T113-S4内置256MB;
  • 支持SPI NAND存储和启动(默认:256MB;最大1GB)或者EMMC启动(默认:4GB,最大32GB);
  • 支持一路USB2.0 OTG(设计为TYPE-A接口);支持二路USB2.0 HOST;
  • 支持七路RS232通信或者6路RS232和1路RS485(隔离);
  • 支持一路CAN BUS通信(隔离);
  • 支持一路10/100M以太网;
  • 稳定的操作系统的支持,可预装LINUX 5.4或者OpenWRT;
  • 经典尺寸主板,尺寸为120*100MM;

产品功能评估图:

产品尺寸:

 

打开CH341 CP210X驱动

CONFIG_USB_SERIAL_CONSOLE=y

CONFIG_USB_SERIAL_GENERIC=y

CONFIG_USB_SERIAL_SIMPLE=y

CONFIG_USB_SERIAL_CH341=y

CONFIG_USB_SERIAL_CP210X=y

ttyS3 修改为 ttyS4

longan/kernel/linux-4.9/drivers/tty/tty_io.c

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c

old mode 100644 new mode 100755 index 33f80b0..3945013 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1346,11 +1346,17 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)

  */

 static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)

 {

+ //int len = -1;         if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)

                return sprintf(p, "%s", driver->name);

- else - return sprintf(p, "%s%d", driver->name, - index + driver->name_base); + else{ + if ((index + driver->name_base) == 3) + return sprintf(p, "%s%d", driver->name, + index + driver->name_base + 6); // ttyS3->ttyS9 + else + return sprintf(p, "%s%d", driver->name, + index + driver->name_base); + }  }

串口软链接

symlink /dev/ttyS3 /dev/s3c2410_serial3

USB 转串口设备的识别过程

当我们的USB Modem设备插入USB端口时,要调用bus_add_device()在USB总线上添加一个USB设备。

./drivers/usb/core/usb.c

static int __init usb_init(void)

{

    int retval;

   

    //---------------------------------------------

    //可以看到在 usb_init 初始化函数中调用了bus_register 注册了一条USB总线

    retval = bus_register(&usb_bus_type);

   

    //---------------------------------------------

   

    // usb_generic_driver 这个驱动程序注册给系统

    retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);

}

./drivers/usb/core/generic.c

该USB设备由于有USB设备号,会找到刚才注册的usb_generic_driver中的generic_probe()函数,在这个函数中经过一系列的函数调用最后会 进入usb_set_configuration()

static int generic_probe(struct usb_device *udev)

{

    int err, c;

    /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */

    if (udev->authorized == 0)

        dev_err(&udev->dev, "Device is not authorized for usage\n");

    else {

        c = usb_choose_configuration(udev);

        if (c >= 0) {

            err = usb_set_configuration(udev, c);

            if (err && err != -ENODEV) {

                dev_err(&udev->dev, "can't set config #%d, error %d\n",

                    c, err);

                /* This need not be fatal. The user can try to * set other configurations. */

            }

        }

    }

    /* USB device state == configured ... usable */

    usb_notify_add_device(udev);

    return 0;

}

struct usb_device_driver usb_generic_driver = {

    .name = "usb",

    .probe = generic_probe,

    .disconnect = generic_disconnect,

#ifdef CONFIG_PM    .suspend = generic_suspend,

    .resume = generic_resume,

#endif  .supports_autosuspend = 1,

drivers/usb/serial/usb-serial.c

usb_set_configuration()函数会根据HOST和Device沟通的情况,进行总线枚举, 该函数会依次将这个interface添加到USB总线上, 根据VID和PID找到合适自己的probe函数,这里设备接口会进入usb_serial_probe()。

usb_serial_init()函数会调用tty_register_driver(usb_serial_tty_driver)向内核注册tty类的设备驱动,并在USB转串口总线上添加这个驱动。

static int __init usb_serial_init(void)

{

//-----------------------------------------------------------------------------

       result = tty_register_driver(usb_serial_tty_driver);

       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);

       if (result < 0) {

              pr_err("%s - usb_register failed\n", __func__);

              goto exit_tty;

       }

//---------------------------------------------------------------------------------------

}

static int allocate_minors(struct usb_serial *serial, int num_ports)

{

       struct usb_serial_port *port;

       unsigned int i, j;

       int minor;

       dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports);

       mutex_lock(&table_lock);

       for (i = 0; i < num_ports; ++i) {

              port = serial->port[i];

              //modify by lixiaogang start

              if (!strcmp(serial->type->description, "ch341-uart")) {

                  minor = idr_alloc(&serial_minors, port, 8,

                                      USB_SERIAL_TTY_MINORS, GFP_KERNEL);

              } else {

                  minor = idr_alloc(&serial_minors, port, 0,

                                      USB_SERIAL_TTY_MINORS, GFP_KERNEL);

              }

              //modify by lixiaogang end

              if (minor < 0)

                    goto error;

              port->minor = minor;

              port->port_number = i;

       }

//-----------------------------------------------------------------------------------------

       return minor;

}

static int usb_serial_probe(struct usb_interface *interface,

                           const struct usb_device_id *id)

{

       struct device *ddev = &interface->dev;

       struct usb_device *dev = interface_to_usbdev(interface);

        // 保存该设备的详细信息

       struct usb_serial *serial = NULL;

       struct usb_serial_port *port;

       struct usb_host_interface *iface_desc;

       struct usb_endpoint_descriptor *endpoint;

       struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];

       struct usb_endpoint_descriptor *interrupt_out_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_driver *type = NULL;

//----------------------------------------------------------------------------------------

       serial = create_serial(dev, interface, type);

       if (!serial) {

              module_put(type->driver.owner);

              return -ENOMEM;

       }

//---------------------------------------------------------------------------------------

       if (allocate_minors(serial, num_ports)) {

              dev_err(ddev, "No more free serial minor numbers\n");

              goto probe_error;

       }

       /* register all of the individual ports with the driver core */

       for (i = 0; i < num_ports; ++i) {

              port = serial->port[i];

              dev_set_name(&port->dev, "ttyUSB%d", port->minor);

              dev_dbg(ddev, "registering %s\n", dev_name(&port->dev));

              device_enable_async_suspend(&port->dev);

              retval = device_add(&port->dev);

              if (retval)

                    dev_err(ddev, "Error registering port device, continuing\n");

       }

//---------------------------------------------------------------------------------------

}

./drivers/usb/serial/ch341.c

static int ch341_port_probe(struct usb_serial_port *port)

{

       struct ch341_private *priv;

       int r;

       priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);

       if (!priv)

              return -ENOMEM;

       spin_lock_init(&priv->lock);

       priv->baud_rate = DEFAULT_BAUD_RATE;

       r = ch341_configure(port->serial->dev, priv);

       if (r < 0)

              goto error;

       usb_set_serial_port_data(port, priv);

       return 0;

error: kfree(priv);

       return r;

}

static struct usb_serial_driver ch341_device = {

       .driver = {

              .owner = THIS_MODULE,

              .name  = "ch341-uart",

       },

       .id_table          = id_table,

       .num_ports         = 1,

       .open              = ch341_open,

       .dtr_rts         = ch341_dtr_rts,

       .carrier_raised        = ch341_carrier_raised,

       .close             = ch341_close,

       .set_termios       = ch341_set_termios,

       .break_ctl         = ch341_break_ctl,

       .tiocmget          = ch341_tiocmget,

       .tiocmset          = ch341_tiocmset,

       .tiocmiwait        = usb_serial_generic_tiocmiwait,

       .read_int_callback = ch341_read_int_callback,

       .port_probe        = ch341_port_probe,

       .port_remove       = ch341_port_remove,

       .reset_resume      = ch341_reset_resume,

};

可插拔 USB 转串口固定编号

Linux

在 Linux 系统中,CH341 USB 转串口转换器的设备文件通常被分配为 /dev/ttyUSBx 的形式,其中 x 是一个数字。这个数字表示设备在系统中的顺序,当插入或拔出其他 USB 设备时,它可能会发生变化。

如果你希望固定 CH341 的 ttyUSB 串口号,你可以通过修改 udev 规则来实现这一点。以下是一个简单的步骤:

  1. 创建一个新的 udev 规则: 在 /etc/udev/rules.d 目录下创建一个新文件,例如 99-ch341.rules。
  2. 编辑规则文件: 使用文本编辑器打开刚才创建的规则文件,并添加以下内容:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="ch341"

这条规则表示所有 vendor ID 为 1a86 和 product ID 为 7523 的设备(这是 CH341 转换器的默认值)都应该被创建一个符号链接,名称为 ch341。

android

/kernel/linux-4.9/drivers/usb/serial/usb-serial.c

CH341串口编号从ttyUSB8开始分配

diff --git a/longan/kernel/linux-4.9/drivers/usb/serial/usb-serial.c b/longan/kernel/linux-4.9/drivers/usb/serial/usb-serial.c

index 4a037b4a79..ed9a2fc5f9 100644 --- a/longan/kernel/linux-4.9/drivers/usb/serial/usb-serial.c +++ b/longan/kernel/linux-4.9/drivers/usb/serial/usb-serial.c @@ -96,8 +96,15 @@ static int allocate_minors(struct usb_serial *serial, int num_ports)

        mutex_lock(&table_lock);

        for (i = 0; i < num_ports; ++i) {

                port = serial->port[i];

- minor = idr_alloc(&serial_minors, port, 0, - USB_SERIAL_TTY_MINORS, GFP_KERNEL); + //modify by lixiaogang start + if (!strcmp(serial->type->description, "ch341-uart")) { + minor = idr_alloc(&serial_minors, port, 8, + USB_SERIAL_TTY_MINORS, GFP_KERNEL); + } else { + minor = idr_alloc(&serial_minors, port, 0, + USB_SERIAL_TTY_MINORS, GFP_KERNEL); + } + //modify by lixiaogang end                 if (minor < 0)

                        goto error;

                port->minor = minor,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值