📄 sab82532.c
字号:
unsigned long flags; char stat_buf[30]; int ret; ret = sprintf(buf, "%u: uart:SAB82532 ", info->line); switch (info->type) { case 0: ret += sprintf(buf+ret, "V1.0 "); break; case 1: ret += sprintf(buf+ret, "V2.0 "); break; case 2: ret += sprintf(buf+ret, "V3.2 "); break; default: ret += sprintf(buf+ret, "V?.? "); break; } ret += sprintf(buf+ret, "port:%lX irq:%s", (unsigned long)info->regs, __irq_itoa(info->irq)); if (!info->regs) { ret += sprintf(buf+ret, "\n"); return ret; } /* * Figure out the current RS-232 lines */ stat_buf[0] = 0; stat_buf[1] = 0; save_flags(flags); cli(); if (readb(&info->regs->r.mode) & SAB82532_MODE_RTS) { if (!(readb(&info->regs->r.mode) & SAB82532_MODE_FRTS)) strcat(stat_buf, "|RTS"); } else { strcat(stat_buf, "|RTS"); } if (readb(&info->regs->r.star) & SAB82532_STAR_CTS) strcat(stat_buf, "|CTS"); if (!(readb(&info->regs->r.pvr) & info->pvr_dtr_bit)) strcat(stat_buf, "|DTR"); if (!(readb(&info->regs->r.pvr) & info->pvr_dsr_bit)) strcat(stat_buf, "|DSR"); if (!(readb(&info->regs->r.vstr) & SAB82532_VSTR_CD)) strcat(stat_buf, "|CD"); restore_flags(flags); if (info->baud) ret += sprintf(buf+ret, " baud:%u", info->baud); ret += sprintf(buf+ret, " tx:%u rx:%u", info->icount.tx, info->icount.rx); if (info->icount.frame) ret += sprintf(buf+ret, " fe:%u", info->icount.frame); if (info->icount.parity) ret += sprintf(buf+ret, " pe:%u", info->icount.parity); if (info->icount.brk) ret += sprintf(buf+ret, " brk:%u", info->icount.brk); if (info->icount.overrun) ret += sprintf(buf+ret, " oe:%u", info->icount.overrun); /* * Last thing is the RS-232 status lines. */ ret += sprintf(buf+ret, " %s\n", stat_buf + 1); return ret;}int sab82532_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct sab82532 *info = sab82532_chain; off_t begin = 0; int len = 0; len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); for (info = sab82532_chain; info && len < 4000; info = info->next) { len += line_info(page + len, info); if (len+begin > off+count) goto done; if (len+begin < off) { begin += len; len = 0; } } *eof = 1;done: if (off >= len+begin) return 0; *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off);}/* * --------------------------------------------------------------------- * sab82532_init() and friends * * sab82532_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- */static int __init get_sab82532(unsigned long *memory_start){ struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; struct sab82532 *sab; unsigned long regs, offset; int i; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "se")) goto ebus_done; } }ebus_done: if (!edev) return -ENODEV; regs = edev->resource[0].start; offset = sizeof(union sab82532_async_regs); for (i = 0; i < 2; i++) { if (memory_start) { *memory_start = (*memory_start + 7) & ~(7); sab = (struct sab82532 *)*memory_start; *memory_start += sizeof(struct sab82532); } else { sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), GFP_KERNEL); if (!sab) { printk("sab82532: can't alloc sab struct\n"); break; } } memset(sab, 0, sizeof(struct sab82532)); sab->regs = ioremap(regs + offset, sizeof(union sab82532_async_regs)); sab->irq = edev->irqs[0]; sab->line = 1 - i; sab->xmit_fifo_size = 32; sab->recv_fifo_size = 32; writeb(SAB82532_IPC_IC_ACT_LOW, &sab->regs->w.ipc); sab->next = sab82532_chain; sab82532_chain = sab; offset -= sizeof(union sab82532_async_regs); } return 0;}#ifndef MODULEstatic void __init sab82532_kgdb_hook(int line){ prom_printf("sab82532: kgdb support is not implemented, yet\n"); prom_halt();}#endifstatic inline void __init show_serial_version(void){ char *revision = "$Revision: 1.54 $"; char *version, *p; version = strchr(revision, ' '); strcpy(serial_version, ++version); p = strchr(serial_version, ' '); *p = '\0'; printk("SAB82532 serial driver version %s\n", serial_version);}extern int su_num_ports;/* * The serial driver boot-time initialization code! */int __init sab82532_init(void){ struct sab82532 *info; int i; if (!sab82532_chain) get_sab82532(0); if (!sab82532_chain) return -ENODEV; init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); /* Initialize the tty_driver structure */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial";#ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/%d";#else serial_driver.name = "ttyS";#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + su_num_ports; serial_driver.num = NR_PORTS; 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 = &sab82532_refcount; serial_driver.table = sab82532_table; serial_driver.termios = sab82532_termios; serial_driver.termios_locked = sab82532_termios_locked; serial_driver.open = sab82532_open; serial_driver.close = sab82532_close; serial_driver.write = sab82532_write; serial_driver.put_char = sab82532_put_char; serial_driver.flush_chars = sab82532_flush_chars; serial_driver.write_room = sab82532_write_room; serial_driver.chars_in_buffer = sab82532_chars_in_buffer; serial_driver.flush_buffer = sab82532_flush_buffer; serial_driver.ioctl = sab82532_ioctl; serial_driver.throttle = sab82532_throttle; serial_driver.unthrottle = sab82532_unthrottle; serial_driver.send_xchar = sab82532_send_xchar; serial_driver.set_termios = sab82532_set_termios; serial_driver.stop = sab82532_stop; serial_driver.start = sab82532_start; serial_driver.hangup = sab82532_hangup; serial_driver.break_ctl = sab82532_break; serial_driver.wait_until_sent = sab82532_wait_until_sent; serial_driver.read_proc = sab82532_read_proc; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver;#ifdef 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; callout_driver.read_proc = 0; callout_driver.proc_entry = 0; 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"); for (info = sab82532_chain, i = 0; info; info = info->next, i++) { info->magic = SERIAL_MAGIC; info->type = readb(&info->regs->r.vstr) & 0x0f; writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &info->regs->w.pcr); writeb(0xff, &info->regs->w.pim); if (info->line == 0) { info->pvr_dsr_bit = (1 << 0); info->pvr_dtr_bit = (1 << 1); } else { info->pvr_dsr_bit = (1 << 3); info->pvr_dtr_bit = (1 << 2); } writeb((1 << 1) | (1 << 2) | (1 << 4), &info->regs->w.pvr); writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode); info->custom_divisor = 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; info->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; info->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; info->x_char = 0; info->event = 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); init_waitqueue_head(&info->delta_msr_wait); info->icount.cts = info->icount.dsr = info->icount.rng = info->icount.dcd = 0; info->icount.rx = info->icount.tx = 0; info->icount.frame = info->icount.parity = 0; info->icount.overrun = info->icount.brk = 0; if (!(info->line & 0x01)) { if (request_irq(info->irq, sab82532_interrupt, SA_SHIRQ, "serial(sab82532)", info)) { printk("sab82532: can't get IRQ %x\n", info->irq); panic("sab82532 initialization failed"); } } printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %s) is a SAB82532 %s\n", info->line + su_num_ports, (unsigned long)info->regs, __irq_itoa(info->irq), sab82532_version[info->type]); }#ifdef SERIAL_LOG_DEVICE dprint_init(SERIAL_LOG_DEVICE);#endif return 0;}int __init sab82532_probe(void){ int node, enode, snode; char model[32]; int len; node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "pci"); /* * Check for SUNW,sabre on Ultra 5/10/AXi. */ len = prom_getproperty(node, "model", model, sizeof(model)); if ((len > 0) && !strncmp(model, "SUNW,sabre", len)) { node = prom_getchild(node); node = prom_searchsiblings(node, "pci"); } /* * For each PCI bus... */ while (node) { enode = prom_getchild(node); enode = prom_searchsiblings(enode, "ebus"); /* * For each EBus on this PCI... */ while (enode) { snode = prom_getchild(enode); snode = prom_searchsiblings(snode, "se"); if (snode) goto found; enode = prom_getsibling(enode); enode = prom_searchsiblings(enode, "ebus"); } node = prom_getsibling(node); node = prom_searchsiblings(node, "pci"); } return -ENODEV;found:#ifdef CONFIG_SERIAL_CONSOLE sunserial_setinitfunc(sab82532_console_init);#endif#ifndef MODULE sunserial_setinitfunc(sab82532_init); rs_ops.rs_kgdb_hook = sab82532_kgdb_hook;#endif return 0;}#ifdef MODULEint init_module(void){ if (get_sab82532(0)) return -ENODEV; return sab82532_init();}void cleanup_module(void) { struct sab82532 *sab; unsigned long flags; int e1, e2; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ save_flags(flags); cli(); remove_bh(SERIAL_BH); if ((e1 = tty_unregister_driver(&serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); if ((e2 = tty_unregister_driver(&callout_driver))) printk("SERIAL: failed to unregister callout driver (%d)\n", e2); restore_flags(flags); if (tmp_buf) { free_page((unsigned long) tmp_buf); tmp_buf = NULL; } for (sab = sab82532_chain; sab; sab = sab->next) { if (!(sab->line & 0x01)) free_irq(sab->irq, sab); iounmap(sab->regs); }}#endif /* MODULE */#ifdef CONFIG_SERIAL_CONSOLEstatic voidbatten_down_hatches(struct sab82532 *info){ unsigned char saved_rfc, tmp; if (!stop_a_enabled) return; /* If we are doing kadb, we call the debugger * else we just drop into the boot monitor. * Note that we must flush the user windows * first before giving up control. */ printk("\n"); flush_user_windows(); /* * Set FIFO to single character mode. */ saved_rfc = readb(&info->regs->r.rfc); tmp = readb(&info->regs->rw.rfc); tmp &= ~(SAB82532_RFC_RFDF); writeb(tmp, &info->regs->rw.rfc); sab82532_cec_wait(info); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);#ifndef __sparc_v9__ if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) && (((unsigned long)linux_dbvec) <= DEBUG_LASTVADDR)) sp_enter_debugger(); else#endif prom_cmdline(); /* * Reset FIFO to character + status mode. */ writeb(saved_rfc, &info->regs->w.rfc); sab82532_cec_wait(info); writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);}static __inline__ voidsab82532_console_putchar(struct sab82532 *info, char c){ unsigned long flags; save_flags(flags); cli(); sab82532_tec_wait(info); writeb(c, &info->regs->w.tic); restore_flags(flags);}static voidsab82532_console_write(struct console *con, const char *s, unsigned n){ struct sab82532 *info; int i; info = sab82532_chain; for (i = con->index; i; i--) { info = info->next; if (!info) return; } for (i = 0; i < n; i++) { if (*s == '\n') sab82532_console_putchar(info, '\r'); sab82532_console_putchar(info, *s++); } sab82532_tec_wait(info);}static intsab82532_console_wait_key(struct console *con)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -