📄 epca.c
字号:
/* ------------------------------------------------------------------ Setup entry points for the driver. These are primarily called by the kernel in tty_io.c and n_tty.c --------------------------------------------------------------------- */ pc_driver.open = pc_open; pc_driver.close = pc_close; pc_driver.write = pc_write; pc_driver.write_room = pc_write_room; pc_driver.flush_buffer = pc_flush_buffer; pc_driver.chars_in_buffer = pc_chars_in_buffer; pc_driver.flush_chars = pc_flush_chars; pc_driver.put_char = pc_put_char; pc_driver.ioctl = pc_ioctl; pc_driver.set_termios = pc_set_termios; pc_driver.stop = pc_stop; pc_driver.start = pc_start; pc_driver.throttle = pc_throttle; pc_driver.unthrottle = pc_unthrottle; pc_driver.hangup = pc_hangup; pc_callout = pc_driver; pc_callout.name = "cud"; pc_callout.major = DIGICU_MAJOR; pc_callout.minor_start = 0; pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; pc_callout.subtype = SERIAL_TYPE_CALLOUT; pc_info = pc_driver; pc_info.name = "digi_ctl"; pc_info.major = DIGIINFOMAJOR; pc_info.minor_start = 0; pc_info.num = 1; pc_info.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; pc_info.subtype = SERIAL_TYPE_INFO; 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: case PC64XE: bd->memory_seg = 0xf000; break; case PCXI: board_id = inb((int)bd->port); if ((board_id & 0x1) == 0x1) { /* Begin its 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; } /* End it is an XI card */ else { printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); } break; } /* End switch on bd->type */ } /* End for each card */ if (tty_register_driver(&pc_driver)) panic("Couldn't register Digi PC/ driver"); if (tty_register_driver(&pc_callout)) panic("Couldn't register Digi PC/ callout"); if (tty_register_driver(&pc_info)) panic("Couldn't register Digi PC/ info "); /* ------------------------------------------------------------------- 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); restore_flags(flags); return 0;} /* End pc_init *//* ------------------ Begin post_fep_init ---------------------- */static void post_fep_init(unsigned int crd){ /* Begin post_fep_init */ int i; unchar *memaddr; volatile struct global_data *gd; struct board_info *bd; volatile struct board_chan *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) /* If the board in question is PCI */ { /* 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)). ------------------------------------------------------------------------ */ bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long) (bd->re_map_membase + XEMPORTS)); epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); nbdevs += (bd->numports); } /* End get PCI number of ports */ 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 = (unchar *)bd->re_map_membase; /* The below command is necessary because newer kernels (2.1.x and up) do not have a 1:1 virtual to physical mapping. The below call adjust for that. */ memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); /* ----------------------------------------------------------------- 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 = (volatile struct board_chan *)((ulong)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 = (volatile struct global_data *)((ulong)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)) && (*(ushort *)((ulong)memaddr + XEPORTS) < 3)) shrinkmem = 1; if (bd->type < PCIXEM) request_region((int)bd->port, 4, board_desc[bd->type]); memwinon(bd, 0); /* -------------------------------------------------------------------- Remember ch is the main drivers channels structure, while bc is the cards channel structure. ------------------------------------------------------------------------ */ /* For every port on the card do ..... */ for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ ch->brdchan = bc; ch->mailbox = gd; ch->tqueue.routine = do_softint; ch->tqueue.data = ch; ch->board = &boards[crd]; switch (bd->type) { /* Begin 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 ; ch->m_dcd = 0x80 ; ch->m_dsr = 0x20 ; ch->m_cts = 0x10 ; ch->m_ri = 0x40 ; ch->m_dtr = 0x01 ; break; case PCXE: case PCXEVE: case PCXI: case PC64XE: ch->m_rts = 0x02 ; ch->m_dcd = 0x08 ; ch->m_dsr = 0x10 ; ch->m_cts = 0x20 ; ch->m_ri = 0x40 ; ch->m_dtr = 0x80 ; break; } /* End switch bd->type */ if (boards[crd].altpin) { ch->dsr = ch->m_dcd; ch->dcd = ch->m_dsr; ch->digiext.digi_flags |= DIGI_ALTPIN; } else { ch->dcd = ch->m_dcd; ch->dsr = ch->m_dsr; } ch->boardnum = crd; ch->channelnum = i; ch->magic = EPCA_MAGIC; ch->tty = 0; if (shrinkmem) { fepcmd(ch, SETBUFFER, 32, 0, 0, 0); shrinkmem = 0; } switch (bd->type) { /* Begin switch bd->type */ case PCIXEM: case PCIXRJ: case PCIXR: /* Cover all the 2MEG cards */ ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff); ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff); ch->txwin = FEPWIN | ((bc->tseg) >> 11); ch->rxwin = FEPWIN | ((bc->rseg) >> 11); break; case PCXEM: case EISAXEM: /* Cover all the 32K windowed cards */ /* Mask equal to window size - 1 */ ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff); ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff); ch->txwin = FEPWIN | ((bc->tseg) >> 11); ch->rxwin = FEPWIN | ((bc->rseg) >> 11); break; case PCXEVE: case PCXE: ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff); ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9); ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff); ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 ); break; case PCXI: case PC64XE: ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4); ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4); ch->txwin = ch->rxwin = 0; break; } /* End switch bd->type */ ch->txbufhead = 0; ch->txbufsize = bc->tmax + 1; ch->rxbufhead = 0; ch->rxbufsize = bc->rmax + 1; lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); /* Set transmitter low water mark */ fepcmd(ch, STXLWATER, lowwater, 0, 10, 0); /* Set receiver low water mark */ fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0); /* Set receiver high water mark */ fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0); bc->edelay = 100; bc->idata = 1; ch->startc = bc->startc; ch->stopc = bc->stopc; ch->startca = bc->startca; ch->stopca = bc->stopca; ch->fepcflag = 0; ch->fepiflag = 0; ch->fepoflag = 0; ch->fepstartc = 0; ch->feps
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -