📄 moxa.c
字号:
/*****************************************************************************//* * moxa.c -- MOXA Intellio family multiport serial driver. * * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw). * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * MOXA Intellio Series Driver * for : LINUX * date : 1999/1/7 * version : 5.1 */#include <linux/module.h>#include <linux/types.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/serial.h>#include <linux/tty_driver.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/bitops.h>#include <linux/completion.h>#include <asm/system.h>#include <asm/io.h>#include <asm/uaccess.h>#define MOXA_VERSION "5.1k"#define MOXAMAJOR 172#define MOXACUMAJOR 173#define MAX_BOARDS 4 /* Don't change this value */#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)/* * Define the Moxa PCI vendor and device IDs. */#define MOXA_BUS_TYPE_ISA 0#define MOXA_BUS_TYPE_PCI 1enum { MOXA_BOARD_C218_PCI = 1, MOXA_BOARD_C218_ISA, MOXA_BOARD_C320_PCI, MOXA_BOARD_C320_ISA, MOXA_BOARD_CP204J,};static char *moxa_brdname[] ={ "C218 Turbo PCI series", "C218 Turbo ISA series", "C320 Turbo PCI series", "C320 Turbo ISA series", "CP-204J series",};#ifdef CONFIG_PCIstatic struct pci_device_id moxa_pcibrds[] = { { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), .driver_data = MOXA_BOARD_C218_PCI }, { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), .driver_data = MOXA_BOARD_C320_PCI }, { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J), .driver_data = MOXA_BOARD_CP204J }, { 0 }};MODULE_DEVICE_TABLE(pci, moxa_pcibrds);#endif /* CONFIG_PCI */struct moxa_isa_board_conf { int boardType; int numPorts; unsigned long baseAddr;};static struct moxa_isa_board_conf moxa_isa_boards[] ={/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */};static struct moxa_board_conf { int boardType; int numPorts; unsigned long baseAddr; int busType; int loadstat; void __iomem *basemem; void __iomem *intNdx; void __iomem *intPend; void __iomem *intTable;} moxa_boards[MAX_BOARDS];struct mxser_mstatus { tcflag_t cflag; int cts; int dsr; int ri; int dcd;};struct moxaq_str { int inq; int outq;};struct moxa_port { int type; int port; int close_delay; unsigned short closing_wait; int count; int blocked_open; long event; /* long req'd for set_bit --RR */ int asyncflags; unsigned long statusflags; struct tty_struct *tty; int cflag; wait_queue_head_t open_wait; struct completion close_wait; struct timer_list emptyTimer; char chkPort; char lineCtrl; void __iomem *tableAddr; long curBaud; char DCDState; char lowChkFlag; ushort breakCnt;};/* statusflags */#define TXSTOPPED 0x1#define LOWWAIT 0x2#define EMPTYWAIT 0x4#define THROTTLE 0x8#define SERIAL_DO_RESTART#define WAKEUP_CHARS 256static int ttymajor = MOXAMAJOR;/* Variables for insmod */#ifdef MODULEstatic int baseaddr[4];static int type[4];static int numports[4];#endifMODULE_AUTHOR("William Chen");MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");MODULE_LICENSE("GPL");#ifdef MODULEmodule_param_array(type, int, NULL, 0);module_param_array(baseaddr, int, NULL, 0);module_param_array(numports, int, NULL, 0);#endifmodule_param(ttymajor, int, 0);/* * static functions: */static int moxa_open(struct tty_struct *, struct file *);static void moxa_close(struct tty_struct *, struct file *);static int moxa_write(struct tty_struct *, const unsigned char *, int);static int moxa_write_room(struct tty_struct *);static void moxa_flush_buffer(struct tty_struct *);static int moxa_chars_in_buffer(struct tty_struct *);static void moxa_flush_chars(struct tty_struct *);static void moxa_put_char(struct tty_struct *, unsigned char);static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);static void moxa_throttle(struct tty_struct *);static void moxa_unthrottle(struct tty_struct *);static void moxa_set_termios(struct tty_struct *, struct ktermios *);static void moxa_stop(struct tty_struct *);static void moxa_start(struct tty_struct *);static void moxa_hangup(struct tty_struct *);static int moxa_tiocmget(struct tty_struct *tty, struct file *file);static int moxa_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);static void moxa_poll(unsigned long);static void moxa_set_tty_param(struct tty_struct *);static int moxa_block_till_ready(struct tty_struct *, struct file *, struct moxa_port *);static void moxa_setup_empty_event(struct tty_struct *);static void moxa_check_xmit_empty(unsigned long);static void moxa_shut_down(struct moxa_port *);static void moxa_receive_data(struct moxa_port *);/* * moxa board interface functions: */static void MoxaDriverInit(void);static int MoxaDriverIoctl(unsigned int, unsigned long, int);static int MoxaDriverPoll(void);static int MoxaPortsOfCard(int);static int MoxaPortIsValid(int);static void MoxaPortEnable(int);static void MoxaPortDisable(int);static long MoxaPortGetMaxBaud(int);static long MoxaPortSetBaud(int, long);static int MoxaPortSetTermio(int, struct ktermios *, speed_t);static int MoxaPortGetLineOut(int, int *, int *);static void MoxaPortLineCtrl(int, int, int);static void MoxaPortFlowCtrl(int, int, int, int, int, int);static int MoxaPortLineStatus(int);static int MoxaPortDCDChange(int);static int MoxaPortDCDON(int);static void MoxaPortFlushData(int, int);static int MoxaPortWriteData(int, unsigned char *, int);static int MoxaPortReadData(int, struct tty_struct *tty);static int MoxaPortTxQueue(int);static int MoxaPortRxQueue(int);static int MoxaPortTxFree(int);static void MoxaPortTxDisable(int);static void MoxaPortTxEnable(int);static int MoxaPortResetBrkCnt(int);static void MoxaPortSendBreak(int, int);static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);static void MoxaSetFifo(int port, int enable);static const struct tty_operations moxa_ops = { .open = moxa_open, .close = moxa_close, .write = moxa_write, .write_room = moxa_write_room, .flush_buffer = moxa_flush_buffer, .chars_in_buffer = moxa_chars_in_buffer, .flush_chars = moxa_flush_chars, .put_char = moxa_put_char, .ioctl = moxa_ioctl, .throttle = moxa_throttle, .unthrottle = moxa_unthrottle, .set_termios = moxa_set_termios, .stop = moxa_stop, .start = moxa_start, .hangup = moxa_hangup, .tiocmget = moxa_tiocmget, .tiocmset = moxa_tiocmset,};static struct tty_driver *moxaDriver;static struct moxa_port moxa_ports[MAX_PORTS];static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);static DEFINE_SPINLOCK(moxa_lock);#ifdef CONFIG_PCIstatic int __devinit moxa_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct moxa_board_conf *board; unsigned int i; int board_type = ent->driver_data; int retval; retval = pci_enable_device(pdev); if (retval) { dev_err(&pdev->dev, "can't enable pci device\n"); goto err; } for (i = 0; i < MAX_BOARDS; i++) if (moxa_boards[i].basemem == NULL) break; retval = -ENODEV; if (i >= MAX_BOARDS) { dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards " "found. Board is ignored.\n", MAX_BOARDS); goto err; } board = &moxa_boards[i]; board->basemem = pci_iomap(pdev, 2, 0x4000); if (board->basemem == NULL) { dev_err(&pdev->dev, "can't remap io space 2\n"); goto err; } 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; pci_set_drvdata(pdev, board); return (0);err: return retval;}static void __devexit moxa_pci_remove(struct pci_dev *pdev){ struct moxa_board_conf *brd = pci_get_drvdata(pdev); pci_iounmap(pdev, brd->basemem); brd->basemem = NULL;}static struct pci_driver moxa_pci_driver = { .name = "moxa", .id_table = moxa_pcibrds, .probe = moxa_pci_probe, .remove = __devexit_p(moxa_pci_remove)};#endif /* CONFIG_PCI */static int __init moxa_init(void){ int i, numBoards, retval = 0; struct moxa_port *ch; printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); moxaDriver = alloc_tty_driver(MAX_PORTS + 1); if (!moxaDriver) return -ENOMEM; moxaDriver->owner = THIS_MODULE; moxaDriver->name = "ttyMX"; moxaDriver->major = ttymajor; moxaDriver->minor_start = 0; moxaDriver->type = TTY_DRIVER_TYPE_SERIAL; moxaDriver->subtype = SERIAL_TYPE_NORMAL; moxaDriver->init_termios = tty_std_termios; moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; moxaDriver->init_termios.c_ispeed = 9600; moxaDriver->init_termios.c_ospeed = 9600; moxaDriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(moxaDriver, &moxa_ops); for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) { ch->type = PORT_16550A; ch->port = i; ch->close_delay = 5 * HZ / 10; ch->closing_wait = 30 * HZ; ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; init_waitqueue_head(&ch->open_wait); init_completion(&ch->close_wait); setup_timer(&ch->emptyTimer, moxa_check_xmit_empty, (unsigned long)ch); } pr_debug("Moxa tty devices major number = %d\n", ttymajor); if (tty_register_driver(moxaDriver)) { printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n"); put_tty_driver(moxaDriver); return -1; } mod_timer(&moxaTimer, jiffies + HZ / 50); /* Find the boards defined in source code */ numBoards = 0; for (i = 0; i < MAX_BOARDS; i++) { if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) || (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) { moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType; if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) moxa_boards[numBoards].numPorts = 8; else moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts; moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr; pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", numBoards + 1, moxa_brdname[moxa_boards[numBoards].boardType-1], moxa_boards[numBoards].baseAddr); numBoards++; } } /* Find the boards defined form module args. */#ifdef MODULE for (i = 0; i < MAX_BOARDS; i++) { if ((type[i] == MOXA_BOARD_C218_ISA) || (type[i] == MOXA_BOARD_C320_ISA)) { pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", numBoards + 1, moxa_brdname[type[i] - 1], (unsigned long)baseaddr[i]); if (numBoards >= MAX_BOARDS) { printk(KERN_WARNING "More than %d MOXA " "Intellio family boards found. Board " "is ignored.\n", 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#ifdef CONFIG_PCI retval = pci_register_driver(&moxa_pci_driver); if (retval) { printk(KERN_ERR "Can't register moxa pci driver!\n"); if (numBoards) retval = 0; }#endif for (i = 0; i < numBoards; i++) { moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr, 0x4000); } return retval;}static void __exit moxa_exit(void){ int i; del_timer_sync(&moxaTimer); for (i = 0; i < MAX_PORTS; i++) del_timer_sync(&moxa_ports[i].emptyTimer); if (tty_unregister_driver(moxaDriver)) printk(KERN_ERR "Couldn't unregister MOXA Intellio family " "serial driver\n"); put_tty_driver(moxaDriver);#ifdef CONFIG_PCI pci_unregister_driver(&moxa_pci_driver);#endif for (i = 0; i < MAX_BOARDS; i++) if (moxa_boards[i].basemem) iounmap(moxa_boards[i].basemem);}module_init(moxa_init);module_exit(moxa_exit);static int moxa_open(struct tty_struct *tty, struct file *filp){ struct moxa_port *ch; int port; int retval; port = tty->index; if (port == MAX_PORTS) { return (0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -