📄 mxser.c
字号:
memset(&mxvar_sdriver, 0, sizeof(struct tty_driver)); mxvar_sdriver.magic = TTY_DRIVER_MAGIC; mxvar_sdriver.name = "ttyM"; mxvar_sdriver.major = ttymajor; mxvar_sdriver.minor_start = 0; mxvar_sdriver.num = MXSER_PORTS + 1; mxvar_sdriver.type = TTY_DRIVER_TYPE_SERIAL; mxvar_sdriver.subtype = SERIAL_TYPE_NORMAL; mxvar_sdriver.init_termios = tty_std_termios; mxvar_sdriver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; mxvar_sdriver.flags = TTY_DRIVER_REAL_RAW; mxvar_sdriver.refcount = &mxvar_refcount; mxvar_sdriver.table = mxvar_tty; mxvar_sdriver.termios = mxvar_termios; mxvar_sdriver.termios_locked = mxvar_termios_locked; mxvar_sdriver.open = mxser_open; mxvar_sdriver.close = mxser_close; mxvar_sdriver.write = mxser_write; mxvar_sdriver.put_char = mxser_put_char; mxvar_sdriver.flush_chars = mxser_flush_chars; mxvar_sdriver.write_room = mxser_write_room; mxvar_sdriver.chars_in_buffer = mxser_chars_in_buffer; mxvar_sdriver.flush_buffer = mxser_flush_buffer; mxvar_sdriver.ioctl = mxser_ioctl; mxvar_sdriver.throttle = mxser_throttle; mxvar_sdriver.unthrottle = mxser_unthrottle; mxvar_sdriver.set_termios = mxser_set_termios; mxvar_sdriver.stop = mxser_stop; mxvar_sdriver.start = mxser_start; mxvar_sdriver.hangup = mxser_hangup; /* * The callout device is just like normal device except for * major number and the subtype code. */ mxvar_cdriver = mxvar_sdriver; mxvar_cdriver.name = "cum"; mxvar_cdriver.major = calloutmajor; mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT; printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor); mxvar_diagflag = 0; memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); memset(&mxvar_log, 0, sizeof(struct mxser_log)); m = 0; /* Start finding ISA boards here */ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { int cap; if (!(cap = mxserBoardCAP[b])) continue; retval = mxser_get_ISA_conf(cap, &hwconf); if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]); if (retval <= 0) { if (retval == MXSER_ERR_IRQ) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXSER_ERR_IRQ_CONFLIT) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXSER_ERR_VECTOR) printk("Invalid interrupt vector,board not configured\n"); else if (retval == MXSER_ERR_IOADDR) printk("Invalid I/O address,board not configured\n"); continue; } hwconf.pdev = NULL; if (mxser_initbrd(m, &hwconf) < 0) continue; mxser_getcfg(m, &hwconf); m++; } /* Start finding ISA boards from module arg */ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { int cap; if (!(cap = ioaddr[b])) continue; retval = mxser_get_ISA_conf(cap, &hwconf); if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]); if (retval <= 0) { if (retval == MXSER_ERR_IRQ) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXSER_ERR_IRQ_CONFLIT) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXSER_ERR_VECTOR) printk("Invalid interrupt vector,board not configured\n"); else if (retval == MXSER_ERR_IOADDR) printk("Invalid I/O address,board not configured\n"); continue; } hwconf.pdev = NULL; if (mxser_initbrd(m, &hwconf) < 0) continue; mxser_getcfg(m, &hwconf); m++; } /* start finding PCI board here */#ifdef CONFIG_PCI { struct pci_dev *pdev = NULL; n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo); index = 0; b = 0; while (b < n) { pdev = pci_find_device(mxser_pcibrds[b].vendor_id, mxser_pcibrds[b].device_id, pdev); if (!pdev) break; if (pci_enable_device(pdev)) continue; b++; hwconf.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[mxser_pcibrds[b].board_type - 1], pdev->bus->number, PCI_SLOT(pdev->devfn >> 3)); if (m >= MXSER_BOARDS) { printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS); } else { retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].board_type, &hwconf); if (retval < 0) { if (retval == MXSER_ERR_IRQ) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXSER_ERR_IRQ_CONFLIT) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXSER_ERR_VECTOR) printk("Invalid interrupt vector,board not configured\n"); else if (retval == MXSER_ERR_IOADDR) printk("Invalid I/O address,board not configured\n"); continue; } if (mxser_initbrd(m, &hwconf) < 0) continue; mxser_getcfg(m, &hwconf); m++; } } }#endif for (i = m; i < MXSER_BOARDS; i++) { mxsercfg[i].board_type = -1; } ret1 = 0; ret2 = 0; if (!(ret1 = tty_register_driver(&mxvar_sdriver))) { if (!(ret2 = tty_register_driver(&mxvar_cdriver))) { return 0; } else { tty_unregister_driver(&mxvar_sdriver); printk("Couldn't install MOXA Smartio family callout driver !\n"); } } else printk("Couldn't install MOXA Smartio family driver !\n"); if (ret1 || ret2) { for (i = 0; i < MXSER_BOARDS; i++) { if (mxsercfg[i].board_type == -1) continue; else { free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); } } return -1; } return (0);}static void mxser_do_softint(void *private_){ struct mxser_struct *info = (struct mxser_struct *) private_; struct tty_struct *tty; tty = info->tty; if (tty) { if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); wake_up_interruptible(&tty->write_wait); } if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) { tty_hangup(tty); /* FIXME: module removal race here - AKPM */ } } MOD_DEC_USE_COUNT;}/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */static int mxser_open(struct tty_struct *tty, struct file *filp){ struct mxser_struct *info; int retval, line; unsigned long page; line = PORTNO(tty); if (line == MXSER_PORTS) return (0); if ((line < 0) || (line > MXSER_PORTS)) return (-ENODEV); info = mxvar_table + line; if (!info->base) return (-ENODEV); info->count++; tty->driver_data = info; info->tty = tty; if (!mxvar_tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) return (-ENOMEM); if (mxvar_tmp_buf) free_page(page); else mxvar_tmp_buf = (unsigned char *) page; } /* * Start up serial port */ retval = mxser_startup(info); if (retval) return (retval); retval = mxser_block_til_ready(tty, filp, info); if (retval) 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; mxser_change_speed(info, 0); } info->session = current->session; info->pgrp = current->pgrp; MOD_INC_USE_COUNT; return (0);}/* * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. */static void mxser_close(struct tty_struct *tty, struct file *filp){ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; unsigned long flags; unsigned long timeout; if (PORTNO(tty) == MXSER_PORTS) return; if (!info) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); MOD_DEC_USE_COUNT; return; } if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("mxser_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("mxser_close: bad serial port count for ttys%d: %d\n", info->port, info->count); info->count = 0; } if (info->count) { restore_flags(flags); MOD_DEC_USE_COUNT; return; } info->flags |= ASYNC_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; if (info->flags & ASYNC_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ info->IER &= ~UART_IER_RLSI; /* by William info->read_status_mask &= ~UART_LSR_DR; */ if (info->flags & ASYNC_INITIALIZED) { outb(info->IER, info->base + UART_IER); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ timeout = jiffies + HZ; while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(5); if (jiffies > timeout) break; } } mxser_shutdown(info); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); MOD_DEC_USE_COUNT;}static int mxser_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ int c, total = 0; struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; unsigned long flags; if (!tty || !info->xmit_buf || !mxvar_tmp_buf) return (0); if (from_user) down(&mxvar_tmp_buf_sem); save_flags(flags); while (1) { cli(); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; if (from_user) { copy_from_user(mxvar_tmp_buf, buf, c); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); } else memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); info->xmit_cnt += c; restore_flags(flags); buf += c; count -= c; total += c; } if (from_user) up(&mxvar_tmp_buf_sem); if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); } restore_flags(flags); return (total);}static void mxser_put_char(struct tty_struct *tty, unsigned char ch){ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; unsigned long flags; if (!tty || !info->xmit_buf) return; save_flags(flags); cli(); if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { restore_flags(flags); return; } info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; /********************************************** why ??? *********** if ( !tty->stopped && !tty->hw_stopped && !(info->IER & UART_IER_THRI) ) { info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); } *****************************************************************/ restore_flags(flags);}static void mxser_flush_chars(struct tty_struct *tty){ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; unsigned long flags; if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) return; save_flags(flags); cli(); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); restore_flags(flags);}static int mxser_write_room(struct tty_struct *tty){ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; int ret; ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; if (ret < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -