From 63295cb2ff4329f563579f3d20c5855a96a866d5 Mon Sep 17 00:00:00 2001 From: Claudio Scordino Date: Thu, 11 Nov 2010 11:22:36 +0100 Subject: serial: add Documentation about RS485 serial communications Documentation about RS485 serial communications Signed-off-by: Claudio Scordino Acked-by: Randy Dunlap Acked-by: Russell King Acked-by: Grant Edwards Signed-off-by: Greg Kroah-Hartman --- Documentation/serial/00-INDEX | 2 + Documentation/serial/serial-rs485.txt | 119 ++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 Documentation/serial/serial-rs485.txt (limited to 'Documentation') diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX index 07dcdb0d2a36..e09468ad3cb1 100644 --- a/Documentation/serial/00-INDEX +++ b/Documentation/serial/00-INDEX @@ -14,6 +14,8 @@ riscom8.txt - notes on using the RISCom/8 multi-port serial driver. rocket.txt - info on the Comtrol RocketPort multiport serial driver. +serial-rs485.txt + - info about RS485 structures and support in the kernel. specialix.txt - info on hardware/driver for specialix IO8+ multiport serial card. stallion.txt diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt new file mode 100644 index 000000000000..a3b1af7b6db9 --- /dev/null +++ b/Documentation/serial/serial-rs485.txt @@ -0,0 +1,119 @@ + RS485 SERIAL COMMUNICATIONS + +1. INTRODUCTION + + EIA-485, also known as TIA/EIA-485 or RS-485, is a standard defining the + electrical characteristics of drivers and receivers for use in balanced + digital multipoint systems. + This standard is widely used for communications in industrial automation + because it can be used effectively over long distances and in electrically + noisy environments. + +2. HARDWARE-RELATED CONSIDERATIONS + + Some CPUs (e.g., Atmel AT91) contain a built-in half-duplex mode capable of + automatically controlling line direction by toggling RTS. That can used to + control external half-duplex hardware like an RS485 transceiver or any + RS232-connected half-duplex device like some modems. + + For these microcontrollers, the Linux driver should be made capable of + working in both modes, and proper ioctls (see later) should be made + available at user-level to allow switching from one mode to the other, and + vice versa. + +3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL + + The Linux kernel provides the serial_rs485 structure (see [1]) to handle + RS485 communications. This data structure is used to set and configure RS485 + parameters in the platform data and in ioctls. + + Any driver for devices capable of working both as RS232 and RS485 should + provide at least the following ioctls: + + - TIOCSRS485 (typically associated with number 0x542F). This ioctl is used + to enable/disable RS485 mode from user-space + + - TIOCGRS485 (typically associated with number 0x542E). This ioctl is used + to get RS485 mode from kernel-space (i.e., driver) to user-space. + + In other words, the serial driver should contain a code similar to the next + one: + + static struct uart_ops atmel_pops = { + /* ... */ + .ioctl = handle_ioctl, + }; + + static int handle_ioctl(struct uart_port *port, + unsigned int cmd, + unsigned long arg) + { + struct serial_rs485 rs485conf; + + switch (cmd) { + case TIOCSRS485: + if (copy_from_user(&rs485conf, + (struct serial_rs485 *) arg, + sizeof(rs485conf))) + return -EFAULT; + + /* ... */ + break; + + case TIOCGRS485: + if (copy_to_user((struct serial_rs485 *) arg, + ..., + sizeof(rs485conf))) + return -EFAULT; + /* ... */ + break; + + /* ... */ + } + } + + +4. USAGE FROM USER-LEVEL + + From user-level, RS485 configuration can be get/set using the previous + ioctls. For instance, to set RS485 you can use the following code: + + #include + + /* Driver-specific ioctls: */ + #define TIOCGRS485 0x542E + #define TIOCSRS485 0x542F + + /* Open your specific device (e.g., /dev/mydevice): */ + int fd = open ("/dev/mydevice", O_RDWR); + if (fd < 0) { + /* Error handling. See errno. */ + } + + struct serial_rs485 rs485conf; + + /* Set RS485 mode: */ + rs485conf.flags |= SER_RS485_ENABLED; + + /* Set rts delay before send, if needed: */ + rs485conf.flags |= SER_RS485_RTS_BEFORE_SEND; + rs485conf.delay_rts_before_send = ...; + + /* Set rts delay after send, if needed: */ + rs485conf.flags |= SER_RS485_RTS_AFTER_SEND; + rs485conf.delay_rts_after_send = ...; + + if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) { + /* Error handling. See errno. */ + } + + /* Use read() and write() syscalls here... */ + + /* Close the device when finished: */ + if (close (fd) < 0) { + /* Error handling. See errno. */ + } + +5. REFERENCES + + [1] include/linux/serial.h -- cgit v1.2.3 From 23308ba54dcdb54481163bfb07dd8aeca76a7a2e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 4 Nov 2010 16:20:24 +0100 Subject: console: add /proc/consoles It allows users to see what consoles are currently known to the system and with what flags. It is based on Werner's patch, the part about traversing fds was removed, the code was moved to kernel/printk.c, where consoles are handled and it makes more sense to me. Signed-off-by: Jiri Slaby [cleanups] Signed-off-by: "Dr. Werner Fink" Cc: Al Viro Cc: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/proc.txt | 24 ++++++++ fs/proc/Makefile | 1 + fs/proc/proc_console.c | 114 +++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 fs/proc/proc_console.c (limited to 'Documentation') diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index e73df2722ff3..9471225212c4 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1181,6 +1181,30 @@ Table 1-12: Files in /proc/fs/ext4/ mb_groups details of multiblock allocator buddy cache of free blocks .............................................................................. +2.0 /proc/consoles +------------------ +Shows registered system console lines. + +To see which character device lines are currently used for the system console +/dev/console, you may simply look into the file /proc/consoles: + + > cat /proc/consoles + tty0 -WU (ECp) 4:7 + ttyS0 -W- (Ep) 4:64 + +The columns are: + + device name of the device + operations R = can do read operations + W = can do write operations + U = can do unblank + flags E = it is enabled + C = it is prefered console + B = it is primary boot console + p = it is used for printk buffer + b = it is not a TTY but a Braille device + a = it is safe to use when cpu is offline + major:minor major and minor number of the device separated by a colon ------------------------------------------------------------------------------ Summary diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 2758e2afc518..288a49e098bf 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -15,6 +15,7 @@ proc-y += devices.o proc-y += interrupts.o proc-y += loadavg.o proc-y += meminfo.o +proc-y += proc_console.o proc-y += stat.o proc-y += uptime.o proc-y += version.o diff --git a/fs/proc/proc_console.c b/fs/proc/proc_console.c new file mode 100644 index 000000000000..8a707609f528 --- /dev/null +++ b/fs/proc/proc_console.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010 Werner Fink, Jiri Slaby + * + * Licensed under GPLv2 + */ + +#include +#include +#include +#include +#include + +/* + * This is handler for /proc/consoles + */ +static int show_console_dev(struct seq_file *m, void *v) +{ + static const struct { + short flag; + char name; + } con_flags[] = { + { CON_ENABLED, 'E' }, + { CON_CONSDEV, 'C' }, + { CON_BOOT, 'B' }, + { CON_PRINTBUFFER, 'p' }, + { CON_BRL, 'b' }, + { CON_ANYTIME, 'a' }, + }; + char flags[ARRAY_SIZE(con_flags) + 1]; + struct console *con = v; + unsigned int a; + int len; + dev_t dev = 0; + + if (con->device) { + const struct tty_driver *driver; + int index; + driver = con->device(con, &index); + if (driver) { + dev = MKDEV(driver->major, driver->minor_start); + dev += index; + } + } + + for (a = 0; a < ARRAY_SIZE(con_flags); a++) + flags[a] = (con->flags & con_flags[a].flag) ? + con_flags[a].name : ' '; + flags[a] = 0; + + seq_printf(m, "%s%d%n", con->name, con->index, &len); + len = 21 - len; + if (len < 1) + len = 1; + seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-', + con->write ? 'W' : '-', con->unblank ? 'U' : '-', + flags); + if (dev) + seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev)); + + seq_printf(m, "\n"); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + struct console *con; + loff_t off = 0; + + acquire_console_sem(); + for_each_console(con) + if (off++ == *pos) + break; + + return con; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct console *con = v; + ++*pos; + return con->next; +} + +static void c_stop(struct seq_file *m, void *v) +{ + release_console_sem(); +} + +static const struct seq_operations consoles_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_console_dev +}; + +static int consoles_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &consoles_op); +} + +static const struct file_operations proc_consoles_operations = { + .open = consoles_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int register_proc_consoles(void) +{ + proc_create("consoles", 0, NULL, &proc_consoles_operations); + return 0; +} +module_init(register_proc_consoles); -- cgit v1.2.3 From de6f86ce51341559dc3c9c9f5c562da12fcfcb31 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Mon, 22 Nov 2010 11:06:32 +0100 Subject: RS485 documentation: add 16C950 UART description Add a notion about 16C950 UART, that is using DTR signal for RS485 mode. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- Documentation/serial/serial-rs485.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt index a3b1af7b6db9..a4932387bbfb 100644 --- a/Documentation/serial/serial-rs485.txt +++ b/Documentation/serial/serial-rs485.txt @@ -11,10 +11,11 @@ 2. HARDWARE-RELATED CONSIDERATIONS - Some CPUs (e.g., Atmel AT91) contain a built-in half-duplex mode capable of - automatically controlling line direction by toggling RTS. That can used to - control external half-duplex hardware like an RS485 transceiver or any - RS232-connected half-duplex device like some modems. + Some CPUs/UARTs (e.g., Atmel AT91 or 16C950 UART) contain a built-in + half-duplex mode capable of automatically controlling line direction by + toggling RTS or DTR signals. That can be used to control external + half-duplex hardware like an RS485 transceiver or any RS232-connected + half-duplex devices like some modems. For these microcontrollers, the Linux driver should be made capable of working in both modes, and proper ioctls (see later) should be made -- cgit v1.2.3 From fbc92a3455577ab17615cbcb91826399061bd789 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 1 Dec 2010 18:51:05 +0100 Subject: tty: add 'active' sysfs attribute to tty0 and console device tty: add 'active' sysfs attribute to tty0 and console device Userspace can query the actual virtual console, and the configured console devices behind /dev/tt0 and /dev/console. The last entry in the list of devices is the active device, analog to the console= kernel command line option. The attribute supports poll(), which is raised when the virtual console is changed or /dev/console is reconfigured. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman index 0000000..b138b66 --- Documentation/ABI/testing/sysfs-tty | 19 +++++++++++++++ drivers/tty/tty_io.c | 47 +++++++++++++++++++++++++++++++++---- drivers/tty/vt/vt.c | 23 +++++++++++++++++- include/linux/console.h | 2 +- kernel/printk.c | 2 ++ 5 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-tty (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty new file mode 100644 index 000000000000..b138b663bf54 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-tty @@ -0,0 +1,19 @@ +What: /sys/class/tty/console/active +Date: Nov 2010 +Contact: Kay Sievers +Description: + Shows the list of currently configured + console devices, like 'tty1 ttyS0'. + The last entry in the file is the active + device connected to /dev/console. + The file supports poll() to detect virtual + console switches. + +What: /sys/class/tty/tty0/active +Date: Nov 2010 +Contact: Kay Sievers +Description: + Shows the currently active virtual console + device, like 'tty1'. + The file supports poll() to detect virtual + console switches. diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c05c5af5aa04..be5ab4ac0b93 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3232,9 +3232,45 @@ static int __init tty_class_init(void) postcore_initcall(tty_class_init); /* 3/2004 jmc: why do these devices exist? */ - static struct cdev tty_cdev, console_cdev; +static ssize_t show_cons_active(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct console *cs[16]; + int i = 0; + struct console *c; + ssize_t count = 0; + + acquire_console_sem(); + for (c = console_drivers; c; c = c->next) { + if (!c->device) + continue; + if (!c->write) + continue; + if ((c->flags & CON_ENABLED) == 0) + continue; + cs[i++] = c; + if (i >= ARRAY_SIZE(cs)) + break; + } + while (i--) + count += sprintf(buf + count, "%s%d%c", + cs[i]->name, cs[i]->index, i ? ' ':'\n'); + release_console_sem(); + + return count; +} +static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL); + +static struct device *consdev; + +void console_sysfs_notify(void) +{ + if (consdev) + sysfs_notify(&consdev->kobj, NULL, "active"); +} + /* * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. @@ -3245,15 +3281,18 @@ int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, - "tty"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, + consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + if (IS_ERR(consdev)) + consdev = NULL; + else + device_create_file(consdev, &dev_attr_active); #ifdef CONFIG_VT vty_init(&console_fops); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index a8ec48ed14d9..76407eca9ab0 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -235,6 +235,14 @@ enum { blank_vesa_wait, }; +/* + * /sys/class/tty/tty0/ + * + * the attribute 'active' contains the name of the current vc + * console and it supports poll() to detect vc switches + */ +static struct device *tty0dev; + /* * Notifier list for console events. */ @@ -688,6 +696,8 @@ void redraw_screen(struct vc_data *vc, int is_switch) save_screen(old_vc); set_origin(old_vc); } + if (tty0dev) + sysfs_notify(&tty0dev->kobj, NULL, "active"); } else { hide_cursor(vc); redraw = 1; @@ -2967,13 +2977,24 @@ static const struct tty_operations con_ops = { static struct cdev vc0_cdev; +static ssize_t show_tty_active(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "tty%d\n", fg_console + 1); +} +static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL); + int __init vty_init(const struct file_operations *console_fops) { cdev_init(&vc0_cdev, console_fops); if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + if (IS_ERR(tty0dev)) + tty0dev = NULL; + else + device_create_file(tty0dev, &dev_attr_active); vcs_init(); diff --git a/include/linux/console.h b/include/linux/console.h index 875cfb1c8132..9774fe6a1a97 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -151,7 +151,7 @@ extern int is_console_locked(void); extern int braille_register_console(struct console *, int index, char *console_options, char *braille_options); extern int braille_unregister_console(struct console *); - +extern void console_sysfs_notify(void); extern int console_suspend_enabled; /* Suspend and resume console messages over PM events */ diff --git a/kernel/printk.c b/kernel/printk.c index bf0420a92a1a..5417784a76b5 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1332,6 +1332,7 @@ void register_console(struct console *newcon) spin_unlock_irqrestore(&logbuf_lock, flags); } release_console_sem(); + console_sysfs_notify(); /* * By unregistering the bootconsoles after we enable the real console @@ -1390,6 +1391,7 @@ int unregister_console(struct console *console) console_drivers->flags |= CON_CONSDEV; release_console_sem(); + console_sysfs_notify(); return res; } EXPORT_SYMBOL(unregister_console); -- cgit v1.2.3