📄 sgiserial.c
字号:
info->flags |= ZILOG_NORMAL_ACTIVE; return 0;} /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its ZILOG structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */int rs_open(struct tty_struct *tty, struct file * filp){ struct sgi_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; /* The zilog lines for the mouse/keyboard must be * opened using their respective drivers. */ if ((line < 0) || (line >= NUM_CHANNELS)) return -ENODEV; info = zs_soft + line; /* Is the kgdb running over this line? */ if (info->kgdb_channel) return -ENODEV; if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->count);#endif info->count++; tty->driver_data = info; info->tty = tty; /* * Start up serial port */ retval = startup(info); if (retval) return retval; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval);#endif return retval; } if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info); } /* If this is the serial console change the speed to * the right value */ if (info->is_cons) { info->tty->termios->c_cflag = sgisercon->cflag; change_speed(info); } info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN printk("rs_open ttys%d successful...\n", info->line);#endif return 0;}/* Finally, routines used to initialize the serial driver. */static void show_serial_version(void){ printk("SGI Zilog8530 serial driver version 1.00\n");}/* Return layout for the requested zs chip number. */static inline struct sgi_zslayout *get_zs(int chip){ extern struct hpc3_miscregs *hpc3mregs; if (chip > 0) panic("Wheee, bogus zs chip number requested."); return (struct sgi_zslayout *) (&hpc3mregs->ser1cmd);}static inline voidrs_cons_check(struct sgi_serial *ss, int channel){ int i, o, io; static int msg_printed = 0; i = o = io = 0; /* Is this one of the serial console lines? */ if((zs_cons_chanout != channel) && (zs_cons_chanin != channel)) return; zs_conschan = ss->zs_channel; zs_consinfo = ss; /* If this is console input, we handle the break received * status interrupt on this line to mean prom_halt(). */ if(zs_cons_chanin == channel) { ss->break_abort = 1; i = 1; } if(o && i) io = 1; /* Set flag variable for this port so that it cannot be * opened for other uses by accident. */ ss->is_cons = 1; if(io) { if (!msg_printed) { printk("zs%d: console I/O\n", ((channel>>1)&1)); msg_printed = 1; } } else { printk("zs%d: console %s\n", ((channel>>1)&1), (i==1 ? "input" : (o==1 ? "output" : "WEIRD"))); }}volatile int test_done;/* rs_init inits the driver */int rs_init(void){ int chip, channel, i, flags; struct sgi_serial *info; /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); /* Initialize the tty_driver structure */ /* SGI: Not all of this is exactly right for us. */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NUM_CHANNELS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; serial_driver.flush_chars = rs_flush_chars; serial_driver.write_room = rs_write_room; serial_driver.chars_in_buffer = rs_chars_in_buffer; serial_driver.flush_buffer = rs_flush_buffer; serial_driver.ioctl = rs_ioctl; serial_driver.throttle = rs_throttle; serial_driver.unthrottle = rs_unthrottle; serial_driver.set_termios = rs_set_termios; serial_driver.stop = rs_stop; serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver; callout_driver.name = "cua"; callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); save_flags(flags); cli(); /* Set up our interrupt linked list */ zs_chain = &zs_soft[0]; zs_soft[0].zs_next = &zs_soft[1]; zs_soft[1].zs_next = 0; for(chip = 0; chip < NUM_SERIAL; chip++) { /* If we are doing kgdb over one of the channels on * chip zero, kgdb_channel will be set to 1 by the * rs_kgdb_hook() routine below. */ if(!zs_chips[chip]) { zs_chips[chip] = get_zs(chip); /* Two channels per chip */ zs_channels[(chip*2)] = &zs_chips[chip]->channelB; zs_channels[(chip*2)+1] = &zs_chips[chip]->channelA; zs_soft[(chip*2)].kgdb_channel = 0; zs_soft[(chip*2)+1].kgdb_channel = 0; } /* First, set up channel A on this chip. */ channel = chip * 2; zs_soft[channel].zs_channel = zs_channels[channel]; zs_soft[channel].change_needed = 0; zs_soft[channel].clk_divisor = 16; zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); zs_soft[channel].cons_mouse = 0; /* If not keyboard/mouse and is console serial * line, then enable receiver interrupts. */ if(zs_soft[channel].is_cons) { write_zsreg(zs_soft[channel].zs_channel, R1, (EXT_INT_ENAB | INT_ALL_Rx)); write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE)); write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ)); write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE)); write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB)); } /* If this is the kgdb line, enable interrupts because we * now want to receive the 'control-c' character from the * client attached to us asynchronously. */ if(zs_soft[channel].kgdb_channel) kgdb_chaninit(&zs_soft[channel], 1, zs_soft[channel].zs_baud); /* Now, channel B */ channel++; zs_soft[channel].zs_channel = zs_channels[channel]; zs_soft[channel].change_needed = 0; zs_soft[channel].clk_divisor = 16; zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); zs_soft[channel].cons_keyb = 0; /* If console serial line, then enable receiver interrupts. */ if(zs_soft[channel].is_cons) { write_zsreg(zs_soft[channel].zs_channel, R1, (EXT_INT_ENAB | INT_ALL_Rx)); write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE)); write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ)); write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE)); write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB | RTS | DTR)); } } for(info=zs_chain, i=0; info; info = info->zs_next, i++) { info->magic = SERIAL_MAGIC; info->port = (int) info->zs_channel; info->line = i; info->tty = 0; info->irq = zilog_irq; info->custom_divisor = 16; info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; info->event = 0; info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; info->callout_termios =callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); printk("tty%02d at 0x%04x (irq = %d)", info->line, info->port, info->irq); printk(" is a Zilog8530\n"); } if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT), "Zilog8530", zs_chain)) panic("Unable to attach zs intr\n"); restore_flags(flags); return 0;}/* * register_serial and unregister_serial allows for serial ports to be * configured at run-time, to support PCMCIA modems. *//* SGI: Unused at this time, just here to make things link. */int register_serial(struct serial_struct *req){ return -1;}void unregister_serial(int line){ return;}/* Hooks for running a serial console. con_init() calls this if the * console is being run over one of the ttya/ttyb serial ports. * 'chip' should be zero, as chip 1 drives the mouse/keyboard. * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels * are addressed backwards, channel B is first, then channel A. */voidrs_cons_hook(int chip, int out, int line){ int channel; if(chip) panic("rs_cons_hook called with chip not zero"); if(line != 0 && line != 1) panic("rs_cons_hook called with line not ttya or ttyb"); channel = line; if(!zs_chips[chip]) { zs_chips[chip] = get_zs(chip); /* Two channels per chip */ zs_channels[(chip*2)] = &zs_chips[chip]->channelB; zs_channels[(chip*2)+1] = &zs_chips[chip]->channelA; } zs_soft[channel].zs_channel = zs_channels[channel]; zs_soft[channel].change_needed = 0; zs_soft[channel].clk_divisor = 16; zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); if(out) zs_cons_chanout = ((chip * 2) + channel); else zs_cons_chanin = ((chip * 2) + channel); rs_cons_check(&zs_soft[channel], channel);}/* This is called at boot time to prime the kgdb serial debugging * serial line. The 'tty_num' argument is 0 for /dev/ttyd2 and 1 for * /dev/ttyd1 (yes they are backwards on purpose) which is determined * in setup_arch() from the boot command line flags. */voidrs_kgdb_hook(int tty_num){ int chip = 0; if(!zs_chips[chip]) { zs_chips[chip] = get_zs(chip); /* Two channels per chip */ zs_channels[(chip*2)] = &zs_chips[chip]->channelA; zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; } zs_soft[tty_num].zs_channel = zs_channels[tty_num]; zs_kgdbchan = zs_soft[tty_num].zs_channel; zs_soft[tty_num].change_needed = 0; zs_soft[tty_num].clk_divisor = 16; zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]); zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */ zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */ /* Turn on transmitter/receiver at 8-bits/char */ kgdb_chaninit(&zs_soft[tty_num], 0, 9600); ZS_CLEARERR(zs_kgdbchan); udelay(5); ZS_CLEARFIFO(zs_kgdbchan);}static void zs_console_write(struct console *co, const char *str, unsigned int count){ while(count--) { if(*str == '\n') zs_cons_put_char('\r'); zs_cons_put_char(*str++); } /* Comment this if you want to have a strict interrupt-driven output */ rs_fair_output();}static int zs_console_wait_key(struct console *con){ sleep_on(&keypress_wait); return 0;}static kdev_t zs_console_device(struct console *con){ return MKDEV(TTY_MAJOR, 64 + con->index);}static int __init zs_console_setup(struct console *con, char *options){ struct sgi_serial *info; int baud; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s, *dbaud; int i, brg; if (options) { baud = simple_strtoul(options, NULL, 10); s = options; while(*s >= '0' && *s <= '9') s++; if (*s) parity = *s++; if (*s) bits = *s - '0'; } else { /* If the user doesn't set console=... try to read the * PROM variable - if this fails use 9600 baud and * inform the user about the problem */ dbaud = ArcGetEnvironmentVariable("dbaud"); if(dbaud) baud = simple_strtoul(dbaud, NULL, 10); else { /* Use prom_printf() to make sure that the user * is getting anything ... */ prom_printf("No dbaud set in PROM ?!? Using 9600.\n"); baud = 9600; } } /* * Now construct a cflag setting. */ switch(baud) { case 1200: cflag |= B1200; break; case 2400: cflag |= B2400; break; case 4800: cflag |= B4800; break; case 19200: cflag |= B19200; break; case 38400: cflag |= B38400; break; case 57600: cflag |= B57600; break; case 115200: cflag |= B115200; break; case 9600: default: cflag |= B9600; break; } switch(bits) { case 7: cflag |= CS7; break; default: case 8: cflag |= CS8; break; } switch(parity) { case 'o': case 'O': cflag |= PARODD; break; case 'e': case 'E': cflag |= PARENB; break; } con->cflag = cflag; rs_cons_hook(0, 0, con->index); info = zs_soft + con->index; info->is_cons = 1; printk("Console: ttyS%d (Zilog8530), %d baud\n", info->line, baud); i = con->cflag & CBAUD; if (con->cflag & CBAUDEX) { i &= ~CBAUDEX; con->cflag &= ~CBAUDEX; } info->zs_baud = baud; switch (con->cflag & CSIZE) { case CS5: zscons_regs[3] = Rx5 | RxENABLE; zscons_regs[5] = Tx5 | TxENAB; break; case CS6: zscons_regs[3] = Rx6 | RxENABLE; zscons_regs[5] = Tx6 | TxENAB; break; case CS7: zscons_regs[3] = Rx7 | RxENABLE; zscons_regs[5] = Tx7 | TxENAB; break; default: case CS8: zscons_regs[3] = Rx8 | RxENABLE; zscons_regs[5] = Tx8 | TxENAB; break; } zscons_regs[5] |= DTR; if (con->cflag & PARENB) zscons_regs[4] |= PAR_ENA; if (!(con->cflag & PARODD)) zscons_regs[4] |= PAR_EVEN; if (con->cflag & CSTOPB) zscons_regs[4] |= SB2; else zscons_regs[4] |= SB1; sgisercon = con; brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor); zscons_regs[12] = brg & 0xff; zscons_regs[13] = (brg >> 8) & 0xff; memcpy(info->curregs, zscons_regs, sizeof(zscons_regs)); memcpy(info->pendregs, zscons_regs, sizeof(zscons_regs)); load_zsregs(info->zs_channel, zscons_regs); ZS_CLEARERR(info->zs_channel); ZS_CLEARFIFO(info->zs_channel); return 0;}static struct console sgi_console_driver = { name: "ttyS", write: zs_console_write, device: zs_console_device, wait_key: zs_console_wait_key, setup: zs_console_setup, flags: CON_PRINTBUFFER, index: -1,};/* * Register console. */void __init sgi_serial_console_init(void){ register_console(&sgi_console_driver);}__initcall(rs_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -