📄 mxpcdrv.c
字号:
#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0))static struct tty_operations mxpcdrv_ops = { .open = mxpcdrv_open, .close = mxpcdrv_close, .write = mxpcdrv_write, .put_char = mxpcdrv_put_char, .flush_chars = mxpcdrv_flush_chars, .write_room = mxpcdrv_write_room, .chars_in_buffer = mxpcdrv_chars_in_buffer, .flush_buffer = mxpcdrv_flush_buffer, .ioctl = mxpcdrv_ioctl, .throttle = mxpcdrv_throttle, .unthrottle = mxpcdrv_unthrottle, .set_termios = mxpcdrv_set_termios, .stop = mxpcdrv_stop, .start = mxpcdrv_start, .hangup = mxpcdrv_hangup, .tiocmget = mxpcdrv_tiocmget, .tiocmset = mxpcdrv_tiocmset,};#endifstatic int CheckIsMoxaMust(int io){ UCHAR oldmcr, hwid; outb(0, io+UART_LCR); DISABLE_MOXA_MUST_ENCHANCE_MODE(io); oldmcr = inb(io+UART_MCR); outb(0, io+UART_MCR); SET_MOXA_MUST_XON1_VALUE(io, 0x11); if ( (hwid=inb(io+UART_MCR)) != 0 ) { outb(oldmcr, io+UART_MCR); return(0); } GET_MOXA_MUST_HARDWARE_ID(io, &hwid); if ( hwid != MOXA_MUST_HARDWARE_ID ) return(0); return(1);}// above is modified by Victor Yu. 08-15-2002/* * The MOXA PC104 Communication Module serial driver boot-time initialization code! */INIT_FUNC_RET INIT_FUNC(void){ int ret; if (verbose) printk("Loading module mxpcdrv ...\n"); ret = mxpcdrv_init(); if (verbose) printk("Done.\n"); return (ret);}CLEAR_FUNC_RET CLEAR_FUNC(void){ int i,err = 0; if (verbose) printk("Unloading module mxpcdrv ...\n");#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) if ((err |= tty_unregister_driver(&mxvar_cdriver))) printk("Couldn't unregister MOXA PC104 Communication Module callout driver\n");#endif if ((err |= tty_unregister_driver(DRV_VAR))) printk("Couldn't unregister MOXA PC104 Communication Module serial driver\n"); for(i=0; i<MXPCDRV_BOARDS; i++){ if(mxpcdrvcfg[i].board_type == -1) continue; else{ free_irq(mxpcdrvcfg[i].irq, &mxvar_table[i*MXPCDRV_PORTS_PER_BOARD]); release_region(mxpcdrvcfg[i].ioaddr[0],8*mxpcdrvcfg[i].ports); if ((mxpcdrvcfg[i].pciInfo.busNum == 0)&&(mxpcdrvcfg[i].pciInfo.devNum == 0)) release_region(mxpcdrvcfg[i].vector,1); else release_region(mxpcdrvcfg[i].vector,16); } } if (verbose) printk("Done.\n");}int mxpcdrv_initbrd(int board,struct mxpcdrv_hwconf *hwconf){ struct mxpcdrv_struct * info; int retval; int i,n;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)) init_MUTEX(&mxvar_tmp_buf_sem); #endif n = board*MXPCDRV_PORTS_PER_BOARD; info = &mxvar_table[n]; #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) printk(" ttyN%d/cum%d - ttyN%d/cum%d ", n, n, n+hwconf->ports-1, n+hwconf->ports-1);#else printk(" ttyN%d - ttyN%d ", n, n+hwconf->ports-1);#endif printk(" max. baud rate = %d bps.\n", hwconf->MaxCanSetBaudRate[0]); for ( i=0; i<hwconf->ports; i++, n++, info++ ) { info->port = n; info->base = hwconf->ioaddr[i]; info->irq = hwconf->irq; info->vector = hwconf->vector; info->vectormask = hwconf->vector_mask; info->ldisc_stop_rx = 0; // following add by Victor Yu. 08-30-2002 // Moxa Must UART support FIFO is 64bytes for Tx/Rx // but receive FIFO just can set up to 62 will be OK. info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag; if ( hwconf->IsMoxaMustChipFlag ) info->rx_trigger = 56; else // above add by Victor Yu. 08-30-2002 info->rx_trigger = 14; info->baud_base = hwconf->baud_base[i]; info->flags = ASYNC_SHARE_IRQ; info->type = hwconf->uart_type; if ( (info->type == PORT_16450) || (info->type == PORT_8250) ) info->xmit_fifo_size = 1; else info->xmit_fifo_size = 16; // following add by Victor Yu. 08-30-2002 if ( info->IsMoxaMustChipFlag ) { info->xmit_fifo_size = 64; ENABLE_MOXA_MUST_ENHANCE_MODE(info->base); } info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i]; // above add by Victor Yu. 08-30-2002 info->custom_divisor = hwconf->baud_base[i] * 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ;#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19)) INIT_WORK(&info->tqueue, mxpcdrv_do_softint);#else INIT_WORK(&info->tqueue, mxpcdrv_do_softint, info);#endif#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) info->callout_termios = mxvar_cdriver.init_termios;#endif info->normal_termios = DRV_VAR_P(init_termios);#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)) init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait);#endif/* added by casper 1/11/2000 */#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) info->icount.rx = info->icount.tx = 0;#endif info->icount.cts = info->icount.dsr = info->icount.dsr = info->icount.dcd = 0;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) info->icount.frame = info->icount.overrun = info->icount.brk = info->icount.parity = 0;#endif/* */ spin_lock_init(&info->slock); } request_region(hwconf->ioaddr[0],8*hwconf->ports,"mxpcdrv(io)"); if ((hwconf->pciInfo.busNum == 0)&&(hwconf->pciInfo.devNum == 0)) request_region(hwconf->vector,1,"mxpcdrv(vector)"); else request_region(hwconf->vector,16,"mxpcdrv(vector)"); /* * Allocate the IRQ if necessary */ /* before set INT ISR, disable all int */ for(i=0; i<hwconf->ports; i++){ outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0, hwconf->ioaddr[i]+UART_IER); } n = board*MXPCDRV_PORTS_PER_BOARD; info = &mxvar_table[n]; retval = request_irq(hwconf->irq, mxpcdrv_interrupt, IRQ_T(info), "mxpcdrv", info); if ( retval ) { printk("Board %d: %s", board, mxpcdrv_brdname[hwconf->board_type-1]); printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n",info->irq); return(retval); } return 0;}static void mxpcdrv_getcfg(int board,struct mxpcdrv_hwconf *hwconf){ mxpcdrvcfg[board] = *hwconf;}int mxpcdrv_init(void){ int i, m, retval, b; int ret1, ret2; struct mxpcdrv_hwconf hwconf; #if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) mxvar_sdriver = alloc_tty_driver(MXPCDRV_PORTS + 1); if (!mxvar_sdriver) return -ENOMEM;#endif printk("MOXA PC104 Communication Module driver version %s\n",MXPCDRV_VERSION); /* Initialize the tty_driver structure */ memset(DRV_VAR, 0, sizeof(struct tty_driver)); DRV_VAR_P(magic) = TTY_DRIVER_MAGIC; DRV_VAR_P(name) = "ttyN"; DRV_VAR_P(major) = ttymajor; DRV_VAR_P(minor_start) = 0; DRV_VAR_P(num) = MXPCDRV_PORTS + 1; DRV_VAR_P(type) = TTY_DRIVER_TYPE_SERIAL; DRV_VAR_P(subtype) = SERIAL_TYPE_NORMAL; DRV_VAR_P(init_termios) = tty_std_termios; DRV_VAR_P(init_termios.c_cflag) = B9600|CS8|CREAD|HUPCL|CLOCAL; DRV_VAR_P(flags) = TTY_DRIVER_REAL_RAW;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) tty_set_operations(DRV_VAR, &mxpcdrv_ops); DRV_VAR_P(ttys) = mxvar_tty;#else DRV_VAR_P(refcount) = &mxvar_refcount; DRV_VAR_P(table) = mxvar_tty;#endif DRV_VAR_P(termios) = mxvar_termios; DRV_VAR_P(termios_locked) = mxvar_termios_locked; DRV_VAR_P(open) = mxpcdrv_open; DRV_VAR_P(close) = mxpcdrv_close; DRV_VAR_P(write) = mxpcdrv_write; DRV_VAR_P(put_char) = mxpcdrv_put_char; DRV_VAR_P(flush_chars) = mxpcdrv_flush_chars; DRV_VAR_P(write_room) = mxpcdrv_write_room; DRV_VAR_P(chars_in_buffer) = mxpcdrv_chars_in_buffer; DRV_VAR_P(flush_buffer) = mxpcdrv_flush_buffer; DRV_VAR_P(ioctl) = mxpcdrv_ioctl; DRV_VAR_P(throttle) = mxpcdrv_throttle; DRV_VAR_P(unthrottle) = mxpcdrv_unthrottle; DRV_VAR_P(set_termios) = mxpcdrv_set_termios; DRV_VAR_P(stop) = mxpcdrv_stop; DRV_VAR_P(start) = mxpcdrv_start; DRV_VAR_P(hangup) = mxpcdrv_hangup;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) DRV_VAR_P(wait_until_sent) = mxpcdrv_wait_until_sent;#endif#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) /* * The callout device is just like normal device except for * major number and the subtype code. */ mxvar_cdriver = mxvar_sdriver; mxvar_cdriver.name = "cun"; mxvar_cdriver.major = calloutmajor; mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT; printk("Tty devices major number = %d, callout devices major number = %d\n",ttymajor,calloutmajor);#endif mxvar_diagflag = 0; memset(mxvar_table, 0, MXPCDRV_PORTS * sizeof(struct mxpcdrv_struct)); memset(&mxvar_log, 0, sizeof(struct mxpcdrv_log)); m = 0; /* Start finding ISA boards here */ for ( b=0; b<MXPCDRV_BOARDS && m<MXPCDRV_BOARDS; b++ ) { int cap,vector,irq; if ( !(cap=mxpcdrvBoardIO[b]) ) continue; if ( !(vector=mxpcdrvBoardVECT[b]) ) continue; if ( !(irq=mxpcdrvBoardIRQ[b]) ) continue; retval = mxpcdrv_get_ISA_conf(cap, vector, &hwconf, irq); if ( retval != 0 ) printk("Found MOXA %s board (IO=0x%x,Vector=0x%x,IRQ=%d)\n", mxpcdrv_brdname[hwconf.board_type-1], mxpcdrvBoardIO[b],mxpcdrvBoardVECT[b], mxpcdrvBoardIRQ[b]); if ( retval <= 0 ) { if (retval == MXPCDRV_ERR_IRQ) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXPCDRV_ERR_IRQ_CONFLIT) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXPCDRV_ERR_VECTOR) printk("Invalid interrupt vector,board not configured\n"); else if (retval == MXPCDRV_ERR_IOADDR) printk("Invalid I/O address,board not configured\n"); continue; } hwconf.pciInfo.busNum = 0; hwconf.pciInfo.devNum = 0; mxpcdrv_getcfg(m,&hwconf); if(mxpcdrv_initbrd(m,&hwconf)<0) continue; m++; } /* Start finding ISA boards from module arg */ for ( b=0; b<MXPCDRV_BOARDS && m<MXPCDRV_BOARDS; b++ ) { int cap,vector; if ( !(cap=ioaddr[b]) ) continue; if ( !(vector=iovect[b]) ) continue; if ( !(irq[b]) ) continue; retval = mxpcdrv_get_ISA_conf(cap, vector, &hwconf, irq[b]); if ( retval != 0 ) printk("Found MOXA %s board (IO=0x%x,Vector=0x%x,IRQ=%d)\n", mxpcdrv_brdname[hwconf.board_type-1], ioaddr[b],iovect[b],irq[b]); if ( retval <= 0 ) { if (retval == MXPCDRV_ERR_IRQ) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXPCDRV_ERR_IRQ_CONFLIT) printk("Invalid interrupt number,board not configured\n"); else if (retval == MXPCDRV_ERR_VECTOR) printk("Invalid interrupt vector,board not configured\n"); else if (retval == MXPCDRV_ERR_IOADDR) printk("Invalid I/O address,board not configured\n"); continue; } hwconf.pciInfo.busNum = 0; hwconf.pciInfo.devNum = 0; mxpcdrv_getcfg(m,&hwconf); if(mxpcdrv_initbrd(m,&hwconf)<0) continue; m++; } for(i=m; i<MXPCDRV_BOARDS; i++){ mxpcdrvcfg[i].board_type = -1; } ret1 = 0; ret2 = 0; if ( !(ret1=tty_register_driver(DRV_VAR)) ){#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) if ( !(ret2=tty_register_driver(&mxvar_cdriver)) ){ return 0; }else{ tty_unregister_driver(DRV_VAR); printk("Couldn't install MOXA PC104 Communication Module callout driver !\n"); }#else return 0; #endif }else printk("Couldn't install MOXA PC104 Communication Module driver !\n"); if(ret1 || ret2){ for(i=0; i<MXPCDRV_BOARDS; i++){ if(mxpcdrvcfg[i].board_type == -1) continue; else{ free_irq(mxpcdrvcfg[i].irq, &mxvar_table[i*MXPCDRV_PORTS_PER_BOARD]); } } return -1; } return(0);}#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static void mxpcdrv_do_softint(struct work_struct *work){ struct mxpcdrv_struct * info = container_of(work,struct mxpcdrv_struct, tqueue);#elsestatic void mxpcdrv_do_softint(void *private_){ struct mxpcdrv_struct * info = (struct mxpcdrv_struct *)private_;#endif struct tty_struct * tty; tty = info->tty;#if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) if ( clear_bit(MXPCDRV_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 ( clear_bit(MXPCDRV_EVENT_HANGUP, &info->event) ) { tty_hangup(tty); }#else#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,9)) if ( test_and_clear_bit(MXPCDRV_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); }#else if ( test_and_clear_bit(MXPCDRV_EVENT_TXLOW, &info->event) ) tty_wakeup(tty);#endif if ( test_and_clear_bit(MXPCDRV_EVENT_HANGUP, &info->event) ) { tty_hangup(tty); }#endif #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) MX_MOD_DEC; #endif}/* * 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 mxpcdrv_open(struct tty_struct * tty, struct file * filp){ struct mxpcdrv_struct * info; int retval, line; unsigned long page; line = PORTNO(tty); if ( line == MXPCDRV_PORTS ) return(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -