Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at b1404069f64457c94de241738fdca142c2e5698f 1035 lines 28 kB view raw
1/* 2 * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports 3 * implementation. 4 * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk> 5 * 6 * Based on atari_SCC.c which was 7 * Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> 8 * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file COPYING in the main directory of this archive 12 * for more details. 13 * 14 */ 15 16#include <linux/module.h> 17#include <linux/kdev_t.h> 18#include <asm/io.h> 19#include <linux/kernel.h> 20#include <linux/ioport.h> 21#include <linux/interrupt.h> 22#include <linux/errno.h> 23#include <linux/tty.h> 24#include <linux/tty_flip.h> 25#include <linux/mm.h> 26#include <linux/serial.h> 27#include <linux/fcntl.h> 28#include <linux/major.h> 29#include <linux/delay.h> 30#include <linux/slab.h> 31#include <linux/miscdevice.h> 32#include <linux/console.h> 33#include <linux/init.h> 34#include <asm/setup.h> 35#include <asm/bootinfo.h> 36 37#ifdef CONFIG_MVME147_SCC 38#include <asm/mvme147hw.h> 39#endif 40#ifdef CONFIG_MVME162_SCC 41#include <asm/mvme16xhw.h> 42#endif 43#ifdef CONFIG_BVME6000_SCC 44#include <asm/bvme6000hw.h> 45#endif 46 47#include <linux/generic_serial.h> 48#include "scc.h" 49 50 51#define CHANNEL_A 0 52#define CHANNEL_B 1 53 54#define SCC_MINOR_BASE 64 55 56/* Shadows for all SCC write registers */ 57static unsigned char scc_shadow[2][16]; 58 59/* Location to access for SCC register access delay */ 60static volatile unsigned char *scc_del = NULL; 61 62/* To keep track of STATUS_REG state for detection of Ext/Status int source */ 63static unsigned char scc_last_status_reg[2]; 64 65/***************************** Prototypes *****************************/ 66 67/* Function prototypes */ 68static void scc_disable_tx_interrupts(void * ptr); 69static void scc_enable_tx_interrupts(void * ptr); 70static void scc_disable_rx_interrupts(void * ptr); 71static void scc_enable_rx_interrupts(void * ptr); 72static int scc_get_CD(void * ptr); 73static void scc_shutdown_port(void * ptr); 74static int scc_set_real_termios(void *ptr); 75static void scc_hungup(void *ptr); 76static void scc_close(void *ptr); 77static int scc_chars_in_buffer(void * ptr); 78static int scc_open(struct tty_struct * tty, struct file * filp); 79static int scc_ioctl(struct tty_struct * tty, struct file * filp, 80 unsigned int cmd, unsigned long arg); 81static void scc_throttle(struct tty_struct *tty); 82static void scc_unthrottle(struct tty_struct *tty); 83static irqreturn_t scc_tx_int(int irq, void *data); 84static irqreturn_t scc_rx_int(int irq, void *data); 85static irqreturn_t scc_stat_int(int irq, void *data); 86static irqreturn_t scc_spcond_int(int irq, void *data); 87static void scc_setsignals(struct scc_port *port, int dtr, int rts); 88static int scc_break_ctl(struct tty_struct *tty, int break_state); 89 90static struct tty_driver *scc_driver; 91 92static struct scc_port scc_ports[2]; 93 94/*--------------------------------------------------------------------------- 95 * Interface from generic_serial.c back here 96 *--------------------------------------------------------------------------*/ 97 98static struct real_driver scc_real_driver = { 99 scc_disable_tx_interrupts, 100 scc_enable_tx_interrupts, 101 scc_disable_rx_interrupts, 102 scc_enable_rx_interrupts, 103 scc_get_CD, 104 scc_shutdown_port, 105 scc_set_real_termios, 106 scc_chars_in_buffer, 107 scc_close, 108 scc_hungup, 109 NULL 110}; 111 112 113static const struct tty_operations scc_ops = { 114 .open = scc_open, 115 .close = gs_close, 116 .write = gs_write, 117 .put_char = gs_put_char, 118 .flush_chars = gs_flush_chars, 119 .write_room = gs_write_room, 120 .chars_in_buffer = gs_chars_in_buffer, 121 .flush_buffer = gs_flush_buffer, 122 .ioctl = scc_ioctl, 123 .throttle = scc_throttle, 124 .unthrottle = scc_unthrottle, 125 .set_termios = gs_set_termios, 126 .stop = gs_stop, 127 .start = gs_start, 128 .hangup = gs_hangup, 129 .break_ctl = scc_break_ctl, 130}; 131 132/*---------------------------------------------------------------------------- 133 * vme_scc_init() and support functions 134 *---------------------------------------------------------------------------*/ 135 136static int scc_init_drivers(void) 137{ 138 int error; 139 140 scc_driver = alloc_tty_driver(2); 141 if (!scc_driver) 142 return -ENOMEM; 143 scc_driver->owner = THIS_MODULE; 144 scc_driver->driver_name = "scc"; 145 scc_driver->name = "ttyS"; 146 scc_driver->major = TTY_MAJOR; 147 scc_driver->minor_start = SCC_MINOR_BASE; 148 scc_driver->type = TTY_DRIVER_TYPE_SERIAL; 149 scc_driver->subtype = SERIAL_TYPE_NORMAL; 150 scc_driver->init_termios = tty_std_termios; 151 scc_driver->init_termios.c_cflag = 152 B9600 | CS8 | CREAD | HUPCL | CLOCAL; 153 scc_driver->init_termios.c_ispeed = 9600; 154 scc_driver->init_termios.c_ospeed = 9600; 155 scc_driver->flags = TTY_DRIVER_REAL_RAW; 156 tty_set_operations(scc_driver, &scc_ops); 157 158 if ((error = tty_register_driver(scc_driver))) { 159 printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n", 160 error); 161 put_tty_driver(scc_driver); 162 return 1; 163 } 164 165 return 0; 166} 167 168 169/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1). 170 */ 171 172static void scc_init_portstructs(void) 173{ 174 struct scc_port *port; 175 int i; 176 177 for (i = 0; i < 2; i++) { 178 port = scc_ports + i; 179 port->gs.magic = SCC_MAGIC; 180 port->gs.close_delay = HZ/2; 181 port->gs.closing_wait = 30 * HZ; 182 port->gs.rd = &scc_real_driver; 183#ifdef NEW_WRITE_LOCKING 184 port->gs.port_write_mutex = MUTEX; 185#endif 186 init_waitqueue_head(&port->gs.port.open_wait); 187 init_waitqueue_head(&port->gs.port.close_wait); 188 } 189} 190 191 192#ifdef CONFIG_MVME147_SCC 193static int mvme147_scc_init(void) 194{ 195 struct scc_port *port; 196 197 printk(KERN_INFO "SCC: MVME147 Serial Driver\n"); 198 /* Init channel A */ 199 port = &scc_ports[0]; 200 port->channel = CHANNEL_A; 201 port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR; 202 port->datap = port->ctrlp + 1; 203 port->port_a = &scc_ports[0]; 204 port->port_b = &scc_ports[1]; 205 request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, 206 "SCC-A TX", port); 207 request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, 208 "SCC-A status", port); 209 request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, 210 "SCC-A RX", port); 211 request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED, 212 "SCC-A special cond", port); 213 { 214 SCC_ACCESS_INIT(port); 215 216 /* disable interrupts for this channel */ 217 SCCwrite(INT_AND_DMA_REG, 0); 218 /* Set the interrupt vector */ 219 SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE); 220 /* Interrupt parameters: vector includes status, status low */ 221 SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); 222 SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); 223 } 224 225 /* Init channel B */ 226 port = &scc_ports[1]; 227 port->channel = CHANNEL_B; 228 port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR; 229 port->datap = port->ctrlp + 1; 230 port->port_a = &scc_ports[0]; 231 port->port_b = &scc_ports[1]; 232 request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, 233 "SCC-B TX", port); 234 request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, 235 "SCC-B status", port); 236 request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, 237 "SCC-B RX", port); 238 request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED, 239 "SCC-B special cond", port); 240 { 241 SCC_ACCESS_INIT(port); 242 243 /* disable interrupts for this channel */ 244 SCCwrite(INT_AND_DMA_REG, 0); 245 } 246 247 /* Ensure interrupts are enabled in the PCC chip */ 248 m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB; 249 250 /* Initialise the tty driver structures and register */ 251 scc_init_portstructs(); 252 scc_init_drivers(); 253 254 return 0; 255} 256#endif 257 258 259#ifdef CONFIG_MVME162_SCC 260static int mvme162_scc_init(void) 261{ 262 struct scc_port *port; 263 264 if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA)) 265 return (-ENODEV); 266 267 printk(KERN_INFO "SCC: MVME162 Serial Driver\n"); 268 /* Init channel A */ 269 port = &scc_ports[0]; 270 port->channel = CHANNEL_A; 271 port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR; 272 port->datap = port->ctrlp + 2; 273 port->port_a = &scc_ports[0]; 274 port->port_b = &scc_ports[1]; 275 request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, 276 "SCC-A TX", port); 277 request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, 278 "SCC-A status", port); 279 request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, 280 "SCC-A RX", port); 281 request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED, 282 "SCC-A special cond", port); 283 { 284 SCC_ACCESS_INIT(port); 285 286 /* disable interrupts for this channel */ 287 SCCwrite(INT_AND_DMA_REG, 0); 288 /* Set the interrupt vector */ 289 SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE); 290 /* Interrupt parameters: vector includes status, status low */ 291 SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); 292 SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); 293 } 294 295 /* Init channel B */ 296 port = &scc_ports[1]; 297 port->channel = CHANNEL_B; 298 port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR; 299 port->datap = port->ctrlp + 2; 300 port->port_a = &scc_ports[0]; 301 port->port_b = &scc_ports[1]; 302 request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, 303 "SCC-B TX", port); 304 request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, 305 "SCC-B status", port); 306 request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, 307 "SCC-B RX", port); 308 request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED, 309 "SCC-B special cond", port); 310 311 { 312 SCC_ACCESS_INIT(port); /* Either channel will do */ 313 314 /* disable interrupts for this channel */ 315 SCCwrite(INT_AND_DMA_REG, 0); 316 } 317 318 /* Ensure interrupts are enabled in the MC2 chip */ 319 *(volatile char *)0xfff4201d = 0x14; 320 321 /* Initialise the tty driver structures and register */ 322 scc_init_portstructs(); 323 scc_init_drivers(); 324 325 return 0; 326} 327#endif 328 329 330#ifdef CONFIG_BVME6000_SCC 331static int bvme6000_scc_init(void) 332{ 333 struct scc_port *port; 334 335 printk(KERN_INFO "SCC: BVME6000 Serial Driver\n"); 336 /* Init channel A */ 337 port = &scc_ports[0]; 338 port->channel = CHANNEL_A; 339 port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR; 340 port->datap = port->ctrlp + 4; 341 port->port_a = &scc_ports[0]; 342 port->port_b = &scc_ports[1]; 343 request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, 344 "SCC-A TX", port); 345 request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, 346 "SCC-A status", port); 347 request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, 348 "SCC-A RX", port); 349 request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED, 350 "SCC-A special cond", port); 351 { 352 SCC_ACCESS_INIT(port); 353 354 /* disable interrupts for this channel */ 355 SCCwrite(INT_AND_DMA_REG, 0); 356 /* Set the interrupt vector */ 357 SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE); 358 /* Interrupt parameters: vector includes status, status low */ 359 SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); 360 SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); 361 } 362 363 /* Init channel B */ 364 port = &scc_ports[1]; 365 port->channel = CHANNEL_B; 366 port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR; 367 port->datap = port->ctrlp + 4; 368 port->port_a = &scc_ports[0]; 369 port->port_b = &scc_ports[1]; 370 request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, 371 "SCC-B TX", port); 372 request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, 373 "SCC-B status", port); 374 request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, 375 "SCC-B RX", port); 376 request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED, 377 "SCC-B special cond", port); 378 379 { 380 SCC_ACCESS_INIT(port); /* Either channel will do */ 381 382 /* disable interrupts for this channel */ 383 SCCwrite(INT_AND_DMA_REG, 0); 384 } 385 386 /* Initialise the tty driver structures and register */ 387 scc_init_portstructs(); 388 scc_init_drivers(); 389 390 return 0; 391} 392#endif 393 394 395static int vme_scc_init(void) 396{ 397 int res = -ENODEV; 398 399#ifdef CONFIG_MVME147_SCC 400 if (MACH_IS_MVME147) 401 res = mvme147_scc_init(); 402#endif 403#ifdef CONFIG_MVME162_SCC 404 if (MACH_IS_MVME16x) 405 res = mvme162_scc_init(); 406#endif 407#ifdef CONFIG_BVME6000_SCC 408 if (MACH_IS_BVME6000) 409 res = bvme6000_scc_init(); 410#endif 411 return res; 412} 413 414module_init(vme_scc_init); 415 416 417/*--------------------------------------------------------------------------- 418 * Interrupt handlers 419 *--------------------------------------------------------------------------*/ 420 421static irqreturn_t scc_rx_int(int irq, void *data) 422{ 423 unsigned char ch; 424 struct scc_port *port = data; 425 struct tty_struct *tty = port->gs.port.tty; 426 SCC_ACCESS_INIT(port); 427 428 ch = SCCread_NB(RX_DATA_REG); 429 if (!tty) { 430 printk(KERN_WARNING "scc_rx_int with NULL tty!\n"); 431 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 432 return IRQ_HANDLED; 433 } 434 tty_insert_flip_char(tty, ch, 0); 435 436 /* Check if another character is already ready; in that case, the 437 * spcond_int() function must be used, because this character may have an 438 * error condition that isn't signalled by the interrupt vector used! 439 */ 440 if (SCCread(INT_PENDING_REG) & 441 (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { 442 scc_spcond_int (irq, data); 443 return IRQ_HANDLED; 444 } 445 446 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 447 448 tty_flip_buffer_push(tty); 449 return IRQ_HANDLED; 450} 451 452 453static irqreturn_t scc_spcond_int(int irq, void *data) 454{ 455 struct scc_port *port = data; 456 struct tty_struct *tty = port->gs.port.tty; 457 unsigned char stat, ch, err; 458 int int_pending_mask = port->channel == CHANNEL_A ? 459 IPR_A_RX : IPR_B_RX; 460 SCC_ACCESS_INIT(port); 461 462 if (!tty) { 463 printk(KERN_WARNING "scc_spcond_int with NULL tty!\n"); 464 SCCwrite(COMMAND_REG, CR_ERROR_RESET); 465 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 466 return IRQ_HANDLED; 467 } 468 do { 469 stat = SCCread(SPCOND_STATUS_REG); 470 ch = SCCread_NB(RX_DATA_REG); 471 472 if (stat & SCSR_RX_OVERRUN) 473 err = TTY_OVERRUN; 474 else if (stat & SCSR_PARITY_ERR) 475 err = TTY_PARITY; 476 else if (stat & SCSR_CRC_FRAME_ERR) 477 err = TTY_FRAME; 478 else 479 err = 0; 480 481 tty_insert_flip_char(tty, ch, err); 482 483 /* ++TeSche: *All* errors have to be cleared manually, 484 * else the condition persists for the next chars 485 */ 486 if (err) 487 SCCwrite(COMMAND_REG, CR_ERROR_RESET); 488 489 } while(SCCread(INT_PENDING_REG) & int_pending_mask); 490 491 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 492 493 tty_flip_buffer_push(tty); 494 return IRQ_HANDLED; 495} 496 497 498static irqreturn_t scc_tx_int(int irq, void *data) 499{ 500 struct scc_port *port = data; 501 SCC_ACCESS_INIT(port); 502 503 if (!port->gs.port.tty) { 504 printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); 505 SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); 506 SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); 507 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 508 return IRQ_HANDLED; 509 } 510 while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) { 511 if (port->x_char) { 512 SCCwrite(TX_DATA_REG, port->x_char); 513 port->x_char = 0; 514 } 515 else if ((port->gs.xmit_cnt <= 0) || 516 port->gs.port.tty->stopped || 517 port->gs.port.tty->hw_stopped) 518 break; 519 else { 520 SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); 521 port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1); 522 if (--port->gs.xmit_cnt <= 0) 523 break; 524 } 525 } 526 if ((port->gs.xmit_cnt <= 0) || port->gs.port.tty->stopped || 527 port->gs.port.tty->hw_stopped) { 528 /* disable tx interrupts */ 529 SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); 530 SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ 531 port->gs.port.flags &= ~GS_TX_INTEN; 532 } 533 if (port->gs.port.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) 534 tty_wakeup(port->gs.port.tty); 535 536 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 537 return IRQ_HANDLED; 538} 539 540 541static irqreturn_t scc_stat_int(int irq, void *data) 542{ 543 struct scc_port *port = data; 544 unsigned channel = port->channel; 545 unsigned char last_sr, sr, changed; 546 SCC_ACCESS_INIT(port); 547 548 last_sr = scc_last_status_reg[channel]; 549 sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); 550 changed = last_sr ^ sr; 551 552 if (changed & SR_DCD) { 553 port->c_dcd = !!(sr & SR_DCD); 554 if (!(port->gs.port.flags & ASYNC_CHECK_CD)) 555 ; /* Don't report DCD changes */ 556 else if (port->c_dcd) { 557 wake_up_interruptible(&port->gs.port.open_wait); 558 } 559 else { 560 if (port->gs.port.tty) 561 tty_hangup (port->gs.port.tty); 562 } 563 } 564 SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); 565 SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); 566 return IRQ_HANDLED; 567} 568 569 570/*--------------------------------------------------------------------------- 571 * generic_serial.c callback funtions 572 *--------------------------------------------------------------------------*/ 573 574static void scc_disable_tx_interrupts(void *ptr) 575{ 576 struct scc_port *port = ptr; 577 unsigned long flags; 578 SCC_ACCESS_INIT(port); 579 580 local_irq_save(flags); 581 SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); 582 port->gs.port.flags &= ~GS_TX_INTEN; 583 local_irq_restore(flags); 584} 585 586 587static void scc_enable_tx_interrupts(void *ptr) 588{ 589 struct scc_port *port = ptr; 590 unsigned long flags; 591 SCC_ACCESS_INIT(port); 592 593 local_irq_save(flags); 594 SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); 595 /* restart the transmitter */ 596 scc_tx_int (0, port); 597 local_irq_restore(flags); 598} 599 600 601static void scc_disable_rx_interrupts(void *ptr) 602{ 603 struct scc_port *port = ptr; 604 unsigned long flags; 605 SCC_ACCESS_INIT(port); 606 607 local_irq_save(flags); 608 SCCmod(INT_AND_DMA_REG, 609 ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0); 610 local_irq_restore(flags); 611} 612 613 614static void scc_enable_rx_interrupts(void *ptr) 615{ 616 struct scc_port *port = ptr; 617 unsigned long flags; 618 SCC_ACCESS_INIT(port); 619 620 local_irq_save(flags); 621 SCCmod(INT_AND_DMA_REG, 0xff, 622 IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL); 623 local_irq_restore(flags); 624} 625 626 627static int scc_get_CD(void *ptr) 628{ 629 struct scc_port *port = ptr; 630 unsigned channel = port->channel; 631 632 return !!(scc_last_status_reg[channel] & SR_DCD); 633} 634 635 636static void scc_shutdown_port(void *ptr) 637{ 638 struct scc_port *port = ptr; 639 640 port->gs.port.flags &= ~ GS_ACTIVE; 641 if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) { 642 scc_setsignals (port, 0, 0); 643 } 644} 645 646 647static int scc_set_real_termios (void *ptr) 648{ 649 /* the SCC has char sizes 5,7,6,8 in that order! */ 650 static int chsize_map[4] = { 0, 2, 1, 3 }; 651 unsigned cflag, baud, chsize, channel, brgval = 0; 652 unsigned long flags; 653 struct scc_port *port = ptr; 654 SCC_ACCESS_INIT(port); 655 656 if (!port->gs.port.tty || !port->gs.port.tty->termios) return 0; 657 658 channel = port->channel; 659 660 if (channel == CHANNEL_A) 661 return 0; /* Settings controlled by boot PROM */ 662 663 cflag = port->gs.port.tty->termios->c_cflag; 664 baud = port->gs.baud; 665 chsize = (cflag & CSIZE) >> 4; 666 667 if (baud == 0) { 668 /* speed == 0 -> drop DTR */ 669 local_irq_save(flags); 670 SCCmod(TX_CTRL_REG, ~TCR_DTR, 0); 671 local_irq_restore(flags); 672 return 0; 673 } 674 else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) || 675 (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) || 676 (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) { 677 printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud); 678 return 0; 679 } 680 681 if (cflag & CLOCAL) 682 port->gs.port.flags &= ~ASYNC_CHECK_CD; 683 else 684 port->gs.port.flags |= ASYNC_CHECK_CD; 685 686#ifdef CONFIG_MVME147_SCC 687 if (MACH_IS_MVME147) 688 brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; 689#endif 690#ifdef CONFIG_MVME162_SCC 691 if (MACH_IS_MVME16x) 692 brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; 693#endif 694#ifdef CONFIG_BVME6000_SCC 695 if (MACH_IS_BVME6000) 696 brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2; 697#endif 698 /* Now we have all parameters and can go to set them: */ 699 local_irq_save(flags); 700 701 /* receiver's character size and auto-enables */ 702 SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE), 703 (chsize_map[chsize] << 6) | 704 ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0)); 705 /* parity and stop bits (both, Tx and Rx), clock mode never changes */ 706 SCCmod (AUX1_CTRL_REG, 707 ~(A1CR_PARITY_MASK | A1CR_MODE_MASK), 708 ((cflag & PARENB 709 ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN) 710 : A1CR_PARITY_NONE) 711 | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1))); 712 /* sender's character size, set DTR for valid baud rate */ 713 SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR); 714 /* clock sources never change */ 715 /* disable BRG before changing the value */ 716 SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0); 717 /* BRG value */ 718 SCCwrite(TIMER_LOW_REG, brgval & 0xff); 719 SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff); 720 /* BRG enable, and clock source never changes */ 721 SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB); 722 723 local_irq_restore(flags); 724 725 return 0; 726} 727 728 729static int scc_chars_in_buffer (void *ptr) 730{ 731 struct scc_port *port = ptr; 732 SCC_ACCESS_INIT(port); 733 734 return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1; 735} 736 737 738/* Comment taken from sx.c (2.4.0): 739 I haven't the foggiest why the decrement use count has to happen 740 here. The whole linux serial drivers stuff needs to be redesigned. 741 My guess is that this is a hack to minimize the impact of a bug 742 elsewhere. Thinking about it some more. (try it sometime) Try 743 running minicom on a serial port that is driven by a modularized 744 driver. Have the modem hangup. Then remove the driver module. Then 745 exit minicom. I expect an "oops". -- REW */ 746 747static void scc_hungup(void *ptr) 748{ 749 scc_disable_tx_interrupts(ptr); 750 scc_disable_rx_interrupts(ptr); 751} 752 753 754static void scc_close(void *ptr) 755{ 756 scc_disable_tx_interrupts(ptr); 757 scc_disable_rx_interrupts(ptr); 758} 759 760 761/*--------------------------------------------------------------------------- 762 * Internal support functions 763 *--------------------------------------------------------------------------*/ 764 765static void scc_setsignals(struct scc_port *port, int dtr, int rts) 766{ 767 unsigned long flags; 768 unsigned char t; 769 SCC_ACCESS_INIT(port); 770 771 local_irq_save(flags); 772 t = SCCread(TX_CTRL_REG); 773 if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); 774 if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); 775 SCCwrite(TX_CTRL_REG, t); 776 local_irq_restore(flags); 777} 778 779 780static void scc_send_xchar(struct tty_struct *tty, char ch) 781{ 782 struct scc_port *port = (struct scc_port *)tty->driver_data; 783 784 port->x_char = ch; 785 if (ch) 786 scc_enable_tx_interrupts(port); 787} 788 789 790/*--------------------------------------------------------------------------- 791 * Driver entrypoints referenced from above 792 *--------------------------------------------------------------------------*/ 793 794static int scc_open (struct tty_struct * tty, struct file * filp) 795{ 796 int line = tty->index; 797 int retval; 798 struct scc_port *port = &scc_ports[line]; 799 int i, channel = port->channel; 800 unsigned long flags; 801 SCC_ACCESS_INIT(port); 802#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC) 803 static const struct { 804 unsigned reg, val; 805 } mvme_init_tab[] = { 806 /* Values for MVME162 and MVME147 */ 807 /* no parity, 1 stop bit, async, 1:16 */ 808 { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, 809 /* parity error is special cond, ints disabled, no DMA */ 810 { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, 811 /* Rx 8 bits/char, no auto enable, Rx off */ 812 { RX_CTRL_REG, RCR_CHSIZE_8 }, 813 /* DTR off, Tx 8 bits/char, RTS off, Tx off */ 814 { TX_CTRL_REG, TCR_CHSIZE_8 }, 815 /* special features off */ 816 { AUX2_CTRL_REG, 0 }, 817 { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG }, 818 { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK }, 819 /* Start Rx */ 820 { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, 821 /* Start Tx */ 822 { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, 823 /* Ext/Stat ints: DCD only */ 824 { INT_CTRL_REG, ICR_ENAB_DCD_INT }, 825 /* Reset Ext/Stat ints */ 826 { COMMAND_REG, CR_EXTSTAT_RESET }, 827 /* ...again */ 828 { COMMAND_REG, CR_EXTSTAT_RESET }, 829 }; 830#endif 831#if defined(CONFIG_BVME6000_SCC) 832 static const struct { 833 unsigned reg, val; 834 } bvme_init_tab[] = { 835 /* Values for BVME6000 */ 836 /* no parity, 1 stop bit, async, 1:16 */ 837 { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, 838 /* parity error is special cond, ints disabled, no DMA */ 839 { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, 840 /* Rx 8 bits/char, no auto enable, Rx off */ 841 { RX_CTRL_REG, RCR_CHSIZE_8 }, 842 /* DTR off, Tx 8 bits/char, RTS off, Tx off */ 843 { TX_CTRL_REG, TCR_CHSIZE_8 }, 844 /* special features off */ 845 { AUX2_CTRL_REG, 0 }, 846 { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG }, 847 { DPLL_CTRL_REG, DCR_BRG_ENAB }, 848 /* Start Rx */ 849 { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, 850 /* Start Tx */ 851 { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, 852 /* Ext/Stat ints: DCD only */ 853 { INT_CTRL_REG, ICR_ENAB_DCD_INT }, 854 /* Reset Ext/Stat ints */ 855 { COMMAND_REG, CR_EXTSTAT_RESET }, 856 /* ...again */ 857 { COMMAND_REG, CR_EXTSTAT_RESET }, 858 }; 859#endif 860 if (!(port->gs.port.flags & ASYNC_INITIALIZED)) { 861 local_irq_save(flags); 862#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) 863 if (MACH_IS_MVME147 || MACH_IS_MVME16x) { 864 for (i = 0; i < ARRAY_SIZE(mvme_init_tab); ++i) 865 SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val); 866 } 867#endif 868#if defined(CONFIG_BVME6000_SCC) 869 if (MACH_IS_BVME6000) { 870 for (i = 0; i < ARRAY_SIZE(bvme_init_tab); ++i) 871 SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val); 872 } 873#endif 874 875 /* remember status register for detection of DCD and CTS changes */ 876 scc_last_status_reg[channel] = SCCread(STATUS_REG); 877 878 port->c_dcd = 0; /* Prevent initial 1->0 interrupt */ 879 scc_setsignals (port, 1,1); 880 local_irq_restore(flags); 881 } 882 883 tty->driver_data = port; 884 port->gs.port.tty = tty; 885 port->gs.port.count++; 886 retval = gs_init_port(&port->gs); 887 if (retval) { 888 port->gs.port.count--; 889 return retval; 890 } 891 port->gs.port.flags |= GS_ACTIVE; 892 retval = gs_block_til_ready(port, filp); 893 894 if (retval) { 895 port->gs.port.count--; 896 return retval; 897 } 898 899 port->c_dcd = scc_get_CD (port); 900 901 scc_enable_rx_interrupts(port); 902 903 return 0; 904} 905 906 907static void scc_throttle (struct tty_struct * tty) 908{ 909 struct scc_port *port = (struct scc_port *)tty->driver_data; 910 unsigned long flags; 911 SCC_ACCESS_INIT(port); 912 913 if (tty->termios->c_cflag & CRTSCTS) { 914 local_irq_save(flags); 915 SCCmod(TX_CTRL_REG, ~TCR_RTS, 0); 916 local_irq_restore(flags); 917 } 918 if (I_IXOFF(tty)) 919 scc_send_xchar(tty, STOP_CHAR(tty)); 920} 921 922 923static void scc_unthrottle (struct tty_struct * tty) 924{ 925 struct scc_port *port = (struct scc_port *)tty->driver_data; 926 unsigned long flags; 927 SCC_ACCESS_INIT(port); 928 929 if (tty->termios->c_cflag & CRTSCTS) { 930 local_irq_save(flags); 931 SCCmod(TX_CTRL_REG, 0xff, TCR_RTS); 932 local_irq_restore(flags); 933 } 934 if (I_IXOFF(tty)) 935 scc_send_xchar(tty, START_CHAR(tty)); 936} 937 938 939static int scc_ioctl(struct tty_struct *tty, struct file *file, 940 unsigned int cmd, unsigned long arg) 941{ 942 return -ENOIOCTLCMD; 943} 944 945 946static int scc_break_ctl(struct tty_struct *tty, int break_state) 947{ 948 struct scc_port *port = (struct scc_port *)tty->driver_data; 949 unsigned long flags; 950 SCC_ACCESS_INIT(port); 951 952 local_irq_save(flags); 953 SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 954 break_state ? TCR_SEND_BREAK : 0); 955 local_irq_restore(flags); 956 return 0; 957} 958 959 960/*--------------------------------------------------------------------------- 961 * Serial console stuff... 962 *--------------------------------------------------------------------------*/ 963 964#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0) 965 966static void scc_ch_write (char ch) 967{ 968 volatile char *p = NULL; 969 970#ifdef CONFIG_MVME147_SCC 971 if (MACH_IS_MVME147) 972 p = (volatile char *)M147_SCC_A_ADDR; 973#endif 974#ifdef CONFIG_MVME162_SCC 975 if (MACH_IS_MVME16x) 976 p = (volatile char *)MVME_SCC_A_ADDR; 977#endif 978#ifdef CONFIG_BVME6000_SCC 979 if (MACH_IS_BVME6000) 980 p = (volatile char *)BVME_SCC_A_ADDR; 981#endif 982 983 do { 984 scc_delay(); 985 } 986 while (!(*p & 4)); 987 scc_delay(); 988 *p = 8; 989 scc_delay(); 990 *p = ch; 991} 992 993/* The console must be locked when we get here. */ 994 995static void scc_console_write (struct console *co, const char *str, unsigned count) 996{ 997 unsigned long flags; 998 999 local_irq_save(flags); 1000 1001 while (count--) 1002 { 1003 if (*str == '\n') 1004 scc_ch_write ('\r'); 1005 scc_ch_write (*str++); 1006 } 1007 local_irq_restore(flags); 1008} 1009 1010static struct tty_driver *scc_console_device(struct console *c, int *index) 1011{ 1012 *index = c->index; 1013 return scc_driver; 1014} 1015 1016static struct console sercons = { 1017 .name = "ttyS", 1018 .write = scc_console_write, 1019 .device = scc_console_device, 1020 .flags = CON_PRINTBUFFER, 1021 .index = -1, 1022}; 1023 1024 1025static int __init vme_scc_console_init(void) 1026{ 1027 if (vme_brdtype == VME_TYPE_MVME147 || 1028 vme_brdtype == VME_TYPE_MVME162 || 1029 vme_brdtype == VME_TYPE_MVME172 || 1030 vme_brdtype == VME_TYPE_BVME4000 || 1031 vme_brdtype == VME_TYPE_BVME6000) 1032 register_console(&sercons); 1033 return 0; 1034} 1035console_initcall(vme_scc_console_init);