📄 moxa.c
字号:
printk("Board %2d: %s board(baseAddr=%lx)\n", numBoards + 1, moxa_brdname[type[i] - 1], (unsigned long) baseaddr[i]); if (numBoards >= MAX_BOARDS) { if (verbose) printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); continue; } moxa_boards[numBoards].boardType = type[i]; if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) moxa_boards[numBoards].numPorts = 8; else moxa_boards[numBoards].numPorts = numports[i]; moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; moxa_boards[numBoards].baseAddr = baseaddr[i]; numBoards++; } }#endif /* Find PCI boards here */#ifdef CONFIG_PCI { struct pci_dev *p = NULL; n = sizeof(moxa_pcibrds) / sizeof(moxa_pciinfo); i = 0; while (i < n) { while((p = pci_find_device(moxa_pcibrds[i].vendor_id, moxa_pcibrds[i].device_id, p))!=NULL) { if (pci_enable_device(p)) continue; if (numBoards >= MAX_BOARDS) { if (verbose) printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); } else { moxa_get_PCI_conf(p, moxa_pcibrds[i].board_type, &moxa_boards[numBoards]); numBoards++; } } i++; } }#endif for (i = 0; i < numBoards; i++) { moxaBaseAddr[i] = (unsigned long) ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000); } return (0);}static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board){ board->baseAddr = pci_resource_start (p, 2); board->boardType = board_type; switch (board_type) { case MOXA_BOARD_C218_ISA: case MOXA_BOARD_C218_PCI: board->numPorts = 8; break; case MOXA_BOARD_CP204J: board->numPorts = 4; break; default: board->numPorts = 0; break; } board->busType = MOXA_BUS_TYPE_PCI; board->pciInfo.busNum = p->bus->number; board->pciInfo.devNum = p->devfn >> 3; return (0);}static void do_moxa_softint(void *private_){ struct moxa_str *ch = (struct moxa_str *) private_; struct tty_struct *tty; if (ch && (tty = ch->tty)) { if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) { tty_hangup(tty); /* FIXME: module removal race here - AKPM */ wake_up_interruptible(&ch->open_wait); ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); } } MOD_DEC_USE_COUNT;}static int moxa_open(struct tty_struct *tty, struct file *filp){ struct moxa_str *ch; int port; int retval; unsigned long page; port = PORTNO(tty); if (port == MAX_PORTS) { MOD_INC_USE_COUNT; return (0); } if (!MoxaPortIsValid(port)) { tty->driver_data = NULL; return (-ENODEV); } down(&moxaBuffSem); if (!moxaXmitBuff) { page = get_free_page(GFP_KERNEL); if (!page) { up(&moxaBuffSem); return (-ENOMEM); } if (moxaXmitBuff) free_page(page); else moxaXmitBuff = (unsigned char *) page; } up(&moxaBuffSem); MOD_INC_USE_COUNT; ch = &moxaChannels[port]; ch->count++; tty->driver_data = ch; ch->tty = tty; if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = ch->normal_termios; else *tty->termios = ch->callout_termios; } ch->session = current->session; ch->pgrp = current->pgrp; if (!(ch->asyncflags & ASYNC_INITIALIZED)) { ch->statusflags = 0; set_tty_param(tty); MoxaPortLineCtrl(ch->port, 1, 1); MoxaPortEnable(ch->port); ch->asyncflags |= ASYNC_INITIALIZED; } retval = block_till_ready(tty, filp, ch); moxa_unthrottle(tty); if (ch->type == PORT_16550A) { MoxaSetFifo(ch->port, 1); } else { MoxaSetFifo(ch->port, 0); } return (retval);}static void moxa_close(struct tty_struct *tty, struct file *filp){ struct moxa_str *ch; int port; port = PORTNO(tty); if (port == MAX_PORTS) { MOD_DEC_USE_COUNT; return; } if (!MoxaPortIsValid(port)) {#ifdef SERIAL_DEBUG_CLOSE printk("Invalid portno in moxa_close\n");#endif tty->driver_data = NULL; return; } if (tty->driver_data == NULL) { return; } if (tty_hung_up_p(filp)) { MOD_DEC_USE_COUNT; return; } ch = (struct moxa_str *) tty->driver_data; if ((tty->count == 1) && (ch->count != 1)) { printk("moxa_close: bad serial port count; tty->count is 1, " "ch->count is %d\n", ch->count); ch->count = 1; } if (--ch->count < 0) { printk("moxa_close: bad serial port count, minor=%d\n", MINOR(tty->device)); ch->count = 0; } if (ch->count) { MOD_DEC_USE_COUNT; return; } ch->asyncflags |= ASYNC_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) ch->normal_termios = *tty->termios; if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) ch->callout_termios = *tty->termios; if (ch->asyncflags & ASYNC_INITIALIZED) { setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ moxaEmptyTimer_on[ch->port] = 0; del_timer(&moxaEmptyTimer[ch->port]); } shut_down(ch); MoxaPortFlushData(port, 2); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); tty->closing = 0; ch->event = 0; ch->tty = 0; if (ch->blocked_open) { if (ch->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(ch->close_delay); } wake_up_interruptible(&ch->open_wait); } ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); MOD_DEC_USE_COUNT;}static int moxa_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ struct moxa_str *ch; int len, port; unsigned long flags; unsigned char *temp; ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return (0); port = ch->port; save_flags(flags); cli(); if (from_user) { copy_from_user(moxaXmitBuff, buf, count); temp = moxaXmitBuff; } else temp = (unsigned char *) buf; len = MoxaPortWriteData(port, temp, count); restore_flags(flags); /********************************************* if ( !(ch->statusflags & LOWWAIT) && ((len != count) || (MoxaPortTxFree(port) <= 100)) ) ************************************************/ ch->statusflags |= LOWWAIT; return (len);}static int moxa_write_room(struct tty_struct *tty){ struct moxa_str *ch; if (tty->stopped) return (0); ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return (0); return (MoxaPortTxFree(ch->port));}static void moxa_flush_buffer(struct tty_struct *tty){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; MoxaPortFlushData(ch->port, 1); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); wake_up_interruptible(&tty->write_wait);}static int moxa_chars_in_buffer(struct tty_struct *tty){ int chars; struct moxa_str *ch = (struct moxa_str *) tty->driver_data; /* * Sigh...I have to check if driver_data is NULL here, because * if an open() fails, the TTY subsystem eventually calls * tty_wait_until_sent(), which calls the driver's chars_in_buffer() * routine. And since the open() failed, we return 0 here. TDJ */ if (ch == NULL) return (0); chars = MoxaPortTxQueue(ch->port); if (chars) { /* * Make it possible to wakeup anything waiting for output * in tty_ioctl.c, etc. */ if (!(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty); } return (chars);}static void moxa_flush_chars(struct tty_struct *tty){ /* * Don't think I need this, because this is called to empty the TX * buffer for the 16450, 16550, etc. */}static void moxa_put_char(struct tty_struct *tty, unsigned char c){ struct moxa_str *ch; int port; unsigned long flags; ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; port = ch->port; save_flags(flags); cli(); moxaXmitBuff[0] = c; MoxaPortWriteData(port, moxaXmitBuff, 1); restore_flags(flags); /************************************************ if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) *************************************************/ ch->statusflags |= LOWWAIT;}static int moxa_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; register int port; int retval, dtr, rts; unsigned long flag; port = PORTNO(tty); if ((port != MAX_PORTS) && (!ch)) return (-EINVAL); switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return (retval); setup_empty_event(tty); tty_wait_until_sent(tty, 0); if (!arg) MoxaPortSendBreak(ch->port, 0); return (0); case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return (retval); setup_empty_event(tty); tty_wait_until_sent(tty, 0); MoxaPortSendBreak(ch->port, arg); return (0); case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); case TIOCSSOFTCAR: if(get_user(retval, (unsigned long *) arg)) return -EFAULT; arg = retval; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); if (C_CLOCAL(tty)) ch->asyncflags &= ~ASYNC_CHECK_CD; else ch->asyncflags |= ASYNC_CHECK_CD; return (0); case TIOCMGET: flag = 0; MoxaPortGetLineOut(ch->port, &dtr, &rts); if (dtr) flag |= TIOCM_DTR; if (rts) flag |= TIOCM_RTS; dtr = MoxaPortLineStatus(ch->port); if (dtr & 1) flag |= TIOCM_CTS; if (dtr & 2) flag |= TIOCM_DSR; if (dtr & 4) flag |= TIOCM_CD; return put_user(flag, (unsigned int *) arg); case TIOCMBIS: if(get_user(retval, (unsigned int *) arg)) return -EFAULT; MoxaPortGetLineOut(ch->port, &dtr, &rts); if (retval & TIOCM_RTS) rts = 1; if (retval & TIOCM_DTR) dtr = 1; MoxaPortLineCtrl(ch->port, dtr, rts); return (0); case TIOCMBIC: if(get_user(retval, (unsigned int *) arg)) return -EFAULT; MoxaPortGetLineOut(ch->port, &dtr, &rts); if (retval & TIOCM_RTS) rts = 0; if (retval & TIOCM_DTR) dtr = 0; MoxaPortLineCtrl(ch->port, dtr, rts); return (0); case TIOCMSET: if(get_user(retval, (unsigned long *) arg)) return -EFAULT; dtr = rts = 0; if (retval & TIOCM_RTS) rts = 1; if (retval & TIOCM_DTR) dtr = 1; MoxaPortLineCtrl(ch->port, dtr, rts); return (0); case TIOCGSERIAL: return (moxa_get_serial_info(ch, (struct serial_struct *) arg)); case TIOCSSERIAL: return (moxa_set_serial_info(ch, (struct serial_struct *) arg)); default: retval = MoxaDriverIoctl(cmd, arg, port); } return (retval);}static void moxa_throttle(struct tty_struct *tty){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; ch->statusflags |= THROTTLE;}static void moxa_unthrottle(struct tty_struct *tty){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; ch->statusflags &= ~THROTTLE;}static void moxa_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct moxa_str *ch = (struct moxa_str *) tty->driver_data; if (ch == NULL) return; set_tty_param(tty); if (!(old_termios->c_cflag & CLOCAL) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -