📄 sab82532.c
字号:
#ifdef SERIAL_DEBUG_OPEN printk("sab82532_open %s%d, count = %d\n", tty->driver.name, info->line, info->count);#endif if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; if (tmp_buf) free_page(page); else tmp_buf = (unsigned char *) page; } info->count++; tty->driver_data = info; info->tty = tty; /* * If the port is in the middle of closing, bail out now. */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);#else return -EAGAIN;#endif } /* * Start up serial port */ retval = startup(info); if (retval) return retval; MOD_INC_USE_COUNT; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("sab82532_open returning after block_til_ready with %d\n", retval);#endif return retval; } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info); }#ifdef CONFIG_SERIAL_CONSOLE if (sab82532_console.cflag && sab82532_console.index == line) { tty->termios->c_cflag = sab82532_console.cflag; sab82532_console.cflag = 0; change_speed(info); }#endif info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN printk("sab82532_open ttys%d successful... count %d", info->line, info->count);#endif return 0;}/* * /proc fs routines.... */static __inline__ intline_info(char *buf, struct sab82532 *info){ 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; if (!strcmp(edev->prom_name, "serial")) { char compat[32]; int clen; /* On RIO this can be an SE, check it. We could * just check ebus->is_rio, but this is more portable. */ clen = prom_getproperty(edev->prom_node, "compatible", compat, sizeof(compat)); if (clen > 0) { if (strncmp(compat, "sab82532", 8) == 0) { /* Yep. */ 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.65 $"; 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) { int child; child = prom_getchild(enode); snode = prom_searchsiblings(child, "se"); if (snode) goto found; snode = prom_searchsiblings(child, "serial"); if (snode) { char compat[32]; int clen; clen = prom_getproperty(snode, "compatible", compat, sizeof(compat)); if (clen > 0) { if (strncmp(compat, "sab82532", 8) == 0) goto found; } } enode = prom_getsibling(enode); enode = prom_searchsiblings(enode, "ebus"); } node = prom_getsibling(node); node = prom_searchsiblings(node, "pci"); } return -ENODEV;found:#i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -