📄 sdl_acb56.c
字号:
mblk_t *mp = p->rx_msg, *mc = p->cp_msg; unsigned int len = (unsigned int)(p->rx_buf - mp->b_rptr); unsigned char li = mp->b_rptr[2]&0x3f; if (len<3) return acb56_short_error(p); if (len>p->dev.module->config.m+4) return acb56_long_error(p); if (li!=(len>63+3?63+3:len)) return acb56_length_error(p); mp->b_wptr = mp->b_rptr + len; if (len<6) { int clen = mc->b_wptr - mc->b_rptr; if (len==clen && !memcmp(mc->b_rptr,mp->b_rptr,len)) { p->stats.compressed_sus++; acb56_rx_setup_next_frame(p); p->dev.ucalls->daedr_compr_frame(&p->dev,1); return; } else { memcpy(mc->b_rptr,mp->b_rptr,len); mc->b_wptr = mc->b_rptr + len; } } else mc->b_wptr = mc->b_rptr; p->rx_octet_mode = 0; acb56_rx_setup_next_frame(p); p->dev.ucalls->daedr_recvd_frame(&p->dev, mp); acb56_do_resupply(); /* mark BH for resupply */ if ( !(p->rx_msg = bufq_dequeue(&acb56_supplyq)) && !(p->rx_msg = bufq_dequeue(&acb56_returnq)) ) return acb56_buffer_error(p); p->rx_buf = p->rx_msg->b_wptr = p->rx_msg->b_rptr; p->rx_max = p->rx_msg->b_datap->db_lim; return; }} static inline void acb56_frame_overflow_check(acb56_t *p) { int actrl = p->dev.iface.iobase+1; /* check for frame overflow */ if (p->rx_buf>p->rx_max) { /* FIGURE 11/Q.703 (sheet 1 of 2) "m+7 octets without flags" */ if (!p->rx_octet_mode && p->dev.iface.ifclock!=DEV_CLOCK_DPLL) { /* can't octet count on DPLL! */ p->rx_octet_count = 0; p->rx_octet_mode = 1; outb(0x0f,actrl); outb(p->regs[0x0f]|=0x02,actrl); /* octet counting isr */ outb(0x03,actrl); outb(p->regs[0x03]|=0x10,actrl); /* force flag hunt */ acb56_rx_setup_next_frame(p); p->dev.ucalls->daedr_loss_of_sync(&p->dev); } }} static void acb56_isr_cha_tx_buf_empty(acb56_t *p) { p->stats.cha_tx_buf_empty++;} static void acb56_isr_cha_ext_status(acb56_t *p) { unsigned char rr0; register int actrl = p->dev.iface.iobase+1; rr0 = p->rr0&~0x02 ; outb(0x00,actrl); p->rr0=inb(actrl); outb(0x00,actrl); outb(0x10,actrl); outb(0x00,actrl); outb(0x10,actrl); /* debounce */ rr0 ^= p->rr0 & 0xfa; if (rr0) { if (rr0 & 0x40) acb56_tx_underrun_eom (p); if (rr0 & 0x10) acb56_sync_hunt (p); if (rr0 & 0x80) acb56_break_abort (p); if (rr0 & 0x08) acb56_dcd (p); if (rr0 & 0x20) acb56_cts (p); } else acb56_zero_count (p); p->stats.cha_ext_status++;} static void acb56_isr_cha_rx_char_avail(acb56_t *p) { register int adata = p->dev.iface.iobase; register int i=0; if ( p->rx_buf ) { /* collect bytes */ for (i=0; i<4; i++) *(p->rx_buf++) = inb(adata); acb56_frame_overflow_check(p); } p->dev.module->stats.rx_bytes+=4; p->stats.cha_rx_char_avail++;} static void acb56_isr_cha_rx_sp_cond(acb56_t *p) { unsigned char rr1 = 0; register int adata = p->dev.iface.iobase; register int actrl = p->dev.iface.iobase+1; register int i=0; p->stats.cha_rx_sp_cond++; /* collect bytes */ outb(0x00,actrl); for (i=0; i<4 && (inb(actrl)&0x01); i++) { *(p->rx_buf++) = inb(adata); p->dev.module->stats.rx_bytes++; outb(0x00,actrl); } acb56_frame_overflow_check(p); /* check for special conditions */ outb(0x07,actrl); if (inb(actrl)&0x40) { outb(0x01,actrl); if ((rr1=inb(actrl))&0xf0) { outb(0x00,actrl); outb(0x30,actrl); /* reset error */ if (rr1 & 0x10 ) { return acb56_parity_error (p); } if (rr1 & 0x20 ) { return acb56_rx_overrun (p); } if (rr1 & 0x80 ) { if (rr1 & 0x40 ) { return acb56_crc_error (p); } else { if((rr1&0xe)^0x6){ return acb56_residue_error (p); } else { return acb56_end_of_frame (p); } } } } }}static void acb56_isr_donothing(acb56_t *p) { (void)p; };static void acb56_isr_chb_tx_buf_empty(acb56_t *p) { p->stats.chb_tx_buf_empty++; }static void acb56_isr_chb_ext_status(acb56_t *p) { p->stats.chb_ext_status++; }static void acb56_isr_chb_rx_char_avail(acb56_t *p){ p->stats.chb_rx_char_avail++; }static void acb56_isr_chb_rx_sp_cond(acb56_t *p) { p->stats.chb_rx_sp_cond++; }static void acb56_isr(int irq, void *dev_id, struct pt_regs *regs) { static void (*vector_map[])(acb56_t *) = { acb56_isr_chb_tx_buf_empty, acb56_isr_chb_ext_status, acb56_isr_chb_rx_char_avail, acb56_isr_chb_rx_sp_cond, acb56_isr_cha_tx_buf_empty, acb56_isr_cha_ext_status, acb56_isr_cha_rx_char_avail, acb56_isr_cha_rx_sp_cond }; unsigned char rr3; register int i; register int actrl = ((acb56_t *)dev_id)->dev.iface.iobase+1; for (i=0,outb(0x03,actrl),rr3=inb(actrl);i<4&&rr3;i++,outb(0x03,actrl),rr3=inb(actrl)) { outb(0x02,actrl+2); (*vector_map[inb(actrl+2)>>1])(dev_id); /* reset highest interrupt under service */ outb(0x00,actrl); outb(0x38,actrl); } ((acb56_t *)dev_id)->stats.interrupts++;};/* * ========================================================================= * * DRIVER SERVICE CALLS * * ========================================================================= */static dev_device_t dev_acbdev_default ={ SPIN_LOCK_UNLOCKED, /* iflock */ 0, /* ifflags */ DEV_TYPE_V35, /* iftype */ DEV_GTYPE_NONE, /* ifgtype */ DEV_MODE_DTE, /* ifmode */ 56000, /* ifrate */ DEV_CLOCK_DPLL, /* ifclock */ DEV_CODING_NRZI, /* ifcoding */ 0, /* ifleads */ 0, /* ifindex */ 0, /* irq */ 0, /* dma_rx */ 0 /* dma_tx */};static const unsigned char preamble[] = { 0x09, 0xC0, 0x0F, 0x01, 0x07, 0x6B, 0x0F, 0x00, 0x00, 0x00, 0x04, 0x20, 0x01, 0x00, 0x02, 0x00, 0x03, 0xCA, 0x05, 0x63, 0x06, 0x00, 0x07, 0x7e, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x16, 0x0C, 0x40, 0x0D, 0x00, 0x0E, 0x02, 0x0E, 0x02, 0x0E, 0x02, 0x0E, 0x03, 0x03, 0xCB, 0x05, 0x6B, 0x00, 0x80, 0x00, 0x30, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x10, 0x00, 0x10, 0x01, 0x00, 0x09, 0x00 };static const unsigned char preset[] = { 0x09, 0xc0, 0x00, 0x00, 0x04, 0x20, 0x03, 0xca, 0x05, 0xe3, 0x07, 0x7e, 0x06, 0x00, 0x0F, 0x01, 0x07, 0x6b, 0x0F, 0x00, 0x01, 0x00, 0x02, 0x00, 0x09, 0x00, 0x0A, 0x80 };static const unsigned char mode_clock[6][3] = { { 0x08, 0x05, 0x7f }, { 0x08, 0x56, 0x7f }, { 0x50, 0x50, 0x78 }, { 0x16, 0x50, 0x1f }, { 0x50, 0x50, 0x78 }, { 0x50, 0x50, 0x78 } };static unsigned char irqprobe[] = { 0x01, 0x19, 0x0F, 0xFA, 0x00, 0x10, 0x00, 0x10, 0x09, 0x08, 0x0E, 0x03};static void dummy_isr(int irq, void *dev_id, struct pt_regs *regs) { volatile int *p; (void)irq; (void)dev_id; (void)regs; p = NULL; p++;}static int board = 0;static int ports[] = { 0x238, 0x280, 0x2A0, 0x300, 0x328, 0 };/* * DEVICE-ATTACH: This is the device attach. It should probe for the device * as specified by the minor device number and determine whether the device * is there and all of the resources for the device can be acquired. All * resources associated with the device (except the allocated structure, * which is freed by the caller) should be freed at the end of this routine * so that the device may be used by some other module if required. */static lmi_t *acb56_devatt(dev_t dev){ int iobase, _irq, actrl, _dma_rx, _dma_tx, i, err; unsigned long time, cookie; acb56_t *p = NULL; board = getminor(dev)-1; if ((iobase=io[board])==-1) iobase=ports[board]; if ((err=check_region(iobase,8))) return NULL; actrl = iobase+1; outb(0x02,actrl); outb(0x55,actrl); /* write to unallocated 8530 bit in WR2 */ outb(0x02,actrl); if (inb(actrl)!=0x55) return NULL; /* probably an 8530 */ outb(0x09,actrl); outb(0xc0,actrl); /* force hardware reset */ outb(0x0f,actrl); outb(0x01,actrl); /* Access W7P register */ outb(0x0f,actrl); if (!inb(actrl)&0x01) return NULL; /* probably an 8530 */ outb(0x0f,actrl); outb(0x00,actrl); /* Remove accss to W7P register */ outb(0x0f,actrl); if (inb(actrl)&0x01) return NULL; /* probably an 8530 */ /* check assigned irq */ if ((_irq=irq[board])!=-1) { if ((err = request_irq(_irq,dummy_isr,SA_SHIRQ,"acb56_dummy",NULL))) return NULL; else goto acb_probe_dma; } for (i=0;i<sizeof(preamble);) { /* setup chip */ outb(preamble[i],actrl); i++; outb(preamble[i],actrl); i++; } cookie = probe_irq_on(); for (i=0;i<sizeof(irqprobe);) { /* setup for guaranteed interrupt */ outb(irqprobe[i],actrl); i++; outb(irqprobe[i],actrl); i++; } /* fill tx fifo to get an interrupt */ outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); outb(0x55,iobase); for (time=jiffies;jiffies-time<100;i++); if (!(_irq = probe_irq_off(cookie))) return NULL; /* no irq! */ outb(0x03,actrl); if (!inb(actrl)) return NULL; /* it wasn't us */ outb(0x09,actrl); outb(0x00,actrl); outb(0x09,actrl); outb(0xc0,actrl); /* force hardware reset */ if ((err=request_irq(_irq,dummy_isr,SA_SHIRQ,"acb56_dummy",NULL))) return NULL;acb_probe_dma: free_irq(_irq,NULL); /* check for dma */ if ((_dma_rx=dma_rx[board])&&_dma_rx!=-1&&!(request_dma(_dma_rx,"acb56_probe"))) free_dma(_dma_rx); else _dma_rx=0; if ((_dma_tx=dma_tx[board])&&_dma_tx!=-1&&!(request_dma(_dma_tx,"acb56_probe"))) free_dma(_dma_tx); else _dma_tx=0; if (!(p = kmalloc(sizeof(*p),GFP_KERNEL))) return NULL; bzero(p, sizeof(*p)); bcopy(&dev_acbdev_default, &p->dev.iface, sizeof(p->dev.iface)); p->dev.iface.ifindex = board; p->dev.iface.irq = _irq; p->dev.iface.iobase = iobase; p->dev.iface.dma_tx = _dma_tx; p->dev.iface.dma_rx = _dma_rx; if (mode [board]!=-1) p->dev.iface.ifmode = mode [board]; if (clock[board]!=-1) p->dev.iface.ifclock = clock[board]; ptrace(("sucessful:\n")); ptrace((" ifindex = %lu\n", p->dev.iface.ifindex)); ptrace((" irq = %lu\n", p->dev.iface.irq)); ptrace((" iobase = 0x%lx\n", p->dev.iface.iobase)); ptrace((" dma_tx = %lu\n", p->dev.iface.dma_tx)); ptrace((" dma_rx = %lu\n", p->dev.iface.dma_rx)); return((lmi_t *)p);}/* * DEVICE-OPEN: Using the information contained in the device structure * created at device attach, this function should reacquire all of the * resources associated with the device (e.g., irqs). The device is left in * the quiescent state. */static intacb56_open(lmi_t *lmi){ acb56_t *p = (acb56_t *)lmi; dev_device_t *dev = &p->dev.iface; int err=0; unsigned long flags; spin_lock_irqsave(&dev->iflock, flags); MOD_INC_USE_COUNT; /* get io region */ if ((err=check_region(dev->iobase,8))) { MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&dev->iflock, flags); return err; } request_region(dev->iobase,8,"acb56"); /* get dma channels */ if (dev->dma_rx && request_dma(dev->dma_rx,"acb56")) dev->dma_rx=0; if (dev->dma_tx && request_dma(dev->dma_tx,"acb56")) dev->dma_tx=0; /* get interrupt */ if ((err=request_irq(dev->irq,acb56_isr,SA_SHIRQ,"acb56",p))) { if (dev->dma_rx) free_dma(dev->dma_rx); if (dev->dma_tx) free_dma(dev->dma_tx); MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&dev->iflock, flags); return err; } spin_unlock_irqrestore(&dev->iflock, flags); return(0);}/* * DEVICE-CLOSE: Using the information contained in the device structure * created at device attach, this function should deallocate all of the * driver resources associated with the device with the exception of the * device structure itself. The device will be in the quiescent state when * the procedure is called. */static intacb56_close(lmi_t *lmi){ acb56_t *p = (acb56_t *)lmi; dev_device_t *dev = &p->dev.iface; unsigned long flags; spin_lock_irqsave(&dev->iflock, flags); free_irq(dev->irq,p); if (dev->dma_tx) free_dma(dev->dma_tx); if (dev->dma_rx) free_dma(dev->dma_rx); release_region(dev->iobase,8); MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&dev->iflock, flags); return(0);}/* * INFO: This is for Style 2 device drivers for returning PPAs. Since this * is only a single-port card, the Signalling Data Link is determined at open * time and we simply return a zero-length PPA. */static intacb56_info(lmi_t *lmi, void **ppap, int *lenp){ acb56_t *p = (acb56_t *)lmi; dev_device_t *dev = &p->dev.iface; unsigned long flags; (void)dev; spin_lock_irqsave(&dev->iflock, flags); *lenp = 0; *ppap = NULL; spin_unlock_irqrestore(&dev->iflock, flags); return(0);}/* * ATTACH: This is for Style 2 device drivers. Since this is only a * single-port card, the Signalling Data Link is determined at open time and * we simply agree with any attach command. */static intacb56_attach(lmi_t *lmi, void *ppa, int len){ acb56_t *p = (acb56_t *)lmi; dev_device_t *dev = &p->dev.iface; unsigned long flags; (void)dev; (void)ppa; (void)len; spin_lock_irqsave(&dev->iflock, flags); spin_unlock_irqrestore(&dev->iflock, flags); return(0);}/* * DETACH: This is for Style 2 device drivers. Since this is only a * single-port card, the Signalling Data LInk was determined at open time and * cannot be detached, so, we simply agree with any detach command. */static intacb56_detach(lmi_t *lmi){ acb56_t *p = (acb56_t *)lmi; dev_device_t *dev = &p->dev.iface; unsigned long flags; (void)dev; spin_lock_irqsave(&dev->iflock, flags); spin_unlock_irqrestore(&dev->iflock, flags); return(0);}#ifndef abs#define abs(x) ((x)<0 ? -(x):(x))#endif/* * ENABLE: This should set up the hardware for the device using the resources * which were reserved during the open. The device should be activated and * made ready for operation. Interrupt service routines should be enabled. */static intacb56_enable(lmi_t *lmi){ acb56_t *p = (acb56_t *)lmi; dev_device_t *dev = &p->dev.iface; int i, actrl; unsigned long flags; spin_lock_irqsave(&dev->iflock, flags); actrl = dev->iobase+1; for (i=0;i<16;i++) p->regs[i] = 0; /* register images */ /* setup chip */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -