📄 epca.c
字号:
/* We dec count so that pc_close will know when to free things */ if (!tty_hung_up_p(filp)) ch->count--; restore_flags(flags); ch->blocked_open++; while(1) { /* Begin forever while */ set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(ch->asyncflags & ASYNC_INITIALIZED)) { if (ch->asyncflags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } if (!(ch->asyncflags & ASYNC_CLOSING) && !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && (do_clocal || (ch->imodem & ch->dcd))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } /* --------------------------------------------------------------- Allow someone else to be scheduled. We will occasionally go through this loop until one of the above conditions change. The below schedule call will allow other processes to enter and prevent this loop from hogging the cpu. ------------------------------------------------------------------ */ schedule(); } /* End forever while */ current->state = TASK_RUNNING; remove_wait_queue(&ch->open_wait, &wait); cli(); if (!tty_hung_up_p(filp)) ch->count++; restore_flags(flags); ch->blocked_open--; if (retval) return retval; ch->asyncflags |= ASYNC_NORMAL_ACTIVE; return 0;} /* End block_til_ready */ /* ------------------ Begin pc_open ---------------------- */static int pc_open(struct tty_struct *tty, struct file * filp){ /* Begin pc_open */ struct channel *ch; unsigned long flags; int line, retval, boardnum; volatile struct board_chan *bc; volatile unsigned int head; /* Nothing "real" happens in open of control device */ if (tty->driver.subtype == SERIAL_TYPE_INFO) { return (0) ; } line = MINOR(tty->device) - tty->driver.minor_start; if (line < 0 || line >= nbdevs) { printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n"); tty->driver_data = NULL; return(-ENODEV); } MOD_INC_USE_COUNT; ch = &digi_channels[line]; boardnum = ch->boardnum; /* Check status of board configured in system. */ /* ----------------------------------------------------------------- I check to see if the epca_setup routine detected an user error. It might be better to put this in pc_init, but for the moment it goes here. ---------------------------------------------------------------------- */ if (invalid_lilo_config) { if (setup_error_code & INVALID_BOARD_TYPE) printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n"); if (setup_error_code & INVALID_NUM_PORTS) 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. -------------------------------------------------------------------- */ /* Should this be here except for SPLIT termios ? */ if (ch->count == 1) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = ch->normal_termios; else *tty->termios = ch->callout_termios; } ch->session = current->session; ch->pgrp = current->pgrp; 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 MODULE/* -------------------- Begin init_module ---------------------- */int __init init_module(){ /* Begin init_module */ unsigned long flags; save_flags(flags); cli(); pc_init(); restore_flags(flags); return(0);} /* End init_module */#endif#ifdef ENABLE_PCIstatic struct pci_driver epca_driver;#endif#ifdef MODULE/* -------------------- Begin cleanup_module ---------------------- */void cleanup_module(){ /* Begin cleanup_module */ 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_callout)) || (tty_unregister_driver(&pc_info))) { printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n"); restore_flags(flags); return; } 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);} /* End cleanup_module */#endif /* MODULE *//* ------------------ 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 */ /* ----------------------------------------------------------------------- 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 (pci_present()) { if(num_cards < MAXBOARDS) pci_boards_found += init_PCI(); num_cards += pci_boards_found; } else { printk(KERN_ERR "<Error> - No PCI BIOS found\n"); }#endif /* ENABLE_PCI */ memset(&pc_driver, 0, sizeof(struct tty_driver)); memset(&pc_callout, 0, sizeof(struct tty_driver)); memset(&pc_info, 0, sizeof(struct tty_driver)); pc_driver.magic = TTY_DRIVER_MAGIC; pc_driver.name = "ttyD"; pc_driver.major = DIGI_MAJOR; pc_driver.minor_start = 0; pc_driver.num = MAX_ALLOC; 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; pc_driver.refcount = &pc_refcount; pc_driver.table = pc_table; /* pc_termios is an array of pointers pointing at termios structs */ /* The below should get the first pointer */ pc_driver.termios = pc_termios; pc_driver.termios_locked = pc_termios_locked;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -