11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Simulated Serial Driver (fake serial) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver is mostly used for bringup purposes and will go away. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It has a strong dependency on the system console. All outputs 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are rerouted to the same facility as the one used by printk which, in our 7adb636fe0845bf1b4dbcb546a1673f40a95062fdJiri Slaby * case means sys_sim.c console (goes via the simulator). 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stephane Eranian <eranian@hpl.hp.com> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 22bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan#include <linux/seq_file.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 24a9415644583ef344e02f84faf5fe24bfadb2af8eRandy Dunlap#include <linux/capability.h> 253c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slaby#include <linux/circ_buf.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 278b916330567b0b788f35ded5d99a7ef7dc30b293Jiri Slaby#include <linux/irq.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 30819c67e69c4e0062787e27dd989f5f9d00d4834eDavid Mosberger-Tang#include <linux/sysrq.h> 318b916330567b0b788f35ded5d99a7ef7dc30b293Jiri Slaby#include <linux/uaccess.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33035cfe5ac55d399169b7f61f7a111d3d7075190cJiri Slaby#include <asm/hpsim.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35035cfe5ac55d399169b7f61f7a111d3d7075190cJiri Slaby#include "hpsim_ssc.h" 36035cfe5ac55d399169b7f61f7a111d3d7075190cJiri Slaby 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef SIMSERIAL_DEBUG /* define this to get some debug information */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define KEYBOARD_INTR 3 /* must match with simulator! */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NR_PORTS 1 /* only one port for now */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 433c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slabystruct serial_state { 447f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby struct tty_port port; 453c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slaby struct circ_buf xmit; 463c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slaby int irq; 473c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slaby int x_char; 483c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slaby}; 493c4782dcd9b8d02e79f0f0bd1fe6e30a79790526Jiri Slaby 50fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabystatic struct serial_state rs_table[NR_PORTS]; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct tty_driver *hp_simserial_driver; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct console *console; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 562e124b4a390ca85325fae75764bef92f0547fa25Jiri Slabystatic void receive_chars(struct tty_port *port) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ch; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned char seen_esc = 0; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { 62f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (ch == 27 && seen_esc == 0) { 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seen_esc = 1; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 65f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } else if (seen_esc == 1 && ch == 'O') { 66f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby seen_esc = 2; 67f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby continue; 68f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } else if (seen_esc == 2) { 69f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (ch == 'P') /* F1 */ 70f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby show_state(); 71819c67e69c4e0062787e27dd989f5f9d00d4834eDavid Mosberger-Tang#ifdef CONFIG_MAGIC_SYSRQ 72f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (ch == 'S') { /* F4 */ 73f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby do { 74f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); 75f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } while (!ch); 76f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby handle_sysrq(ch); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 78f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby#endif 79f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby seen_esc = 0; 80f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby continue; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seen_esc = 0; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8492a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0) 85d50f5c5ca0c3426669fbe11ad4d5708d333eb9fbAndreas Schwab break; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 872e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(port); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the serial driver's interrupt routine for a single port 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 935dcded1b0b4f1537bb6dff453fb805517756c94bAl Virostatic irqreturn_t rs_interrupt_single(int irq, void *dev_id) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 95916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = dev_id; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 972e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby receive_chars(&info->port); 982e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------- 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Here ends the serial interrupt routines. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------- 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108f34d7a5b7010b82fe97da95496b9971435530062Alan Coxstatic int rs_put_char(struct tty_struct *tty, unsigned char ch) 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 110916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1136e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby if (!info->xmit.buf) 114f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 0; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 119f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 0; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.buf[info->xmit.head] = ch; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 124f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 1; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1275e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slabystatic void transmit_chars(struct tty_struct *tty, struct serial_state *info, 1285e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby int *intr_done) 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) { 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c = info->x_char; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, &c, 1); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145ee7970690568b0c875467f475d9c957ec0d9e099Jiri Slaby if (info->xmit.head == info->xmit.tail || tty->stopped) { 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SIMSERIAL_DEBUG 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", 1485e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby info->xmit.head, info->xmit.tail, tty->stopped); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We removed the loop and try to do it in to chunks. We need 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 operations maximum because it's a ring buffer. 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First from current to tail if possible. 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Then from the beginning of the buffer until necessary 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SERIAL_XMIT_SIZE - info->xmit.tail); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, info->xmit.buf+info->xmit.tail, count); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have more at the beginning of the buffer 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count) { 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, info->xmit.buf, count); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.tail += count; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_flush_chars(struct tty_struct *tty) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 180916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 182f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->xmit.head == info->xmit.tail || tty->stopped || 183ee7970690568b0c875467f475d9c957ec0d9e099Jiri Slaby !info->xmit.buf) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1865e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_write(struct tty_struct * tty, 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, int count) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 192916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1966e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby if (!info->xmit.buf) 197d88405d44fd30fcbe77a9db540afd8823b30afdcJiri Slaby return 0; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < c) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = count; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) { 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(info->xmit.buf + info->xmit.head, buf, c); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = ((info->xmit.head + c) & 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (SERIAL_XMIT_SIZE-1)); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hey, we transmit directly from here in our case 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 218f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && 219ee7970690568b0c875467f475d9c957ec0d9e099Jiri Slaby !tty->stopped) 2205e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 221f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_write_room(struct tty_struct *tty) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 227916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_chars_in_buffer(struct tty_struct *tty) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 234916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_flush_buffer(struct tty_struct *tty) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 241916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = info->xmit.tail = 0; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24815648f154a8faea97cbe931e189cf0a57fd066f4Alan Cox tty_wakeup(tty); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used to send a high-priority XON/XOFF character to 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_send_xchar(struct tty_struct *tty, char ch) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 257916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = ch; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I guess we could call console->write() directly but 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * let's do that for now. 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2655e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rs_throttle() 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the upper-layer tty layer to signal that 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * incoming characters should be throttled. 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_throttle(struct tty_struct * tty) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 279f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (I_IXOFF(tty)) 280f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby rs_send_xchar(tty, STOP_CHAR(tty)); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simrs_throttle called\n"); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_unthrottle(struct tty_struct * tty) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 287916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rs_send_xchar(tty, START_CHAR(tty)); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simrs_unthrottle called\n"); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29810e82f6ce76351425644bccc56f8e2c2ad596ce6Tony Luckstatic int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && 3020587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox (cmd != TIOCMIWAIT)) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 308f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCGSERIAL: 309f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSSERIAL: 310f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGSTRUCT: 311f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCMIWAIT: 312f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return 0; 313f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERCONFIG: 314f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGETLSR: /* Get line status register */ 315f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return -EINVAL; 316f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGWILD: 317f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERSWILD: 318f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby /* "setserial -W" is called in Debian boot */ 319f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); 320f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return 0; 321f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } 322f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return -ENOIOCTLCMD; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will shutdown a serial port; interrupts are disabled, and 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DTR is dropped if the hangup on close termio flag is on. 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 331458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slabystatic void shutdown(struct tty_port *port) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 333458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby struct serial_state *info = container_of(port, struct serial_state, 334458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby port); 335458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby unsigned long flags; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 338f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->irq) 339f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby free_irq(info->irq, info); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->xmit.buf) { 342f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby free_page((unsigned long) info->xmit.buf); 343f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby info->xmit.buf = NULL; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_close(struct tty_struct *tty, struct file * filp) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 350916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 35137343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby 352458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby tty_port_close(&info->port, tty, filp); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_hangup(struct tty_struct *tty) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 357916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rs_flush_buffer(tty); 360458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby tty_port_hangup(&info->port); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3639aead90a7f5772fc74f733242d953688748b0ce4Jiri Slabystatic int activate(struct tty_port *port, struct tty_struct *tty) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3659aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby struct serial_state *state = container_of(port, struct serial_state, 3669aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby port); 367f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby unsigned long flags, page; 368f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby int retval = 0; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = get_zeroed_page(GFP_KERNEL); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 376916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby if (state->xmit.buf) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page(page); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 379916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby state->xmit.buf = (unsigned char *) page; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381964105b501071e8a0e9feb1d0e4b3e46508bc38eJiri Slaby if (state->irq) { 3822f8c521a1d41faf96f729c76991eb4ad70294513Jiri Slaby retval = request_irq(state->irq, rs_interrupt_single, 0, 383916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby "simserial", state); 3849e12dd5fce1c676e709625bd2f55dc83664c3c93Jiri Slaby if (retval) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto errout; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 388916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby state->xmit.head = state->xmit.tail = 0; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the tty->alt_speed kludge 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39301bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) 3945e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 57600; 39501bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) 3965e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 115200; 39701bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) 3985e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 230400; 39901bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) 4005e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 460800; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserrout: 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called whenever a serial port is opened. It 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enables interrupts for a serial port, linking in its async structure into 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IRQ chain. It also performs the serial-specific 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialization for the tty structure. 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_open(struct tty_struct *tty, struct file * filp) 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 416916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = rs_table + tty->index; 4177f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby struct tty_port *port = &info->port; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 419916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby tty->driver_data = info; 420d6c53c0e9bd0a83f9f9ddbc9fd80141a54d83896Jiri Slaby port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out which console to use (should be one already) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = console_drivers; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (console) { 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((console->flags & CON_ENABLED) && console->write) break; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = console->next; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4319aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby return tty_port_open(port, tty, filp); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /proc fs routines.... 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 438bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic int rs_proc_show(struct seq_file *m, void *v) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 440bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan int i; 441bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 4426e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby seq_printf(m, "simserinfo:1.0\n"); 443bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan for (i = 0; i < NR_PORTS; i++) 44498e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", 44598e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby i, rs_table[i].irq); 446bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan return 0; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 449bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic int rs_proc_open(struct inode *inode, struct file *file) 450bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan{ 451bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan return single_open(file, rs_proc_show, NULL); 452bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan} 453bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 454bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic const struct file_operations rs_proc_fops = { 455bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .owner = THIS_MODULE, 456bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .open = rs_proc_open, 457bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .read = seq_read, 458bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .llseek = seq_lseek, 459bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .release = single_release, 460bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan}; 461bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 462b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations hp_ops = { 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = rs_open, 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = rs_close, 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = rs_write, 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = rs_put_char, 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = rs_flush_chars, 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = rs_write_room, 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = rs_chars_in_buffer, 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = rs_flush_buffer, 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = rs_ioctl, 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = rs_throttle, 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = rs_unthrottle, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = rs_send_xchar, 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = rs_hangup, 476bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .proc_fops = &rs_proc_fops, 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47937343030458c0eea3f1093b09fc604d4f300eac7Jiri Slabystatic const struct tty_port_operations hp_port_ops = { 4809aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby .activate = activate, 481458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby .shutdown = shutdown, 48237343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby}; 48337343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby 484fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabystatic int __init simrs_init(void) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 486fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby struct serial_state *state; 487fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby int retval; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ia64_platform_is("hpsim")) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 492410235fd4d20b8feaf8930a0575d23acc088aa87Jiri Slaby hp_simserial_driver = alloc_tty_driver(NR_PORTS); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!hp_simserial_driver) 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4966e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the tty_driver structure */ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->driver_name = "simserial"; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->name = "ttyS"; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->major = TTY_MAJOR; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->minor_start = 64; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL; 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->init_termios = tty_std_termios; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->init_termios.c_cflag = 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B9600 | CS8 | CREAD | HUPCL | CLOCAL; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(hp_simserial_driver, &hp_ops); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 512fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby state = rs_table; 5137f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby tty_port_init(&state->port); 51437343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby state->port.ops = &hp_port_ops; 5157f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby state->port.close_delay = 0; /* XXX really 0? */ 516fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby 517fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby retval = hpsim_get_irq(KEYBOARD_INTR); 518fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby if (retval < 0) { 519fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby printk(KERN_ERR "%s: out of interrupt vectors!\n", 520fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby __func__); 521fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby goto err_free_tty; 522fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby } 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 524fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby state->irq = retval; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 526fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby /* the port is imaginary */ 52798e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 529b19e2ca77ee4becadc85341bb0c1cee454dd4fd5Jiri Slaby tty_port_link_device(&state->port, hp_simserial_driver, 0); 530fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby retval = tty_register_driver(hp_simserial_driver); 531fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby if (retval) { 532fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby printk(KERN_ERR "Couldn't register simserial driver\n"); 533fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby goto err_free_tty; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 537fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabyerr_free_tty: 538fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby put_tty_driver(hp_simserial_driver); 539191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby tty_port_destroy(&state->port); 540fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby return retval; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__initcall(simrs_init); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 546