📄 mxser.c
字号:
unsigned long txcnt[MXSER_PORTS];};struct mxser_mon{ unsigned long rxcnt; unsigned long txcnt; unsigned long up_rxcnt; unsigned long up_txcnt; int modem_status; unsigned char hold_reason;};struct mxser_mon_ext{ unsigned long rx_cnt[32]; unsigned long tx_cnt[32]; unsigned long up_rxcnt[32]; unsigned long up_txcnt[32]; int modem_status[32]; long baudrate[32]; int databits[32]; int stopbits[32]; int parity[32]; int flowctrl[32]; int fifo[32]; int iftype[32];};struct mxser_hwconf { int board_type; int ports; int irq; int vector; int vector_mask; int uart_type; int ioaddr[MXSER_PORTS_PER_BOARD]; int baud_base[MXSER_PORTS_PER_BOARD]; moxa_pci_info pciInfo; int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002 int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 09-04-2002 int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 01-05-2004};struct mxser_struct { int port; int base; /* port base address */ int irq; /* port using irq no. */ int vector; /* port irq vector */ int vectormask; /* port vector mask */ int rx_high_water; int rx_trigger; /* Rx fifo trigger level */ int rx_low_water; int baud_base; /* max. speed */ int flags; /* defined in tty.h */ int type; /* UART type */ struct tty_struct * tty; int read_status_mask; int ignore_status_mask; int xmit_fifo_size; int custom_divisor; int x_char; /* xon/xoff character */ int close_delay; unsigned short closing_wait; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ unsigned long event; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt;#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) struct tq_struct tqueue;#else struct work_struct tqueue;#endif struct termios normal_termios; struct termios callout_termios;#if (LINUX_VERSION_CODE < VERSION_CODE(2,4,0)) struct wait_queue *open_wait; struct wait_queue *close_wait; struct wait_queue *delta_msr_wait;#else wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait;#endif struct async_icount icount; /* kernel counters for the 4 input interrupts */ int timeout; int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002 int MaxCanSetBaudRate; // add by Victor Yu. 09-04-2002 int opmode_ioaddr; // add by Victor Yu. 01-05-2004 unsigned char stop_rx; unsigned char ldisc_stop_rx; long realbaud; struct mxser_mon mon_data; unsigned char err_shadow; spinlock_t slock;};struct mxser_mstatus{ tcflag_t cflag; int cts; int dsr; int ri; int dcd;};static struct mxser_mstatus GMStatus[MXSER_PORTS];static int mxserBoardCAP[MXSER_BOARDS] = { 0,0,0,0 /* 0x180, 0x280, 0x200, 0x320 */};#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0))static struct tty_driver mxvar_sdriver;static struct tty_driver mxvar_cdriver;#elsestatic struct tty_driver *mxvar_sdriver;#endif#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0))static int mxvar_refcount;#endifstatic struct mxser_struct mxvar_table[MXSER_PORTS];static struct tty_struct * mxvar_tty[MXSER_PORTS+1];static struct termios * mxvar_termios[MXSER_PORTS+1];static struct termios * mxvar_termios_locked[MXSER_PORTS+1];static struct mxser_log mxvar_log;static int mxvar_diagflag;static unsigned char mxser_msr[MXSER_PORTS+1];static struct mxser_mon_ext mon_data_ext;static int mxser_set_baud_method[MXSER_PORTS+1];static spinlock_t gm_lock;//static int moxaTimer_on;//static struct timer_list moxaTimer;/* * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need * to lock it in case the memcpy_fromfs blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ports, since it significantly saves * memory if large numbers of serial ports are open. */#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0))static unsigned char * mxvar_tmp_buf;static struct semaphore mxvar_tmp_buf_sem;#elsestatic unsigned char * mxvar_tmp_buf = 0;static struct semaphore mxvar_tmp_buf_sem = MUTEX;#endif/* * This is used to figure out the divisor speeds and the timeouts */struct mxser_hwconf mxsercfg[MXSER_BOARDS];/* * static functions: */#ifdef MODULEint init_module(void);void cleanup_module(void);#endifstatic void mxser_getcfg(int board,struct mxser_hwconf *hwconf);int mxser_init(void);//static void mxser_poll(unsigned long);static int mxser_get_ISA_conf(int, struct mxser_hwconf *);#ifdef CONFIG_PCIstatic int mxser_get_PCI_conf(int ,int ,int ,struct mxser_hwconf *);#endifstatic void mxser_do_softint(void *);static int mxser_open(struct tty_struct *, struct file *);static void mxser_close(struct tty_struct *, struct file *);static int mxser_write(struct tty_struct *, int, const unsigned char *, int);static int mxser_write_room(struct tty_struct *);static void mxser_flush_buffer(struct tty_struct *);static int mxser_chars_in_buffer(struct tty_struct *);static void mxser_flush_chars(struct tty_struct *);static void mxser_put_char(struct tty_struct *, unsigned char);static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);static int mxser_ioctl_special(unsigned int, unsigned long);static void mxser_throttle(struct tty_struct *);static void mxser_unthrottle(struct tty_struct *);static void mxser_set_termios(struct tty_struct *, struct termios *);static void mxser_stop(struct tty_struct *);static void mxser_start(struct tty_struct *);static void mxser_hangup(struct tty_struct *);static void mxser_rs_break(struct tty_struct *, int);static IRQ_RET mxser_interrupt(int, void *, struct pt_regs *);static inline void mxser_receive_chars(struct mxser_struct *, int *);static inline void mxser_transmit_chars(struct mxser_struct *);static inline void mxser_check_modem_status(struct mxser_struct *, int);static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);static int mxser_startup(struct mxser_struct *);static void mxser_shutdown(struct mxser_struct *);static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *);static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);static void mxser_send_break(struct mxser_struct *, int);#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0))static int mxser_tiocmget(struct tty_struct *, struct file *);static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);#elsestatic int mxser_get_modem_info(struct mxser_struct *, unsigned int *);static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *);#endifstatic int mxser_set_baud(struct mxser_struct *info, long newspd);#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))static void mxser_wait_until_sent(struct tty_struct *tty, int timeout);#endifstatic void mxser_startrx(struct tty_struct * tty);static void mxser_stoprx(struct tty_struct * tty);static int CheckIsMoxaMust(int io){ UCHAR oldmcr, hwid; int i; 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(MOXA_OTHER_UART); } GET_MOXA_MUST_HARDWARE_ID(io, &hwid); for(i=0; i<UART_TYPE_NUM; i++){ if(hwid == Gmoxa_uart_id[i]) return (int)hwid; } return MOXA_OTHER_UART;}// above is modified by Victor Yu. 08-15-2002#if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0))static struct tty_operations mxser_ops = { .open = mxser_open, .close = mxser_close, .write = mxser_write, .put_char = mxser_put_char, .flush_chars = mxser_flush_chars, .write_room = mxser_write_room, .chars_in_buffer = mxser_chars_in_buffer, .flush_buffer = mxser_flush_buffer, .ioctl = mxser_ioctl, .throttle = mxser_throttle, .unthrottle = mxser_unthrottle, .set_termios = mxser_set_termios, .stop = mxser_stop, .start = mxser_start, .hangup = mxser_hangup, .tiocmget = mxser_tiocmget, .tiocmset = mxser_tiocmset,};#endif/* * The MOXA Smartio/Industio serial driver boot-time initialization code! */#ifdef MODULEINIT_FUNC_RET INIT_FUNC(void){ int ret; if (verbose) printk("Loading module mxser ...\n"); ret = mxser_init(); if (verbose) printk("Done.\n"); return (ret);}CLEAR_FUNC_RET CLEAR_FUNC(void){ int i,err = 0; if (verbose) printk("Unloading module mxser ...\n");#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) if ((err |= tty_unregister_driver(&mxvar_cdriver))) printk("Couldn't unregister MOXA Smartio/Industio family callout driver\n");#endif if ((err |= tty_unregister_driver(DRV_VAR))) printk("Couldn't unregister MOXA Smartio/Industio family serial driver\n"); for(i=0; i<MXSER_BOARDS; i++){ struct pci_dev *pdev; if(mxsercfg[i].board_type == -1) continue; else{ pdev = mxsercfg[i].pciInfo.pdev; free_irq(mxsercfg[i].irq, &mxvar_table[i*MXSER_PORTS_PER_BOARD]); if(pdev!=NULL){ //PCI release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); }else{ release_region(mxsercfg[i].ioaddr[0], 8*mxsercfg[i].ports); release_region(mxsercfg[i].vector, 1); } } } if (verbose) printk("Done.\n");}#endifstatic void process_txrx_fifo(struct mxser_struct *info){ int i; if ( (info->type == PORT_16450) || (info->type == PORT_8250) ){ info->rx_trigger = 1; info->rx_high_water = 1; info->rx_low_water = 1; info->xmit_fifo_size = 1; }else{ for(i=0; i<UART_INFO_NUM; i++){ if(info->IsMoxaMustChipFlag == Gpci_uart_info[i].type){ info->rx_trigger = Gpci_uart_info[i].rx_trigger; info->rx_low_water = Gpci_uart_info[i].rx_low_water; info->rx_high_water = Gpci_uart_info[i].rx_high_water; info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size; break; } } }}int mxser_initbrd(int board,struct mxser_hwconf *hwconf){ struct mxser_struct * info; unsigned long flags; int retval; int i,n;#if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)) init_MUTEX(&mxvar_tmp_buf_sem);#endif n = board*MXSER_PORTS_PER_BOARD; info = &mxvar_table[n]; /*if (verbose)*/ {#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) printk(" ttyM%d/cum%d - ttyM%d/cum%d ", n, n, n+hwconf->ports-1, n+hwconf->ports-1);#else printk(" ttyM%d - ttyM%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->opmode_ioaddr = hwconf->opmode_ioaddr[i]; // add by Victor Yu. 01-05-2004 info->stop_rx = 0; info->ldisc_stop_rx = 0; info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag; //Enhance mode enabled here if(info->IsMoxaMustChipFlag!=MOXA_OTHER_UART){ ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base); } info->flags = ASYNC_SHARE_IRQ; info->type = hwconf->uart_type; info->baud_base = hwconf->baud_base[i]; info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i]; process_txrx_fifo(info); info->custom_divisor = hwconf->baud_base[i] * 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; INIT_WORK(&info->tqueue, mxser_do_softint, info);#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 memset(&info->mon_data, 0, sizeof(struct mxser_mon)); info->err_shadow = 0; spin_lock_init(&info->slock); } /* * 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*MXSER_PORTS_PER_BOARD; info = &mxvar_table[n]; MX_LOCK(&info->slock); retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), "mxser", info); if ( retval ) { MX_UNLOCK(&info->slock); printk("Board %d: %s", board, mxser_brdname[hwconf->board_type-1]); printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n",info->irq); return(retval); } MX_UNLOCK(&info->slock); return 0;}static void mxser_getcfg(int board,struct mxser_hwconf *hwconf){ mxsercfg[board] = *hwconf;}#ifdef CONFIG_PCIstatic int mxser_get_PCI_conf(int busnum,int devnum,int board_type,struct mxser_hwconf *hwconf){ int i, j;// unsigned int val; unsigned int ioaddress; struct pci_dev *pdev=hwconf->pciInfo.pdev; //io address hwconf->board_type = board_type; hwconf->ports = mxser_numports[board_type-1]; ioaddress = pci_resource_start(pdev, 2); request_region(pci_resource_start(pdev, 2),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -