📄 zs.c
字号:
} request_region((unsigned long) zs_channels[n_channels].control, ZS_CHAN_IO_SIZE, "SCC");#endif zs_soft[n_channels].zs_channel = &zs_channels[n_channels]; zs_soft[n_channels].irq = zs_parms->irq; /* * Identification of channel A. Location of channel A * inside chip depends on mapping of internal address * the chip decodes channels by. * CHANNEL_A_NR returns either 0 (in case of * DECstations) or 1 (in case of Baget). */ if (CHANNEL_A_NR == channel) zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1-2*CHANNEL_A_NR]; else zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels]; *pp = &zs_soft[n_channels]; pp = &zs_soft[n_channels].zs_next; n_channels++; } } *pp = 0; zs_channels_found = n_channels; for (n = 0; n < zs_channels_found; n++) { for (i = 0; i < 16; i++) { zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i]; } }/* save_and_cli(flags); for (n = 0; n < zs_channels_found; n++) { if (((int)zs_channels[n].control & 0xf) == 1) { write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES); mdelay(10); write_zsreg(zs_soft[n].zs_chan_a, R9, 0); } load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs); } restore_flags(flags); */}/* zs_init inits the driver */int __init zs_init(void){ int channel, i; unsigned long flags; struct dec_serial *info; if(!BUS_PRESENT) return -ENODEV; /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) probe_sccs(); show_serial_version(); /* Initialize the tty_driver structure */ /* Not all of this is exactly right for us. */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC;#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/%d";#else serial_driver.name = "ttyS";#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = zs_channels_found; 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 | TTY_DRIVER_NO_DEVFS; 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; serial_driver.break_ctl = rs_break; serial_driver.wait_until_sent = rs_wait_until_sent; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver;#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua/%d";#else callout_driver.name = "cua";#endif 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(); for (channel = 0; channel < zs_channels_found; ++channel) { if (zs_soft[channel].hook && zs_soft[channel].hook->init_channel) (*zs_soft[channel].hook->init_channel) (&zs_soft[channel]); zs_soft[channel].clk_divisor = 16; zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ, "SCC", &zs_soft[channel])) printk(KERN_ERR "decserial: can't get irq %d\n", zs_parms->irq); } for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { if (info->hook && info->hook->init_info) { (*info->hook->init_info)(info); continue; } info->magic = SERIAL_MAGIC; info->port = (int) info->zs_channel->control; info->line = i; info->tty = 0; 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->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("ttyS%02d at 0x%08x (irq = %d)", info->line, info->port, info->irq); printk(" is a Z85C30 SCC\n"); tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + info->line); tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + info->line); } restore_flags(flags); return 0;}/* * register_serial and unregister_serial allows for serial ports to be * configured at run-time, to support PCMCIA modems. *//* PowerMac: 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;}/* * polling I/O routines */static intzs_poll_tx_char(struct dec_serial *info, unsigned char ch){ struct dec_zschannel *chan = info->zs_channel; int ret; if(chan) { int loops = 10000;// int nine = read_zsreg(chan, R9); RECOVERY_DELAY;// write_zsreg(chan, R9, nine & ~MIE); wbflush(); RECOVERY_DELAY; while (!(*(chan->control) & Tx_BUF_EMP) && --loops) RECOVERY_DELAY; if (loops) { ret = 0; *(chan->data) = ch; wbflush(); RECOVERY_DELAY; } else ret = -EAGAIN;// write_zsreg(chan, R9, nine); wbflush(); RECOVERY_DELAY; return ret; } return -ENODEV;}static intzs_poll_rx_char(struct dec_serial *info){ struct dec_zschannel *chan = info->zs_channel; int ret; if(chan) { int loops = 10000; while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) loops--; if (loops) ret = read_zsdata(chan); else ret = -EAGAIN; return ret; } else return -ENODEV;}unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook){ struct dec_serial *info = &zs_soft[channel]; if (info->hook) { printk(__FUNCTION__": line %d has already a hook registered\n", channel); return 0; } else { info->hook = hook; if (zs_chain == 0) probe_sccs(); if (!(info->flags & ZILOG_INITIALIZED)) zs_startup(info); hook->poll_rx_char = zs_poll_rx_char; hook->poll_tx_char = zs_poll_tx_char; return 1; }}unsigned int unregister_zs_hook(unsigned int channel){ struct dec_serial *info = &zs_soft[channel]; if (info->hook) { info->hook = NULL; return 1; } else { printk(__FUNCTION__": trying to unregister hook on line %d," " but none is registered\n", channel); return 0; }}/* * ------------------------------------------------------------ * Serial console driver * ------------------------------------------------------------ */#ifdef CONFIG_SERIAL_CONSOLE/* * Print a string to the serial port trying not to disturb * any possible real use of the port... */static void serial_console_write(struct console *co, const char *s, unsigned count){ struct dec_serial *info; int i; info = zs_soft + co->index; for (i = 0; i < count; i++, s++) { if(*s == '\n') zs_poll_tx_char(info, '\r'); zs_poll_tx_char(info, *s); }}/* * Receive character from the serial port */static int serial_console_wait_key(struct console *co){ struct dec_serial *info; info = zs_soft + co->index; return zs_poll_rx_char(info);}static kdev_t serial_console_device(struct console *c){ return MKDEV(TTY_MAJOR, 64 + c->index);}/* * Setup initial baud/bits/parity. We do two things here: * - construct a cflag setting for the first rs_open() * - initialize the serial port * Return non-zero if we didn't find a serial port. */static int __init serial_console_setup(struct console *co, char *options){ struct dec_serial *info; int baud = 9600; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; unsigned long flags; if(!BUS_PRESENT) return -ENODEV; info = zs_soft + co->index; if (zs_chain == 0) probe_sccs(); info->is_cons = 1; 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'; } /* * 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; } co->cflag = cflag;#if 1 save_and_cli(flags); /* * Turn on RTS and DTR. */ zs_rtsdtr(info, RTS | DTR, 1); /* * Finally, enable sequencing */ info->zs_channel->curregs[3] |= (RxENABLE | Rx8); info->zs_channel->curregs[5] |= (TxENAB | Tx8); info->zs_channel->curregs[9] |= (VIS); write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]); /* * Clear the interrupt registers. */ write_zsreg(info->zs_channel, 0, ERR_RES); write_zsreg(info->zs_channel, 0, RES_H_IUS); /* * Set the speed of the serial port */ change_speed(info); /* Save the current value of RR0 */ info->read_reg_zero = read_zsreg(info->zs_channel, 0); zs_soft[co->index].clk_divisor = 16; zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]); restore_flags(flags);#endif return 0;}static struct console sercons = { name: "ttyS", write: serial_console_write, device: serial_console_device, wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1,};/* * Register console. */void __init zs_serial_console_init(void){ register_console(&sercons);}#endif /* ifdef CONFIG_SERIAL_CONSOLE */#ifdef CONFIG_KGDBstruct dec_zschannel *zs_kgdbchan;static unsigned char scc_inittab[] = { 9, 0x80, /* reset A side (CHRA) */ 13, 0, /* set baud rate divisor */ 12, 1, 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */ 11, 0x50, /* clocks = br gen (RCBR | TCBR) */ 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */ 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/ 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/};/* These are for receiving and sending characters under the kgdb * source level kernel debugger. */void putDebugChar(char kgdb_char){ struct dec_zschannel *chan = zs_kgdbchan; while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) RECOVERY_DELAY; write_zsdata(chan, kgdb_char);}char getDebugChar(void){ struct dec_zschannel *chan = zs_kgdbchan; while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) eieio(); /*barrier();*/ return read_zsdata(chan);}void kgdb_interruptible(int yes){ struct dec_zschannel *chan = zs_kgdbchan; int one, nine; nine = read_zsreg(chan, 9); if (yes == 1) { one = EXT_INT_ENAB|INT_ALL_Rx; nine |= MIE; printk("turning serial ints on\n"); } else { one = RxINT_DISAB; nine &= ~MIE; printk("turning serial ints off\n"); } write_zsreg(chan, 1, one); write_zsreg(chan, 9, nine);}static int kgdbhook_init_channel(struct dec_serial* info) { return 0;}static void kgdbhook_init_info(struct dec_serial* info){}static void kgdbhook_rx_char(struct dec_serial* info, unsigned char ch, unsigned char stat){ if (ch == 0x03 || ch == '$') breakpoint(); if (stat & (Rx_OVR|FRM_ERR|PAR_ERR)) write_zsreg(info->zs_channel, 0, ERR_RES);}/* This sets up the serial port we're using, and turns on * interrupts for that channel, so kgdb is usable once we're done. */static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps){ int brg; int i, x; volatile char *sccc = ms->control; brg = BPS_TO_BRG(bps, zs_parms->clock/16); printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg); for (i = 20000; i != 0; --i) { x = *sccc; eieio(); } for (i = 0; i < sizeof(scc_inittab); ++i) { write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]); i++; }}/* This is called at boot time to prime the kgdb serial debugging * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */struct zs_hook zs_kgdbhook = { init_channel : kgdbhook_init_channel, init_info : kgdbhook_init_info, cflags : B38400|CS8|CLOCAL, rx_char : kgdbhook_rx_char,}void __init zs_kgdb_hook(int tty_num){ /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) probe_sccs(); 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 = 38400; zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */ /* Turn on transmitter/receiver at 8-bits/char */ kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400); printk("KGDB: on channel %d initialized\n", tty_num); set_debug_traps(); /* init stub */}#endif /* ifdef CONFIG_KGDB */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -