在procttydriver添加serial⽂件,来统计系统的串⼝设备的统计
信息
1、⽬前系统有4类串⼝设备 omap  spi  usb  4g,美⼀类都有⾃⼰的信息。需要统⼀到⼀个⽂件⾥
2、在D:\z_linux_picohood_project\board-support_xj\board-support\linux-4.4.x-mainline\linux-4.4.x-mainline\drivers\tty\serial\serial_core.c   添加⾃⼰的lsh_serial_uart_proc_fops
/*add by lsh*/
const struct file_operations lsh_serial_uart_proc_fops = {
.owner  = THIS_MODULE,
.open  = uart_proc_open,
.read  = seq_read,
.llseek  = seq_lseek,
.release = single_release,
};
EXPORT_SYMBOL_GPL(lsh_serial_uart_proc_fops);
3、在D:\z_linux_picohood_project\board-support_xj\board-support\linux-4.4.x-mainline\linux-4.4.x-mainline\fs\proc\proc_tty.c
  添加proc_create_data("serial", 0, proc_tty_driver,  &lsh_serial_uart_proc_fops, NULL);
void __init proc_tty_init(void)
{
if (!proc_mkdir("tty", NULL))
return;
proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */
/*
* /proc/tty/driver/serial reveals the exact character counts for
* serial links which is just too easy to abuse for inferring
* password lengths and inter-keystroke timings during password
* entry.
*/
proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
/*add by lsh*/
//proc_create("tty/driver/serial", 0, NULL, &lsh_serial_uart_proc_fops);
proc_create_data("serial", 0, proc_tty_driver,  &lsh_serial_uart_proc_fops, NULL);
}
4、添加⼀个函数通过⽂件名到对应的struct tty_driver函数
/*add by lsh*/
struct tty_driver * return_my_serial_proc_tty_driver(const char *name)
{
struct tty_driver *ttydrv;
struct proc_dir_entry * file_dir;
file_dir = pde_subdir_find(proc_tty_driver,name,strlen(name));
ttydrv = file_dir->data;
return ttydrv;
}
5、添加对应驱动的串⼝统计的数据打印到指定⽂件
/
*add by lsh*/
static void serial_uart_line_info(struct seq_file *m, struct uart_driver *drv, int i, int disp_nr)
{
struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
enum uart_pm_state pm_state;
struct uart_port *uport = state->uart_port;
char stat_buf[32];
unsigned int status;
int mmio;
if (!uport)
return;
mmio = uport->iotype >= UPIO_MEM;
seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
disp_nr, mmio ? "OMAPSERI" : "MAX14830",
mmio ? "mmio:0x" : "port:0x",
mmio ? (unsigned long long)uport->mapbase
: (unsigned long long)uport->iobase,
uport->irq);
if (uport->type == PORT_UNKNOWN) {
seq_putc(m, '\n');
return;
}
if (capable(CAP_SYS_ADMIN)) {
mutex_lock(&port->mutex);
pm_state = state->pm_state;
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, UART_PM_STATE_ON);
spin_lock_irq(&uport->lock);
status = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, pm_state);
模拟串口使用printf函数mutex_unlock(&port->mutex);
seq_printf(m, " tx:%d rx:%d",
uport-&, uport-&);
if (uport->icount.frame)
seq_printf(m, " fe:%d",
uport->icount.frame);
if (uport->icount.parity)
seq_printf(m, " pe:%d",
uport->icount.parity);
if (uport->icount.brk)
seq_printf(m, " brk:%d",
uport->icount.brk);
if (uport->icount.overrun)
seq_printf(m, " oe:%d",
uport->icount.overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
strncat(stat_buf, (str), sizeof(stat_buf) - \
strlen(stat_buf) - 2)
#define STATBIT(bit, str) \
if (status & (bit)) \
strncat(stat_buf, (str), sizeof(stat_buf) - \
strlen(stat_buf) - 2)
stat_buf[0] = '\0';
stat_buf[1] = '\0';
INFOBIT(TIOCM_RTS, "|RTS");
STATBIT(TIOCM_CTS, "|CTS");
INFOBIT(TIOCM_DTR, "|DTR");
STATBIT(TIOCM_DSR, "|DSR");
STATBIT(TIOCM_CAR, "|CD");
STATBIT(TIOCM_RNG, "|RI");
if (stat_buf[0])
stat_buf[0] = ' ';
seq_puts(m, stat_buf);
}
seq_putc(m, '\n');
#undef STATBIT
#undef INFOBIT
}
 6、usb转串⼝的数据⽐较不⼀致,需要单独加显⽰函数
/* add by lsh*/
static int usb_serial_proc_show(struct seq_file *m,struct tty_driver *ttydrv,int i,int disp_nr) {
struct tty_struct *tty;
struct usb_serial *serial;
struct usb_serial_port *port;
char stat_buf[40];
unsigned int status;
port = usb_serial_port_get_by_minor(i);
if (port == NULL)
return 0;
serial = port->serial;
/*******************************************************************************/
/*add by lsh */
seq_printf(m, "%d: uart:%s %s%08X irq:%d",
disp_nr,module_name(serial->type->driver.owner),
"port:0x",
(unsigned int)port,
183);
seq_printf(m, " tx:%d rx:%d",
port-&, port-&);
if (port->icount.frame)
seq_printf(m, " fe:%d",
port->icount.frame);
if (port->icount.parity)
seq_printf(m, " pe:%d",
port->icount.parity);
if (port->icount.brk)
seq_printf(m, " brk:%d",
port->icount.brk);
if (port->icount.overrun)
seq_printf(m, " oe:%d",
port->icount.overrun);
seq_printf(m, " DSR|",
port->icount.overrun);
seq_printf(m, "CD",
port->icount.overrun);
/*
tty = tty_port_tty_get(&port->port);
status = serial->type->tiocmget(tty);  //kernel null pointer
#define STATBIT(bit, str) \
if (status & (bit)) \
strncat(stat_buf, (str), sizeof(stat_buf) - \
strlen(stat_buf) - 2)
stat_buf[0] = '\0';
stat_buf[1] = '\0';
STATBIT(TIOCM_RTS, "|RTS");
STATBIT(TIOCM_CTS, "|CTS");
STATBIT(TIOCM_DTR, "|DTR");
STATBIT(TIOCM_DSR, "|DSR");
STATBIT(TIOCM_CAR, "|CD");
STATBIT(TIOCM_RNG, "|RI");
if (stat_buf[0])
stat_buf[0] = ' ';
seq_puts(m, stat_buf);
*/
seq_putc(m, '\n');
/*******************************************************************************/
usb_serial_put(serial);
mutex_unlock(&serial->disc_mutex);
#undef STATBIT
}
 7、usb需要通过此设备号,获取当前的串⼝号,需要将改函数导出usb_serial_port_get_by_minor
  D:\z_linux_picohood_project\board-support_xj\board-support\linux-4.4.x-mainline\linux-4.4.x-mainline\drivers\usb\serial\usb-serial.c struct usb_serial_port *usb_serial_port_get_by_minor(unsigned minor)
{
struct usb_serial *serial;
struct usb_serial_port *port;
mutex_lock(&table_lock);
port = idr_find(&serial_minors, minor);
if (!port)
goto exit;
serial = port->serial;
mutex_lock(&serial->disc_mutex);
if (serial->disconnected) {
mutex_unlock(&serial->disc_mutex);
port = NULL;
} else {
kref_get(&serial->kref);
}
exit:
mutex_unlock(&table_lock);
return port;
}
/*add by lsh*/
EXPORT_SYMBOL_GPL(usb_serial_port_get_by_minor);
 8、usb串⼝要配置⼀个⽂件名,才会在、/proc/tty/driver/ 下⽣成 usbseriver⽂件,其他的⽂件都是在对应驱动注册时。加⼊了配置
  D:\z_linux_picohood_project\board-support_xj\board-support\linux-4.4.x-mainline\linux-4.4.x-mainline\drivers\usb\serial\usb-serial.c
static int __init usb_serial_init(void)
{
int result;
usb_serial_tty_driver = alloc_tty_driver(USB_SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
/* Initialize our global data */
result = bus_register(&usb_serial_bus_type);
if (result) {
pr_err("%s - registering bus driver failed\n", __func__);
goto exit_bus;
}
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->name = "ttyUSB";
usb_serial_tty_driver->major = USB_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);
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;
}
/* 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;
}