epca.c
来自「linux 内核源代码」· C语言 代码 · 共 2,328 行 · 第 1/5 页
C
2,328 行
* Every time a channel is opened, increment a counter. This is * necessary because we do not wish to flush and shutdown the channel * until the last app holding the channel open, closes it. */ ch->count++; /* * Set a kernel structures pointer to our local channel structure. This * way we can get to it when passed only a tty struct. */ tty->driver_data = ch; /* * If this is the first time the channel has been opened, initialize * the tty->termios struct otherwise let pc_close handle it. */ globalwinon(ch); ch->statusflags = 0; /* Save boards current modem status */ ch->imodem = readb(&bc->mstat); /* * Set receive head and tail ptrs to each other. This indicates no data * available to read. */ head = readw(&bc->rin); writew(head, &bc->rout); /* Set the channels associated tty structure */ ch->tty = tty; /* * The below routine generally sets up parity, baud, flow control * issues, etc.... It effect both control flags and input flags. */ epcaparam(tty,ch); ch->asyncflags |= ASYNC_INITIALIZED; memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); retval = block_til_ready(tty, filp, ch); if (retval) return retval; /* * Set this again in case a hangup set it to zero while this open() was * waiting for the line... */ spin_lock_irqsave(&epca_lock, flags); ch->tty = tty; globalwinon(ch); /* Enable Digi Data events */ writeb(1, &bc->idata); memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); return 0;}static int __init epca_module_init(void){ return pc_init();}module_init(epca_module_init);static struct pci_driver epca_driver;static void __exit epca_module_exit(void){ int count, crd; struct board_info *bd; struct channel *ch; del_timer_sync(&epca_timer); if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info)) { printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n"); return; } put_tty_driver(pc_driver); put_tty_driver(pc_info); for (crd = 0; crd < num_cards; crd++) { bd = &boards[crd]; if (!bd) { /* sanity check */ printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n"); return; } ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { if (ch && ch->tty) tty_hangup(ch->tty); } } pci_unregister_driver(&epca_driver);}module_exit(epca_module_exit);static const struct tty_operations pc_ops = { .open = pc_open, .close = pc_close, .write = pc_write, .write_room = pc_write_room, .flush_buffer = pc_flush_buffer, .chars_in_buffer = pc_chars_in_buffer, .flush_chars = pc_flush_chars, .put_char = pc_put_char, .ioctl = pc_ioctl, .set_termios = pc_set_termios, .stop = pc_stop, .start = pc_start, .throttle = pc_throttle, .unthrottle = pc_unthrottle, .hangup = pc_hangup,};static int info_open(struct tty_struct *tty, struct file * filp){ return 0;}static struct tty_operations info_ops = { .open = info_open, .ioctl = info_ioctl,};static int __init pc_init(void){ int crd; struct board_info *bd; unsigned char board_id = 0; int err = -ENOMEM; int pci_boards_found, pci_count; pci_count = 0; pc_driver = alloc_tty_driver(MAX_ALLOC); if (!pc_driver) goto out1; pc_info = alloc_tty_driver(MAX_ALLOC); if (!pc_info) goto out2; /* * If epca_setup has not been ran by LILO set num_cards to defaults; * copy board structure defined by digiConfig into drivers board * structure. Note : If LILO has ran epca_setup then epca_setup will * handle defining num_cards as well as copying the data into the board * structure. */ if (!liloconfig) { /* driver has been configured via. epcaconfig */ nbdevs = NBDEVS; num_cards = NUMCARDS; memcpy(&boards, &static_boards, sizeof(struct board_info) * NUMCARDS); } /* * Note : If lilo was used to configure the driver and the ignore * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards * will equal 0 at this point. This is okay; PCI cards will still be * picked up if detected. */ /* * Set up interrupt, we will worry about memory allocation in * post_fep_init. */ printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION); /* * NOTE : This code assumes that the number of ports found in the * boards array is correct. This could be wrong if the card in question * is PCI (And therefore has no ports entry in the boards structure.) * The rest of the information will be valid for PCI because the * beginning of pc_init scans for PCI and determines i/o and base * memory addresses. I am not sure if it is possible to read the number * of ports supported by the card prior to it being booted (Since that * is the state it is in when pc_init is run). Because it is not * possible to query the number of supported ports until after the card * has booted; we are required to calculate the card_ptrs as the card * is initialized (Inside post_fep_init). The negative thing about this * approach is that digiDload's call to GET_INFO will have a bad port * value. (Since this is called prior to post_fep_init.) */ pci_boards_found = 0; if (num_cards < MAXBOARDS) pci_boards_found += init_PCI(); num_cards += pci_boards_found; pc_driver->owner = THIS_MODULE; pc_driver->name = "ttyD"; pc_driver->major = DIGI_MAJOR; pc_driver->minor_start = 0; pc_driver->type = TTY_DRIVER_TYPE_SERIAL; pc_driver->subtype = SERIAL_TYPE_NORMAL; pc_driver->init_termios = tty_std_termios; pc_driver->init_termios.c_iflag = 0; pc_driver->init_termios.c_oflag = 0; pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; pc_driver->init_termios.c_lflag = 0; pc_driver->init_termios.c_ispeed = 9600; pc_driver->init_termios.c_ospeed = 9600; pc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(pc_driver, &pc_ops); pc_info->owner = THIS_MODULE; pc_info->name = "digi_ctl"; pc_info->major = DIGIINFOMAJOR; pc_info->minor_start = 0; pc_info->type = TTY_DRIVER_TYPE_SERIAL; pc_info->subtype = SERIAL_TYPE_INFO; pc_info->init_termios = tty_std_termios; pc_info->init_termios.c_iflag = 0; pc_info->init_termios.c_oflag = 0; pc_info->init_termios.c_lflag = 0; pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; pc_info->init_termios.c_ispeed = 9600; pc_info->init_termios.c_ospeed = 9600; pc_info->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(pc_info, &info_ops); for (crd = 0; crd < num_cards; crd++) { /* * This is where the appropriate memory handlers for the * hardware is set. Everything at runtime blindly jumps through * these vectors. */ /* defined in epcaconfig.h */ bd = &boards[crd]; switch (bd->type) { case PCXEM: case EISAXEM: bd->memwinon = pcxem_memwinon; bd->memwinoff = pcxem_memwinoff; bd->globalwinon = pcxem_globalwinon; bd->txwinon = pcxem_txwinon; bd->rxwinon = pcxem_rxwinon; bd->memoff = pcxem_memoff; bd->assertgwinon = dummy_assertgwinon; bd->assertmemoff = dummy_assertmemoff; break; case PCIXEM: case PCIXRJ: case PCIXR: bd->memwinon = dummy_memwinon; bd->memwinoff = dummy_memwinoff; bd->globalwinon = dummy_globalwinon; bd->txwinon = dummy_txwinon; bd->rxwinon = dummy_rxwinon; bd->memoff = dummy_memoff; bd->assertgwinon = dummy_assertgwinon; bd->assertmemoff = dummy_assertmemoff; break; case PCXE: case PCXEVE: bd->memwinon = pcxe_memwinon; bd->memwinoff = pcxe_memwinoff; bd->globalwinon = pcxe_globalwinon; bd->txwinon = pcxe_txwinon; bd->rxwinon = pcxe_rxwinon; bd->memoff = pcxe_memoff; bd->assertgwinon = dummy_assertgwinon; bd->assertmemoff = dummy_assertmemoff; break; case PCXI: case PC64XE: bd->memwinon = pcxi_memwinon; bd->memwinoff = pcxi_memwinoff; bd->globalwinon = pcxi_globalwinon; bd->txwinon = pcxi_txwinon; bd->rxwinon = pcxi_rxwinon; bd->memoff = pcxi_memoff; bd->assertgwinon = pcxi_assertgwinon; bd->assertmemoff = pcxi_assertmemoff; break; default: break; } /* * Some cards need a memory segment to be defined for use in * transmit and receive windowing operations. These boards are * listed in the below switch. In the case of the XI the amount * of memory on the board is variable so the memory_seg is also * variable. This code determines what they segment should be. */ switch (bd->type) { case PCXE: case PCXEVE: case PC64XE: bd->memory_seg = 0xf000; break; case PCXI: board_id = inb((int)bd->port); if ((board_id & 0x1) == 0x1) { /* it's an XI card */ /* Is it a 64K board */ if ((board_id & 0x30) == 0) bd->memory_seg = 0xf000; /* Is it a 128K board */ if ((board_id & 0x30) == 0x10) bd->memory_seg = 0xe000; /* Is is a 256K board */ if ((board_id & 0x30) == 0x20) bd->memory_seg = 0xc000; /* Is it a 512K board */ if ((board_id & 0x30) == 0x30) bd->memory_seg = 0x8000; } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); break; } } err = tty_register_driver(pc_driver); if (err) { printk(KERN_ERR "Couldn't register Digi PC/ driver"); goto out3; } err = tty_register_driver(pc_info); if (err) { printk(KERN_ERR "Couldn't register Digi PC/ info "); goto out4; } /* Start up the poller to check for events on all enabled boards */ init_timer(&epca_timer); epca_timer.function = epcapoll; mod_timer(&epca_timer, jiffies + HZ/25); return 0;out4: tty_unregister_driver(pc_driver);out3: put_tty_driver(pc_info);out2: put_tty_driver(pc_driver);out1: return err;}static void post_fep_init(unsigned int crd){ int i; void __iomem *memaddr; struct global_data __iomem *gd; struct board_info *bd; struct board_chan __iomem *bc; struct channel *ch; int shrinkmem = 0, lowwater; /* * This call is made by the user via. the ioctl call DIGI_INIT. It is * responsible for setting up all the card specific stuff. */ bd = &boards[crd]; /* * If this is a PCI board, get the port info. Remember PCI cards do not * have entries into the epcaconfig.h file, so we can't get the number * of ports from it. Unfortunetly, this means that anyone doing a * DIGI_GETINFO before the board has booted will get an invalid number * of ports returned (It should return 0). Calls to DIGI_GETINFO after * DIGI_INIT has been called will return the proper values. */ if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */ /* * Below we use XEMPORTS as a memory offset regardless of which * PCI card it is. This is because all of the supported PCI * cards have the same memory offset for the channel data. This * will have to be changed if we ever develop a PCI/XE card. * NOTE : The FEP manual states that the port offset is 0xC22 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI * cards; not for the XEM, or CX series. On the PCI cards the * number of ports is determined by reading a ID PROM located * in the box attached to the card. The card can then determine * the index the id to determine the number of ports available. * (FYI - The id should be located at 0x1ac (And may use up to * 4 bytes if the box in question is a XEM or CX)). */ /* PCI cards are already remapped at this point ISA are not */ bd->numports = readw(bd->re_map_membase + XEMPORTS); epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); nbdevs += (bd->numports); } else { /* Fix up the mappings for ISA/EISA etc */ /* FIXME: 64K - can we be smarter ? */ bd->re_map_membase = ioremap(bd->membase, 0x10000); } if (crd != 0) card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports; else card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */ ch = card_ptr[crd]; epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range"); memaddr = bd->re_map_membase; /* * The below assignment will set bc to point at the BEGINING of the * cards channel structures. For 1 card there will be between 8 and 64 * of these structures. */ bc = memaddr + CHANSTRUCT; /* * The below assignment will set gd to point at the BEGINING of global * memory address 0xc00. The first data in that global memory actually * starts at address 0xc1a. The command in pointer begins at 0xd10. */ gd = memaddr + GLOBAL; /* * XEPORTS (address 0xc22) points at the number of channels the card * supports. (For 64XE, XI, XEM, and XR use 0xc02) */ if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3)) shrinkmem = 1; if (bd->type < PCIXEM) if (!request_region((int)bd->port, 4, board_desc[bd->type])) return; memwinon(bd, 0); /* * Remember ch is the main drivers channels structure, while bc is the * cards channel structure. */ for (i = 0; i < bd->numports; i++, ch++, bc++) { unsigned long flags; u16 tseg, rseg; ch->brdchan = bc; ch->mailbox = gd; INIT_WORK(&ch->tqueue, do_softint); ch->board = &boards[crd]; spin_lock_irqsave(&epca_lock, flags); switch (bd->type) { /* * Since some of the boards use different bitmaps for * their control signals we cannot hard code these * values and retain portability. We virtualize this * data here. */ case EISAXEM: case PCXEM: case PCIXEM: case PCIXRJ: case PCIXR: ch->m_rts = 0x02;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?