epca.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,180 行 · 第 1/5 页
C
2,180 行
printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n"); if (setup_error_code & INVALID_MEM_BASE) printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n"); if (setup_error_code & INVALID_PORT_BASE) printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n"); if (setup_error_code & INVALID_BOARD_STATUS) printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n"); if (setup_error_code & INVALID_ALTPIN) printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n"); tty->driver_data = NULL; /* Mark this device as 'down' */ return(-ENODEV); } if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) { tty->driver_data = NULL; /* Mark this device as 'down' */ return(-ENODEV); } if (( bc = ch->brdchan) == 0) { tty->driver_data = NULL; return(-ENODEV); } /* ------------------------------------------------------------------ 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. -------------------------------------------------------------------- */ save_flags(flags); cli(); globalwinon(ch); ch->statusflags = 0; /* Save boards current modem status */ ch->imodem = bc->mstat; /* ---------------------------------------------------------------- Set receive head and tail ptrs to each other. This indicates no data available to read. ----------------------------------------------------------------- */ head = bc->rin; bc->rout = head; /* 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); restore_flags(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... --------------------------------------------------------------- */ ch->tty = tty; save_flags(flags); cli(); globalwinon(ch); /* Enable Digi Data events */ bc->idata = 1; memoff(ch); restore_flags(flags); return 0;} /* End pc_open */#ifdef MODULEstatic int __init epca_module_init(void){ /* Begin init_module */ unsigned long flags; save_flags(flags); cli(); pc_init(); restore_flags(flags); return(0);}module_init(epca_module_init);#endif#ifdef ENABLE_PCIstatic struct pci_driver epca_driver;#endif#ifdef MODULE/* -------------------- Begin cleanup_module ---------------------- */static void __exit epca_module_exit(void){ int count, crd; struct board_info *bd; struct channel *ch; unsigned long flags; del_timer_sync(&epca_timer); save_flags(flags); cli(); if ((tty_unregister_driver(pc_driver)) || (tty_unregister_driver(pc_info))) { printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n"); restore_flags(flags); return; } put_tty_driver(pc_driver); put_tty_driver(pc_info); for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ bd = &boards[crd]; if (!bd) { /* Begin sanity check */ printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n"); return; } /* End sanity check */ ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { /* Begin for each port */ if (ch) { if (ch->tty) tty_hangup(ch->tty); kfree(ch->tmp_buf); } } /* End for each port */ } /* End for each card */#ifdef ENABLE_PCI pci_unregister_driver (&epca_driver);#endif restore_flags(flags);}module_exit(epca_module_exit);#endif /* MODULE */static 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,};/* ------------------ Begin pc_init ---------------------- */int __init pc_init(void){ /* Begin pc_init */ /* ---------------------------------------------------------------- pc_init is called by the operating system during boot up prior to any open calls being made. In the older versions of Linux (Prior to 2.0.0) an entry is made into tty_io.c. A pointer to the last memory location (from kernel space) used (kmem_start) is passed to pc_init. It is pc_inits responsibility to modify this value for any memory that the Digi driver might need and then return this value to the operating system. For example if the driver wishes to allocate 1K of kernel memory, pc_init would return (kmem_start + 1024). This memory (Between kmem_start and kmem_start + 1024) would then be available for use exclusively by the driver. In this case our driver does not allocate any of this kernel memory. ------------------------------------------------------------------*/ ulong flags; int crd; struct board_info *bd; unsigned char board_id = 0;#ifdef ENABLE_PCI int pci_boards_found, pci_count; pci_count = 0;#endif /* ENABLE_PCI */ pc_driver = alloc_tty_driver(MAX_ALLOC); if (!pc_driver) return -ENOMEM; pc_info = alloc_tty_driver(MAX_ALLOC); if (!pc_info) { put_tty_driver(pc_driver); return -ENOMEM; } /* ----------------------------------------------------------------------- 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) { /* Begin driver has been configured via. epcaconfig */ nbdevs = NBDEVS; num_cards = NUMCARDS; memcpy((void *)&boards, (void *)&static_boards, (sizeof(struct board_info) * NUMCARDS)); } /* End driver has been configured via. epcaconfig */ /* ----------------------------------------------------------------- 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);#ifdef ENABLE_PCI /* ------------------------------------------------------------------ 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 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;#endif /* ENABLE_PCI */ pc_driver->owner = THIS_MODULE; pc_driver->name = "ttyD"; pc_driver->devfs_name = "tts/D"; 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->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->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(pc_info, &info_ops); save_flags(flags); cli(); for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ /* ------------------------------------------------------------------ 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) { /* Begin switch on bd->type {board 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; } /* End switch on bd->type */ /* --------------------------------------------------------------- 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) { /* Begin switch on bd->type {board type} */ case PCXE: case PCXEVE:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?