📄 mxser.c
字号:
pci_resource_len(pdev, 2), "mxser(IO)"); for (i = 0; i < hwconf->ports; i++) { hwconf->ioaddr[i] = ioaddress + 8*i; } //vector ioaddress = pci_resource_start(pdev, 3); request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3), "mxser(vector)"); hwconf->vector = ioaddress; //irq hwconf->irq = hwconf->pciInfo.pdev->irq; hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]); hwconf->uart_type = PORT_16550A; hwconf->vector_mask = 0; for (i = 0; i < hwconf->ports; i++) { for(j=0; j<UART_INFO_NUM ;j++){ if(Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) { hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud; //exception....CP-102 if(board_type == MXSER_BOARD_CP102) hwconf->MaxCanSetBaudRate[i] = 921600; break; } } } if(hwconf->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID){ for (i = 0; i < hwconf->ports; i++) { if ( i < 4 ) hwconf->opmode_ioaddr[i] = ioaddress + 4; else hwconf->opmode_ioaddr[i] = ioaddress + 0x0c; } outb(0, ioaddress+4); // default set to RS232 mode outb(0, ioaddress+0x0c); //default set to RS232 mode } for (i = 0; i < hwconf->ports; i++) { hwconf->vector_mask |= (1<<i); hwconf->baud_base[i] = 921600; } return(0);}#endifint mxser_init(void){ int i, m, retval, b; int ret1, ret2;#ifdef CONFIG_PCIstruct pci_dev *pdev=NULL; int index; unsigned char busnum,devnum;#endif struct mxser_hwconf hwconf;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); if (!mxvar_sdriver) return -ENOMEM;#endif spin_lock_init(&gm_lock); for(i=0; i<MXSER_BOARDS; i++){ mxsercfg[i].board_type = -1; } printk("MOXA Smartio/Industio family driver version %s\n",MXSER_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) = "ttyM"; DRV_VAR_P(major) = ttymajor; DRV_VAR_P(minor_start) = 0; DRV_VAR_P(num) = MXSER_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, &mxser_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) = mxser_open; DRV_VAR_P(close) = mxser_close; DRV_VAR_P(write) = mxser_write; DRV_VAR_P(put_char) = mxser_put_char; DRV_VAR_P(flush_chars) = mxser_flush_chars; DRV_VAR_P(write_room) = mxser_write_room; DRV_VAR_P(chars_in_buffer) = mxser_chars_in_buffer; DRV_VAR_P(flush_buffer) = mxser_flush_buffer; DRV_VAR_P(ioctl) = mxser_ioctl; DRV_VAR_P(throttle) = mxser_throttle; DRV_VAR_P(unthrottle) = mxser_unthrottle; DRV_VAR_P(set_termios) = mxser_set_termios; DRV_VAR_P(stop) = mxser_stop; DRV_VAR_P(start) = mxser_start; DRV_VAR_P(hangup) = mxser_hangup;// added by James 03-12-2004.#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,66)) /* Linux 2.1.66 */ DRV_VAR_P(break_ctl) = mxser_rs_break;#endif// (above) added by James.#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) DRV_VAR_P(wait_until_sent) = mxser_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 = "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);#endif mxvar_diagflag = 0; memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); memset(&mxvar_log, 0, sizeof(struct mxser_log)); memset(&mxser_msr, 0, sizeof(unsigned char) * (MXSER_PORTS+1)); memset(&mon_data_ext, 0, sizeof(struct mxser_mon_ext)); memset(&mxser_set_baud_method, 0, sizeof(int) * (MXSER_PORTS+1)); memset(&hwconf, 0, sizeof(struct mxser_hwconf)); 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.pciInfo.busNum = 0; hwconf.pciInfo.devNum = 0; hwconf.pciInfo.pdev = NULL; mxser_getcfg(m,&hwconf); //init mxsercfg first, or mxsercfg data is not correct on ISR. //mxser_initbrd will hook ISR. if(mxser_initbrd(m,&hwconf)<0) continue; 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.pciInfo.busNum = 0; hwconf.pciInfo.devNum = 0; hwconf.pciInfo.pdev = NULL; mxser_getcfg(m,&hwconf); //init mxsercfg first, or mxsercfg data is not correct on ISR. //mxser_initbrd will hook ISR. if(mxser_initbrd(m,&hwconf)<0) continue; m++; } /* start finding PCI board here */#ifdef CONFIG_PCI#if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) if (pcibios_present()) {#else#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) if (pci_present()) {#else { #endif #endif int n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1; index = 0; b = 0; while (b < n) { pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev); if(pdev==NULL){ b++; continue; } hwconf.pciInfo.busNum = busnum = pdev->bus->number; hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn)<<3; hwconf.pciInfo.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",mxser_brdname[(int)(mxser_pcibrds[b].driver_data)-1],busnum,devnum >> 3); index++; if ( m >= MXSER_BOARDS) { printk("Too many Smartio/Industio family boards find (maximum %d),board not configured\n",MXSER_BOARDS); } else { if ( pci_enable_device(pdev) ) { printk("Moxa SmartI/O PCI enable fail !\n"); continue; } retval = mxser_get_PCI_conf(busnum,devnum, (int)mxser_pcibrds[b].driver_data,&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; } mxser_getcfg(m,&hwconf); //init mxsercfg first, or mxsercfg data is not correct on ISR. //mxser_initbrd will hook ISR. if(mxser_initbrd(m,&hwconf)<0) continue; m++; } } }#endif 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)) ){// init_timer(&moxaTimer);// moxaTimer.function = mxser_poll;// moxaTimer.expires = jiffies + (HZ / 10); /* 0.1 sec */// moxaTimer_on = 1;// add_timer(&moxaTimer); return 0; }else{ tty_unregister_driver(DRV_VAR); printk("Couldn't install MOXA Smartio/Industio family callout driver !\n"); }#else return 0; #endif }else printk("Couldn't install MOXA Smartio/Industio 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]); //todo: release io, vector } } 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 (LINUX_VERSION_CODE < VERSION_CODE(2,1,0)) if ( 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 ( clear_bit(MXSER_EVENT_HANGUP, &info->event) ) { tty_hangup(tty); }#else 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); }#endif }#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) MX_MOD_DEC;#endif}static unsigned char mxser_get_msr(int baseaddr, int mode, int port, struct mxser_struct *info){ unsigned char status=0; status = inb(baseaddr + UART_MSR); mxser_msr[port] &= 0x0F; mxser_msr[port] |= status; status = mxser_msr[port]; if( mode ) mxser_msr[port] = 0; return status;}/* * 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; //unsigned char status; 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); tty->driver_data = info; info->tty = tty; if ( !mxvar_tmp_buf ) { page = GET_FPAGE(GFP_KERNEL); if ( !page ) return(-ENOMEM); if ( mxvar_tmp_buf ) free_page(page); else mxvar_tmp_buf = (unsigned char *)page; }//printk("port %d, mxser_open\r\n", info->port); /* * Start up serial port */ retval = mxser_startup(info); if ( retval ) return(retval); retval = mxser_block_til_ready(tty, filp, info); if ( retval ) return(retval); info->count++; MX_MOD_INC; if ( (info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS) ) { if ( MX_TTY_DRV(subtype) == SERIAL_TYPE_NORMAL ) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; mxser_change_speed(info, 0); } info->session = MX_SESSION(); info->pgrp = MX_CGRP(); clear_bit(TTY_DONT_FLIP, &tty->flags); //status = mxser_get_msr(info->base, 0, info->port); //mxser_check_modem_status(info, status);/* unmark here for very high baud rate (ex. 921600 bps) used*/#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) tty->low_latency = 1;#endif 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 timeout; MX_LOCK_INIT();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -