zs.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,301 行 · 第 1/4 页
C
2,301 行
#ifndef CONFIG_SERIAL_CONSOLE /* * We're called early and memory managment isn't up, yet. * Thus check_region would fail. */ if (!request_region((unsigned long) zs_channels[n_channels].control, ZS_CHAN_IO_SIZE, "SCC")) panic("SCC I/O region is not free");#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); */}static struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, .write = rs_write, .flush_chars = rs_flush_chars, .write_room = rs_write_room, .chars_in_buffer = rs_chars_in_buffer, .flush_buffer = rs_flush_buffer, .ioctl = rs_ioctl, .throttle = rs_throttle, .unthrottle = rs_unthrottle, .set_termios = rs_set_termios, .stop = rs_stop, .start = rs_start, .hangup = rs_hangup, .break_ctl = rs_break, .wait_until_sent = rs_wait_until_sent, .tiocmget = rs_tiocmget, .tiocmset = rs_tiocmset,};/* 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(); serial_driver = alloc_tty_driver(zs_channels_found); if (!serial_driver) return -ENOMEM; show_serial_version(); /* Initialize the tty_driver structure */ /* Not all of this is exactly right for us. */ serial_driver->owner = THIS_MODULE; serial_driver->devfs_name = "tts/"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; serial_driver->minor_start = 64; 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; tty_set_operations(serial_driver, &serial_ops); if (tty_register_driver(serial_driver)) panic("Couldn't register serial 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; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); printk("ttyS%d at 0x%08x (irq = %d)", info->line, info->port, info->irq); printk(" is a Z85C30 SCC\n"); tty_register_device(serial_driver, info->line, NULL); } 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("%s: line %d has already a hook registered\n", __FUNCTION__, 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("%s: trying to unregister hook on line %d," " but none is registered\n", __FUNCTION__, 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); }}static struct tty_driver *serial_console_device(struct console *c, int *index){ *index = c->index; return serial_driver;}/* * 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, .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 + =
减小字号Ctrl + -
显示快捷键?