1/* 2 * Simulated Serial Driver (fake serial) 3 * 4 * This driver is mostly used for bringup purposes and will go away. 5 * It has a strong dependency on the system console. All outputs 6 * are rerouted to the same facility as the one used by printk which, in our 7 * case means sys_sim.c console (goes via the simulator). 8 * 9 * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co 10 * Stephane Eranian <eranian@hpl.hp.com> 11 * David Mosberger-Tang <davidm@hpl.hp.com> 12 */ 13 14#include <linux/init.h> 15#include <linux/errno.h> 16#include <linux/sched.h> 17#include <linux/tty.h> 18#include <linux/tty_flip.h> 19#include <linux/major.h> 20#include <linux/fcntl.h> 21#include <linux/mm.h> 22#include <linux/seq_file.h> 23#include <linux/slab.h> 24#include <linux/capability.h> 25#include <linux/circ_buf.h> 26#include <linux/console.h> 27#include <linux/irq.h> 28#include <linux/module.h> 29#include <linux/serial.h> 30#include <linux/sysrq.h> 31#include <linux/uaccess.h> 32 33#include <asm/hpsim.h> 34 35#include "hpsim_ssc.h" 36 37#undef SIMSERIAL_DEBUG /* define this to get some debug information */ 38 39#define KEYBOARD_INTR 3 /* must match with simulator! */ 40 41#define NR_PORTS 1 /* only one port for now */ 42 43struct serial_state { 44 struct tty_port port; 45 struct circ_buf xmit; 46 int irq; 47 int x_char; 48}; 49 50static struct serial_state rs_table[NR_PORTS]; 51 52struct tty_driver *hp_simserial_driver; 53 54static struct console *console; 55 56static void receive_chars(struct tty_port *port) 57{ 58 unsigned char ch; 59 static unsigned char seen_esc = 0; 60 61 while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { 62 if (ch == 27 && seen_esc == 0) { 63 seen_esc = 1; 64 continue; 65 } else if (seen_esc == 1 && ch == 'O') { 66 seen_esc = 2; 67 continue; 68 } else if (seen_esc == 2) { 69 if (ch == 'P') /* F1 */ 70 show_state(); 71#ifdef CONFIG_MAGIC_SYSRQ 72 if (ch == 'S') { /* F4 */ 73 do { 74 ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); 75 } while (!ch); 76 handle_sysrq(ch); 77 } 78#endif 79 seen_esc = 0; 80 continue; 81 } 82 seen_esc = 0; 83 84 if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0) 85 break; 86 } 87 tty_flip_buffer_push(port); 88} 89 90/* 91 * This is the serial driver's interrupt routine for a single port 92 */ 93static irqreturn_t rs_interrupt_single(int irq, void *dev_id) 94{ 95 struct serial_state *info = dev_id; 96 97 receive_chars(&info->port); 98 99 return IRQ_HANDLED; 100} 101 102/* 103 * ------------------------------------------------------------------- 104 * Here ends the serial interrupt routines. 105 * ------------------------------------------------------------------- 106 */ 107 108static int rs_put_char(struct tty_struct *tty, unsigned char ch) 109{ 110 struct serial_state *info = tty->driver_data; 111 unsigned long flags; 112 113 if (!info->xmit.buf) 114 return 0; 115 116 local_irq_save(flags); 117 if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { 118 local_irq_restore(flags); 119 return 0; 120 } 121 info->xmit.buf[info->xmit.head] = ch; 122 info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); 123 local_irq_restore(flags); 124 return 1; 125} 126 127static void transmit_chars(struct tty_struct *tty, struct serial_state *info, 128 int *intr_done) 129{ 130 int count; 131 unsigned long flags; 132 133 local_irq_save(flags); 134 135 if (info->x_char) { 136 char c = info->x_char; 137 138 console->write(console, &c, 1); 139 140 info->x_char = 0; 141 142 goto out; 143 } 144 145 if (info->xmit.head == info->xmit.tail || tty->stopped) { 146#ifdef SIMSERIAL_DEBUG 147 printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", 148 info->xmit.head, info->xmit.tail, tty->stopped); 149#endif 150 goto out; 151 } 152 /* 153 * We removed the loop and try to do it in to chunks. We need 154 * 2 operations maximum because it's a ring buffer. 155 * 156 * First from current to tail if possible. 157 * Then from the beginning of the buffer until necessary 158 */ 159 160 count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), 161 SERIAL_XMIT_SIZE - info->xmit.tail); 162 console->write(console, info->xmit.buf+info->xmit.tail, count); 163 164 info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1); 165 166 /* 167 * We have more at the beginning of the buffer 168 */ 169 count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 170 if (count) { 171 console->write(console, info->xmit.buf, count); 172 info->xmit.tail += count; 173 } 174out: 175 local_irq_restore(flags); 176} 177 178static void rs_flush_chars(struct tty_struct *tty) 179{ 180 struct serial_state *info = tty->driver_data; 181 182 if (info->xmit.head == info->xmit.tail || tty->stopped || 183 !info->xmit.buf) 184 return; 185 186 transmit_chars(tty, info, NULL); 187} 188 189static int rs_write(struct tty_struct * tty, 190 const unsigned char *buf, int count) 191{ 192 struct serial_state *info = tty->driver_data; 193 int c, ret = 0; 194 unsigned long flags; 195 196 if (!info->xmit.buf) 197 return 0; 198 199 local_irq_save(flags); 200 while (1) { 201 c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 202 if (count < c) 203 c = count; 204 if (c <= 0) { 205 break; 206 } 207 memcpy(info->xmit.buf + info->xmit.head, buf, c); 208 info->xmit.head = ((info->xmit.head + c) & 209 (SERIAL_XMIT_SIZE-1)); 210 buf += c; 211 count -= c; 212 ret += c; 213 } 214 local_irq_restore(flags); 215 /* 216 * Hey, we transmit directly from here in our case 217 */ 218 if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && 219 !tty->stopped) 220 transmit_chars(tty, info, NULL); 221 222 return ret; 223} 224 225static int rs_write_room(struct tty_struct *tty) 226{ 227 struct serial_state *info = tty->driver_data; 228 229 return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 230} 231 232static int rs_chars_in_buffer(struct tty_struct *tty) 233{ 234 struct serial_state *info = tty->driver_data; 235 236 return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 237} 238 239static void rs_flush_buffer(struct tty_struct *tty) 240{ 241 struct serial_state *info = tty->driver_data; 242 unsigned long flags; 243 244 local_irq_save(flags); 245 info->xmit.head = info->xmit.tail = 0; 246 local_irq_restore(flags); 247 248 tty_wakeup(tty); 249} 250 251/* 252 * This function is used to send a high-priority XON/XOFF character to 253 * the device 254 */ 255static void rs_send_xchar(struct tty_struct *tty, char ch) 256{ 257 struct serial_state *info = tty->driver_data; 258 259 info->x_char = ch; 260 if (ch) { 261 /* 262 * I guess we could call console->write() directly but 263 * let's do that for now. 264 */ 265 transmit_chars(tty, info, NULL); 266 } 267} 268 269/* 270 * ------------------------------------------------------------ 271 * rs_throttle() 272 * 273 * This routine is called by the upper-layer tty layer to signal that 274 * incoming characters should be throttled. 275 * ------------------------------------------------------------ 276 */ 277static void rs_throttle(struct tty_struct * tty) 278{ 279 if (I_IXOFF(tty)) 280 rs_send_xchar(tty, STOP_CHAR(tty)); 281 282 printk(KERN_INFO "simrs_throttle called\n"); 283} 284 285static void rs_unthrottle(struct tty_struct * tty) 286{ 287 struct serial_state *info = tty->driver_data; 288 289 if (I_IXOFF(tty)) { 290 if (info->x_char) 291 info->x_char = 0; 292 else 293 rs_send_xchar(tty, START_CHAR(tty)); 294 } 295 printk(KERN_INFO "simrs_unthrottle called\n"); 296} 297 298static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) 299{ 300 if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 301 (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && 302 (cmd != TIOCMIWAIT)) { 303 if (tty->flags & (1 << TTY_IO_ERROR)) 304 return -EIO; 305 } 306 307 switch (cmd) { 308 case TIOCGSERIAL: 309 case TIOCSSERIAL: 310 case TIOCSERGSTRUCT: 311 case TIOCMIWAIT: 312 return 0; 313 case TIOCSERCONFIG: 314 case TIOCSERGETLSR: /* Get line status register */ 315 return -EINVAL; 316 case TIOCSERGWILD: 317 case TIOCSERSWILD: 318 /* "setserial -W" is called in Debian boot */ 319 printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); 320 return 0; 321 } 322 return -ENOIOCTLCMD; 323} 324 325#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) 326 327/* 328 * This routine will shutdown a serial port; interrupts are disabled, and 329 * DTR is dropped if the hangup on close termio flag is on. 330 */ 331static void shutdown(struct tty_port *port) 332{ 333 struct serial_state *info = container_of(port, struct serial_state, 334 port); 335 unsigned long flags; 336 337 local_irq_save(flags); 338 if (info->irq) 339 free_irq(info->irq, info); 340 341 if (info->xmit.buf) { 342 free_page((unsigned long) info->xmit.buf); 343 info->xmit.buf = NULL; 344 } 345 local_irq_restore(flags); 346} 347 348static void rs_close(struct tty_struct *tty, struct file * filp) 349{ 350 struct serial_state *info = tty->driver_data; 351 352 tty_port_close(&info->port, tty, filp); 353} 354 355static void rs_hangup(struct tty_struct *tty) 356{ 357 struct serial_state *info = tty->driver_data; 358 359 rs_flush_buffer(tty); 360 tty_port_hangup(&info->port); 361} 362 363static int activate(struct tty_port *port, struct tty_struct *tty) 364{ 365 struct serial_state *state = container_of(port, struct serial_state, 366 port); 367 unsigned long flags, page; 368 int retval = 0; 369 370 page = get_zeroed_page(GFP_KERNEL); 371 if (!page) 372 return -ENOMEM; 373 374 local_irq_save(flags); 375 376 if (state->xmit.buf) 377 free_page(page); 378 else 379 state->xmit.buf = (unsigned char *) page; 380 381 if (state->irq) { 382 retval = request_irq(state->irq, rs_interrupt_single, 0, 383 "simserial", state); 384 if (retval) 385 goto errout; 386 } 387 388 state->xmit.head = state->xmit.tail = 0; 389 390 /* 391 * Set up the tty->alt_speed kludge 392 */ 393 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) 394 tty->alt_speed = 57600; 395 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) 396 tty->alt_speed = 115200; 397 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) 398 tty->alt_speed = 230400; 399 if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) 400 tty->alt_speed = 460800; 401 402errout: 403 local_irq_restore(flags); 404 return retval; 405} 406 407 408/* 409 * This routine is called whenever a serial port is opened. It 410 * enables interrupts for a serial port, linking in its async structure into 411 * the IRQ chain. It also performs the serial-specific 412 * initialization for the tty structure. 413 */ 414static int rs_open(struct tty_struct *tty, struct file * filp) 415{ 416 struct serial_state *info = rs_table + tty->index; 417 struct tty_port *port = &info->port; 418 419 tty->driver_data = info; 420 port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 421 422 /* 423 * figure out which console to use (should be one already) 424 */ 425 console = console_drivers; 426 while (console) { 427 if ((console->flags & CON_ENABLED) && console->write) break; 428 console = console->next; 429 } 430 431 return tty_port_open(port, tty, filp); 432} 433 434/* 435 * /proc fs routines.... 436 */ 437 438static int rs_proc_show(struct seq_file *m, void *v) 439{ 440 int i; 441 442 seq_printf(m, "simserinfo:1.0\n"); 443 for (i = 0; i < NR_PORTS; i++) 444 seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", 445 i, rs_table[i].irq); 446 return 0; 447} 448 449static int rs_proc_open(struct inode *inode, struct file *file) 450{ 451 return single_open(file, rs_proc_show, NULL); 452} 453 454static const struct file_operations rs_proc_fops = { 455 .owner = THIS_MODULE, 456 .open = rs_proc_open, 457 .read = seq_read, 458 .llseek = seq_lseek, 459 .release = single_release, 460}; 461 462static const struct tty_operations hp_ops = { 463 .open = rs_open, 464 .close = rs_close, 465 .write = rs_write, 466 .put_char = rs_put_char, 467 .flush_chars = rs_flush_chars, 468 .write_room = rs_write_room, 469 .chars_in_buffer = rs_chars_in_buffer, 470 .flush_buffer = rs_flush_buffer, 471 .ioctl = rs_ioctl, 472 .throttle = rs_throttle, 473 .unthrottle = rs_unthrottle, 474 .send_xchar = rs_send_xchar, 475 .hangup = rs_hangup, 476 .proc_fops = &rs_proc_fops, 477}; 478 479static const struct tty_port_operations hp_port_ops = { 480 .activate = activate, 481 .shutdown = shutdown, 482}; 483 484static int __init simrs_init(void) 485{ 486 struct serial_state *state; 487 int retval; 488 489 if (!ia64_platform_is("hpsim")) 490 return -ENODEV; 491 492 hp_simserial_driver = alloc_tty_driver(NR_PORTS); 493 if (!hp_simserial_driver) 494 return -ENOMEM; 495 496 printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); 497 498 /* Initialize the tty_driver structure */ 499 500 hp_simserial_driver->driver_name = "simserial"; 501 hp_simserial_driver->name = "ttyS"; 502 hp_simserial_driver->major = TTY_MAJOR; 503 hp_simserial_driver->minor_start = 64; 504 hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL; 505 hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL; 506 hp_simserial_driver->init_termios = tty_std_termios; 507 hp_simserial_driver->init_termios.c_cflag = 508 B9600 | CS8 | CREAD | HUPCL | CLOCAL; 509 hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; 510 tty_set_operations(hp_simserial_driver, &hp_ops); 511 512 state = rs_table; 513 tty_port_init(&state->port); 514 state->port.ops = &hp_port_ops; 515 state->port.close_delay = 0; /* XXX really 0? */ 516 517 retval = hpsim_get_irq(KEYBOARD_INTR); 518 if (retval < 0) { 519 printk(KERN_ERR "%s: out of interrupt vectors!\n", 520 __func__); 521 goto err_free_tty; 522 } 523 524 state->irq = retval; 525 526 /* the port is imaginary */ 527 printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); 528 529 tty_port_link_device(&state->port, hp_simserial_driver, 0); 530 retval = tty_register_driver(hp_simserial_driver); 531 if (retval) { 532 printk(KERN_ERR "Couldn't register simserial driver\n"); 533 goto err_free_tty; 534 } 535 536 return 0; 537err_free_tty: 538 put_tty_driver(hp_simserial_driver); 539 tty_port_destroy(&state->port); 540 return retval; 541} 542 543#ifndef MODULE 544__initcall(simrs_init); 545#endif 546