simserial.c revision 6e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57
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{ 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 84d50f5c5ca0c3426669fbe11ad4d5708d333eb9fbAndreas Schwab if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0) 85d50f5c5ca0c3426669fbe11ad4d5708d333eb9fbAndreas Schwab break; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push(tty); 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; 963a5c24232463b4978acf8d8668becbf515d30a36Jiri Slaby struct tty_struct *tty = tty_port_tty_get(&info->port); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 987f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby if (!tty) { 996e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby printk(KERN_INFO "%s: tty=0 problem\n", __func__); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pretty simple in our case, because we only get interrupts 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on inbound traffic 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1067f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby receive_chars(tty); 1073a5c24232463b4978acf8d8668becbf515d30a36Jiri Slaby tty_kref_put(tty); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------- 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Here ends the serial interrupt routines. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------- 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 117f34d7a5b7010b82fe97da95496b9971435530062Alan Coxstatic int rs_put_char(struct tty_struct *tty, unsigned char ch) 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 119916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1226e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby if (!info->xmit.buf) 123f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 0; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 128f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 0; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.buf[info->xmit.head] = ch; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 133f34d7a5b7010b82fe97da95496b9971435530062Alan Cox return 1; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1365e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slabystatic void transmit_chars(struct tty_struct *tty, struct serial_state *info, 1375e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby int *intr_done) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c = info->x_char; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, &c, 1); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1545e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby if (info->xmit.head == info->xmit.tail || tty->stopped || 1555e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->hw_stopped) { 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SIMSERIAL_DEBUG 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", 1585e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby info->xmit.head, info->xmit.tail, tty->stopped); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We removed the loop and try to do it in to chunks. We need 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 operations maximum because it's a ring buffer. 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First from current to tail if possible. 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Then from the beginning of the buffer until necessary 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SERIAL_XMIT_SIZE - info->xmit.tail); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, info->xmit.buf+info->xmit.tail, count); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have more at the beginning of the buffer 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count) { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console->write(console, info->xmit.buf, count); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.tail += count; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_flush_chars(struct tty_struct *tty) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 190916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 192f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->xmit.head == info->xmit.tail || tty->stopped || 193f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby tty->hw_stopped || !info->xmit.buf) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1965e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_write(struct tty_struct * tty, 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, int count) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 202916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int c, ret = 0; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2066e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby if (!info->xmit.buf) 207d88405d44fd30fcbe77a9db540afd8823b30afdcJiri Slaby return 0; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < c) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = count; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c <= 0) { 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(info->xmit.buf + info->xmit.head, buf, c); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = ((info->xmit.head + c) & 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (SERIAL_XMIT_SIZE-1)); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += c; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= c; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret += c; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hey, we transmit directly from here in our case 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 228f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && 229f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby !tty->stopped && !tty->hw_stopped) 2305e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 231f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_write_room(struct tty_struct *tty) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 237916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_chars_in_buffer(struct tty_struct *tty) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 244916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_flush_buffer(struct tty_struct *tty) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 251916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->xmit.head = info->xmit.tail = 0; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25815648f154a8faea97cbe931e189cf0a57fd066f4Alan Cox tty_wakeup(tty); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used to send a high-priority XON/XOFF character to 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_send_xchar(struct tty_struct *tty, char ch) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 267916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = ch; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch) { 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I guess we could call console->write() directly but 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * let's do that for now. 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2755e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby transmit_chars(tty, info, NULL); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rs_throttle() 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called by the upper-layer tty layer to signal that 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * incoming characters should be throttled. 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_throttle(struct tty_struct * tty) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 289f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (I_IXOFF(tty)) 290f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby rs_send_xchar(tty, STOP_CHAR(tty)); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simrs_throttle called\n"); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_unthrottle(struct tty_struct * tty) 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 297916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (I_IXOFF(tty)) { 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (info->x_char) 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->x_char = 0; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rs_send_xchar(tty, START_CHAR(tty)); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simrs_unthrottle called\n"); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30810e82f6ce76351425644bccc56f8e2c2ad596ce6Tony Luckstatic int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && 3120587102cf9f427c185bfdeb2cef41e13ee0264b1Alan Cox (cmd != TIOCMIWAIT)) { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty->flags & (1 << TTY_IO_ERROR)) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 318f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCGSERIAL: 319f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSSERIAL: 320f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGSTRUCT: 321f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCMIWAIT: 322f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return 0; 323f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERCONFIG: 324f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGETLSR: /* Get line status register */ 325f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return -EINVAL; 326f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERGWILD: 327f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby case TIOCSERSWILD: 328f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby /* "setserial -W" is called in Debian boot */ 329f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); 330f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return 0; 331f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby } 332f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby return -ENOIOCTLCMD; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 337f889a26a703b03c774849685583cec7746738f3cTony Luckstatic void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle turning off CRTSCTS */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((old_termios->c_cflag & CRTSCTS) && 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(tty->termios->c_cflag & CRTSCTS)) { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->hw_stopped = 0; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine will shutdown a serial port; interrupts are disabled, and 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DTR is dropped if the hangup on close termio flag is on. 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 349458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slabystatic void shutdown(struct tty_port *port) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 351458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby struct serial_state *info = container_of(port, struct serial_state, 352458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby port); 353458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby unsigned long flags; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 356f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->irq) 357f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby free_irq(info->irq, info); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 359f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby if (info->xmit.buf) { 360f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby free_page((unsigned long) info->xmit.buf); 361f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby info->xmit.buf = NULL; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_close(struct tty_struct *tty, struct file * filp) 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 368916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 36937343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby 370458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby tty_port_close(&info->port, tty, filp); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rs_hangup(struct tty_struct *tty) 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 375916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = tty->driver_data; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rs_flush_buffer(tty); 378458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby tty_port_hangup(&info->port); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3819aead90a7f5772fc74f733242d953688748b0ce4Jiri Slabystatic int activate(struct tty_port *port, struct tty_struct *tty) 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3839aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby struct serial_state *state = container_of(port, struct serial_state, 3849aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby port); 385f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby unsigned long flags, page; 386f66279cd7d5cdf43686da0d9ed20378581b88d0fJiri Slaby int retval = 0; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = get_zeroed_page(GFP_KERNEL); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!page) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 394916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby if (state->xmit.buf) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page(page); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 397916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby state->xmit.buf = (unsigned char *) page; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 399964105b501071e8a0e9feb1d0e4b3e46508bc38eJiri Slaby if (state->irq) { 4002f8c521a1d41faf96f729c76991eb4ad70294513Jiri Slaby retval = request_irq(state->irq, rs_interrupt_single, 0, 401916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby "simserial", state); 4029e12dd5fce1c676e709625bd2f55dc83664c3c93Jiri Slaby if (retval) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto errout; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 406916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby state->xmit.head = state->xmit.tail = 0; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the tty->alt_speed kludge 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41101bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) 4125e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 57600; 41301bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) 4145e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 115200; 41501bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) 4165e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 230400; 41701bd730d92bd002adc3f3317d8e3328c629b436cJiri Slaby if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) 4185e99d5458729b0eb763ca83a2fbb95f6276c4243Jiri Slaby tty->alt_speed = 460800; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserrout: 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine is called whenever a serial port is opened. It 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enables interrupts for a serial port, linking in its async structure into 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IRQ chain. It also performs the serial-specific 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialization for the tty structure. 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rs_open(struct tty_struct *tty, struct file * filp) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 434916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby struct serial_state *info = rs_table + tty->index; 4357f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby struct tty_port *port = &info->port; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 437916b765675b7044bd5895b7430a2aa2c63ea4545Jiri Slaby tty->driver_data = info; 4387f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out which console to use (should be one already) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = console_drivers; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (console) { 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((console->flags & CON_ENABLED) && console->write) break; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = console->next; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4499aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby return tty_port_open(port, tty, filp); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /proc fs routines.... 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 456bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic int rs_proc_show(struct seq_file *m, void *v) 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 458bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan int i; 459bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 4606e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby seq_printf(m, "simserinfo:1.0\n"); 461bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan for (i = 0; i < NR_PORTS; i++) 46298e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", 46398e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby i, rs_table[i].irq); 464bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan return 0; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 467bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic int rs_proc_open(struct inode *inode, struct file *file) 468bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan{ 469bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan return single_open(file, rs_proc_show, NULL); 470bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan} 471bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 472bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyanstatic const struct file_operations rs_proc_fops = { 473bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .owner = THIS_MODULE, 474bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .open = rs_proc_open, 475bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .read = seq_read, 476bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .llseek = seq_lseek, 477bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .release = single_release, 478bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan}; 479bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan 480b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations hp_ops = { 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = rs_open, 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = rs_close, 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = rs_write, 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .put_char = rs_put_char, 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_chars = rs_flush_chars, 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = rs_write_room, 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = rs_chars_in_buffer, 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flush_buffer = rs_flush_buffer, 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = rs_ioctl, 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = rs_throttle, 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = rs_unthrottle, 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send_xchar = rs_send_xchar, 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = rs_set_termios, 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hangup = rs_hangup, 495bf54215ef86a1bd83affd8ecdf833c053aefb49dAlexey Dobriyan .proc_fops = &rs_proc_fops, 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49837343030458c0eea3f1093b09fc604d4f300eac7Jiri Slabystatic const struct tty_port_operations hp_port_ops = { 4999aead90a7f5772fc74f733242d953688748b0ce4Jiri Slaby .activate = activate, 500458cd31a4c33ce489eb538193f801ac73ff4010bJiri Slaby .shutdown = shutdown, 50137343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby}; 50237343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby 503fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabystatic int __init simrs_init(void) 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 505fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby struct serial_state *state; 506fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby int retval; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ia64_platform_is("hpsim")) 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511410235fd4d20b8feaf8930a0575d23acc088aa87Jiri Slaby hp_simserial_driver = alloc_tty_driver(NR_PORTS); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!hp_simserial_driver) 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5156e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57Jiri Slaby printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the tty_driver structure */ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->driver_name = "simserial"; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->name = "ttyS"; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->major = TTY_MAJOR; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->minor_start = 64; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->init_termios = tty_std_termios; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->init_termios.c_cflag = 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds B9600 | CS8 | CREAD | HUPCL | CLOCAL; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(hp_simserial_driver, &hp_ops); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby state = rs_table; 5327f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby tty_port_init(&state->port); 53337343030458c0eea3f1093b09fc604d4f300eac7Jiri Slaby state->port.ops = &hp_port_ops; 5347f32f8dd349bae106eccb0b9759c932875d6622eJiri Slaby state->port.close_delay = 0; /* XXX really 0? */ 535fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby 536fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby retval = hpsim_get_irq(KEYBOARD_INTR); 537fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby if (retval < 0) { 538fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby printk(KERN_ERR "%s: out of interrupt vectors!\n", 539fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby __func__); 540fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby goto err_free_tty; 541fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby } 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 543fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby state->irq = retval; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 545fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby /* the port is imaginary */ 54698e3a9e6dd99f1b8ac2a03b8b4942eec16ef911bJiri Slaby printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 548fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby retval = tty_register_driver(hp_simserial_driver); 549fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby if (retval) { 550fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby printk(KERN_ERR "Couldn't register simserial driver\n"); 551fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby goto err_free_tty; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 555fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slabyerr_free_tty: 556fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby put_tty_driver(hp_simserial_driver); 557fd2d7a6e60068779bc72029f867b51d3dc2fe0ccJiri Slaby return retval; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__initcall(simrs_init); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 563