simserial.c revision d6c53c0e9bd0a83f9f9ddbc9fd80141a54d83896
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 562fcd5caf6d9dbf274ac7ef277f1cc541f1be9784Jiri Slabystatic void receive_chars(struct tty_struct *tty) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5892a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby struct tty_port *port = tty->port; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ch; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned char seen_esc = 0; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { 63f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (ch == 27 && seen_esc == 0) { 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seen_esc = 1; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 66f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } else if (seen_esc == 1 && ch == 'O') { 67f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby seen_esc = 2; 68f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby continue; 69f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } else if (seen_esc == 2) { 70f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (ch == 'P') /* F1 */ 71f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby show_state(); 72819c67e69c4e0062787e27dd989f5f9d00d4834eDavid Mosberger-Tang#ifdef CONFIG_MAGIC_SYSRQ 73f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (ch == 'S') { /* F4 */ 74f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby do { 75f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); 76f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } while (!ch); 77f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby handle_sysrq(ch); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 79f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby#endif 80f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby seen_esc = 0; 81f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby continue; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seen_esc = 0; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8592a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0) 86d50f5c5ca0c3426669fbe11ad4d5708d333eb9fbAndreas Schwab break; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push(tty); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the serial driver's interrupt routine for a single port 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 945dcded1b0b4f1537bb6dff453fb805517756c94bAl Virostatic irqreturn_t rs_interrupt_single(int irq, void *dev_id) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 96916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = dev_id; 973a5c24232463b4978acf8d8668becbf515d30a36Jiri Slaby struct tty_struct *tty = tty_port_tty_get(&info->port); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 997f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby if (!tty) { 1006e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby printk(KERN_INFO "%s: tty=0 problem\n", __func__); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pretty simple in our case, because we only get interrupts 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on inbound traffic 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1077f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby receive_chars(tty); 1083a5c24232463b4978acf8d8668becbf515d30a36Jiri Slaby tty_kref_put(tty); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------- 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Here ends the serial interrupt routines. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------- 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118f34d7a5b7010b82fe97da95496b9971435530062Alan Coxstatic int rs_put_char(struct tty_struct *tty, unsigned char ch) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 120916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1236e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby if (!info->xmit.buf) 124f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 0; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 129f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 0; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.buf[info->xmit.head] = ch; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 134f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 1; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1375e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slabystatic void transmit_chars(struct tty_struct *tty, struct serial_state *info, 1385e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby int *intr_done) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) { 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c = info->x_char; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, &c, 1); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1555e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby if (info->xmit.head == info->xmit.tail || tty->stopped || 1565e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->hw_stopped) { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SIMSERIAL_DEBUG 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", 1595e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby info->xmit.head, info->xmit.tail, tty->stopped); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We removed the loop and try to do it in to chunks. We need 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 operations maximum because it's a ring buffer. 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First from current to tail if possible. 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Then from the beginning of the buffer until necessary 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SERIAL_XMIT_SIZE - info->xmit.tail); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, info->xmit.buf+info->xmit.tail, count); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have more at the beginning of the buffer 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count) { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, info->xmit.buf, count); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.tail += count; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_flush_chars(struct tty_struct *tty) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 191916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 193f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->xmit.head == info->xmit.tail || tty->stopped || 194f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby tty->hw_stopped || !info->xmit.buf) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1975e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_write(struct tty_struct * tty, 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, int count) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 203916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2076e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby if (!info->xmit.buf) 208d88405d44fd30fcbe77a9db540afd8823b30afdcJiri Slaby return 0; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < c) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = count; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(info->xmit.buf + info->xmit.head, buf, c); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = ((info->xmit.head + c) & 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (SERIAL_XMIT_SIZE-1)); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hey, we transmit directly from here in our case 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 229f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && 230f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby !tty->stopped && !tty->hw_stopped) 2315e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 232f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_write_room(struct tty_struct *tty) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 238916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_chars_in_buffer(struct tty_struct *tty) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 245916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_flush_buffer(struct tty_struct *tty) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 252916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = info->xmit.tail = 0; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25915648f154a8faea97cbe931e189cf0a57fd066f4Alan Cox tty_wakeup(tty); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used to send a high-priority XON/XOFF character to 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_send_xchar(struct tty_struct *tty, char ch) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 268916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = ch; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I guess we could call console->write() directly but 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * let's do that for now. 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2765e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rs_throttle() 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the upper-layer tty layer to signal that 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * incoming characters should be throttled. 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_throttle(struct tty_struct * tty) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 290f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (I_IXOFF(tty)) 291f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby rs_send_xchar(tty, STOP_CHAR(tty)); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simrs_throttle called\n"); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_unthrottle(struct tty_struct * tty) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 298916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rs_send_xchar(tty, START_CHAR(tty)); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simrs_unthrottle called\n"); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30910e82f6ce76351425644bccc56f8e2c2ad596ce6Tony Luckstatic int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && 3130587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox (cmd != TIOCMIWAIT)) { 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 319f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCGSERIAL: 320f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSSERIAL: 321f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGSTRUCT: 322f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCMIWAIT: 323f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return 0; 324f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERCONFIG: 325f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGETLSR: /* Get line status register */ 326f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return -EINVAL; 327f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGWILD: 328f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERSWILD: 329f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby /* "setserial -W" is called in Debian boot */ 330f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); 331f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return 0; 332f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } 333f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return -ENOIOCTLCMD; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 338f889a26a703b03c774849685583cec7746738f3cTony Luckstatic void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle turning off CRTSCTS */ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_termios->c_cflag & CRTSCTS) && 342adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox !(tty->termios.c_cflag & CRTSCTS)) { 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped = 0; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will shutdown a serial port; interrupts are disabled, and 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DTR is dropped if the hangup on close termio flag is on. 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 350458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slabystatic void shutdown(struct tty_port *port) 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 352458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby struct serial_state *info = container_of(port, struct serial_state, 353458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby port); 354458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby unsigned long flags; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 357f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->irq) 358f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby free_irq(info->irq, info); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 360f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->xmit.buf) { 361f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby free_page((unsigned long) info->xmit.buf); 362f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby info->xmit.buf = NULL; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_close(struct tty_struct *tty, struct file * filp) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 369916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 37037343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby 371458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby tty_port_close(&info->port, tty, filp); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_hangup(struct tty_struct *tty) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 376916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rs_flush_buffer(tty); 379458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby tty_port_hangup(&info->port); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3829aead90a7f5772fc74f733242d953688748b0ce4Jiri Slabystatic int activate(struct tty_port *port, struct tty_struct *tty) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3849aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby struct serial_state *state = container_of(port, struct serial_state, 3859aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby port); 386f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby unsigned long flags, page; 387f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby int retval = 0; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = get_zeroed_page(GFP_KERNEL); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 395916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby if (state->xmit.buf) 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page(page); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 398916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby state->xmit.buf = (unsigned char *) page; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 400964105b501071e8a0e9feb1d0e4b3e46508bc38eJiri Slaby if (state->irq) { 4012f8c521a1d41faf96f729c76991eb4ad70294513Jiri Slaby retval = request_irq(state->irq, rs_interrupt_single, 0, 402916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby "simserial", state); 4039e12dd5fce1c676e709625bd2f55dc83664c3c93Jiri Slaby if (retval) 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto errout; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 407916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby state->xmit.head = state->xmit.tail = 0; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the tty->alt_speed kludge 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41201bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) 4135e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 57600; 41401bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) 4155e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 115200; 41601bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) 4175e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 230400; 41801bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) 4195e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 460800; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserrout: 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called whenever a serial port is opened. It 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enables interrupts for a serial port, linking in its async structure into 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IRQ chain. It also performs the serial-specific 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialization for the tty structure. 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_open(struct tty_struct *tty, struct file * filp) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 435916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = rs_table + tty->index; 4367f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby struct tty_port *port = &info->port; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 438916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby tty->driver_data = info; 439d6c53c0e9bd0a83f9f9ddbc9fd80141a54d83896Jiri Slaby port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out which console to use (should be one already) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = console_drivers; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (console) { 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((console->flags & CON_ENABLED) && console->write) break; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = console->next; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4509aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby return tty_port_open(port, tty, filp); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /proc fs routines.... 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 457bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic int rs_proc_show(struct seq_file *m, void *v) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 459bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan int i; 460bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 4616e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby seq_printf(m, "simserinfo:1.0\n"); 462bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan for (i = 0; i < NR_PORTS; i++) 46398e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", 46498e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby i, rs_table[i].irq); 465bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan return 0; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 468bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic int rs_proc_open(struct inode *inode, struct file *file) 469bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan{ 470bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan return single_open(file, rs_proc_show, NULL); 471bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan} 472bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 473bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic const struct file_operations rs_proc_fops = { 474bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .owner = THIS_MODULE, 475bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .open = rs_proc_open, 476bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .read = seq_read, 477bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .llseek = seq_lseek, 478bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .release = single_release, 479bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan}; 480bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 481b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations hp_ops = { 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = rs_open, 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = rs_close, 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = rs_write, 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = rs_put_char, 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = rs_flush_chars, 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = rs_write_room, 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = rs_chars_in_buffer, 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = rs_flush_buffer, 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = rs_ioctl, 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = rs_throttle, 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = rs_unthrottle, 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = rs_send_xchar, 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = rs_set_termios, 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = rs_hangup, 496bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .proc_fops = &rs_proc_fops, 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49937343030458c0eea3f1093b09fc604d4f300eac7Jiri Slabystatic const struct tty_port_operations hp_port_ops = { 5009aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby .activate = activate, 501458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby .shutdown = shutdown, 50237343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby}; 50337343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby 504fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabystatic int __init simrs_init(void) 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 506fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby struct serial_state *state; 507fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby int retval; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ia64_platform_is("hpsim")) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 512410235fd4d20b8feaf8930a0575d23acc088aa87Jiri Slaby hp_simserial_driver = alloc_tty_driver(NR_PORTS); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!hp_simserial_driver) 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5166e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the tty_driver structure */ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->driver_name = "simserial"; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->name = "ttyS"; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->major = TTY_MAJOR; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->minor_start = 64; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->init_termios = tty_std_termios; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->init_termios.c_cflag = 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B9600 | CS8 | CREAD | HUPCL | CLOCAL; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(hp_simserial_driver, &hp_ops); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 532fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby state = rs_table; 5337f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby tty_port_init(&state->port); 53437343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby state->port.ops = &hp_port_ops; 5357f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby state->port.close_delay = 0; /* XXX really 0? */ 536fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby 537fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby retval = hpsim_get_irq(KEYBOARD_INTR); 538fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby if (retval < 0) { 539fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby printk(KERN_ERR "%s: out of interrupt vectors!\n", 540fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby __func__); 541fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby goto err_free_tty; 542fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby } 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 544fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby state->irq = retval; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 546fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby /* the port is imaginary */ 54798e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 549b19e2ca77ee4becadc85341bb0c1cee454dd4fd5Jiri Slaby tty_port_link_device(&state->port, hp_simserial_driver, 0); 550fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby retval = tty_register_driver(hp_simserial_driver); 551fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby if (retval) { 552fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby printk(KERN_ERR "Couldn't register simserial driver\n"); 553fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby goto err_free_tty; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 557fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabyerr_free_tty: 558fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby put_tty_driver(hp_simserial_driver); 559191c5f10275cfbb36802edadbdb10c73537327b4Jiri Slaby tty_port_destroy(&state->port); 560fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby return retval; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__initcall(simrs_init); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 566