📄 pt.c
字号:
static void chipset_init(struct device *dev){ struct pt_local *lp = (struct pt_local*) dev->priv;#ifdef PT_DEBUG printk(KERN_DEBUG "PT: chipset_init(): pt0a tstate = %d.\n", ((struct pt_local*)pt0a.priv)->tstate); printk(KERN_DEBUG "PT: chipset_init(): pt0b tstate = %d.\n", ((struct pt_local*)pt0b.priv)->tstate);#endif /* Reset SCC if both channels are to be canned */ if ( ((lp->base & CHANA) && !(pt_sercfg & PT_DTRB_ON)) || (!(lp->base & CHANA) && !(pt_sercfg & PT_DTRA_ON)) ) { wrtscc(lp->cardbase, lp->base + CTL, R9, FHWRES); /* Reset int and dma registers */ outb_p((pt_sercfg = 0), lp->cardbase + SERIAL_CFG); outb_p((pt_dmacfg = 0), lp->cardbase + DMA_CFG);#ifdef PT_DEBUG printk(KERN_DEBUG "PT: chipset_init() Resetting SCC, called by ch (%d).\n", lp->base & CHANA);#endif } /* Reset individual channel */ if (lp->base & CHANA) { wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRA); outb_p( (pt_sercfg &= ~PT_DTRA_ON), lp->cardbase + SERIAL_CFG); } else { wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRB); outb_p( (pt_sercfg &= ~PT_DTRB_ON), lp->cardbase + SERIAL_CFG); }} /* chipset_init() */__initfunc(int pt_init(void)){ int *port; int ioaddr = 0; int card_type = 0; int ports[] = { 0x230, 0x240, 0x250, 0x260, 0x270, 0x280, 0x290, 0x2a0, 0x2b0, 0x300, 0x330, 0x3f0, 0}; printk(KERN_INFO "PT: 0.41 ALPHA 07 October 1995 Craig Small (csmall@small.dropbear.id.au)\n"); for (port = &ports[0]; *port && !card_type; port++) { ioaddr = *port; if (check_region(ioaddr, PT_TOTAL_SIZE) == 0) { printk(KERN_INFO "PT: Probing for card at address %#3x\n", ioaddr); card_type = hw_probe(ioaddr); } } if (card_type) { printk(KERN_INFO "PT: Found a PT at address %#3x\n",ioaddr); } else { printk(KERN_ERR "PT: ERROR: No card found.\n"); return -EIO; } /* * Link a couple of device structures into the chain * * For the A port * Allocate space for 4 buffers even though we only need 3, * because one of them may cross a DMA page boundary and * be rejected by get_dma_buffer(). */ register_netdev(&pt0a); pt0a.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); pt0a.dma = 0; /* wizzer - no dma yet */ pt0a.base_addr = ioaddr + CHANA; pt0a.irq = 0; /* And B port */ register_netdev(&pt0b); pt0b.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA); pt0b.base_addr = ioaddr + CHANB; pt0b.irq = 0; /* Now initialise them */ pt_probe(&pt0a); pt_probe(&pt0b); pt0b.irq = pt0a.irq; /* IRQ is shared */ return 0;} /* pt_init() *//* * Probe for PT card. Also initialises the timers */__initfunc(static int hw_probe(int ioaddr)){ int time = 1000; /* Number of milliseconds to test */ int a = 1; int b = 1; unsigned long start_time, end_time; inb_p(ioaddr + TMR1CLR); inb_p(ioaddr + TMR2CLR); /* Timer counter channel 0, 1mS period */ outb_p(SC0 | LSB_MSB | MODE3, ioaddr + TMRCMD); outb_p(0x00, ioaddr + TMR0); outb_p(0x18, ioaddr + TMR0); /* Setup timer control word for timer 1 */ outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD); outb_p((time << 1) & 0xff, ioaddr + TMR1); outb_p((time >> 7) & 0xff, ioaddr + TMR1); /* wait until counter reg is loaded */ do { /* Latch count for reading */ outb_p(SC1, ioaddr + TMRCMD); a = inb_p(ioaddr + TMR1); b = inb_p(ioaddr + TMR1); } while (b == 0); start_time = jiffies; while(b != 0) { /* Latch count for reading */ outb_p(SC1, ioaddr + TMRCMD); a = inb_p(ioaddr + TMR1); b = inb_p(ioaddr + TMR1); end_time = jiffies; /* Don't wait forever - there may be no card here */ if ((end_time - start_time) > 200) { inb_p(ioaddr + TMR1CLR); return 0; } } /* Now fix the timers up for general operation */ /* Clear the timers */ inb_p(ioaddr + TMR1CLR); inb_p(ioaddr + TMR2CLR); outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD); inb_p(ioaddr + TMR1CLR); outb_p(SC2 | LSB_MSB | MODE0, ioaddr + TMRCMD); /* Should this be tmr1 or tmr2? wiz3*/ inb_p(ioaddr + TMR1CLR); return 1;} /* hw_probe() */static void pt_rts(struct pt_local *lp, int x){ int tc; long br; int cmd = lp->base + CTL;#ifdef PT_DEBUG printk(KERN_DEBUG "PT: pt_rts(): Transmitter status will be %d (%d).\n", x, lp->base & CHANA);#endif if (x == ON) { /* Ex ints off to avoid int */ wrtscc(lp->cardbase, cmd, R15, 0); wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); /* Rx off */ lp->rstate = IDLE; if(lp->dmachan) { /* Setup for Tx DMA */ wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB); } else { /* No interrupts */ wrtscc(lp->cardbase, cmd, R1, 0); } if (!lp->clockmode) { if (lp->speed) { br = lp->speed; tc = (lp->xtal / (br * 2)) - 2; wrtscc(lp->cardbase, cmd, R12, tc & 0xff); wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); } } /* Turn on Tx by raising RTS */ wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR); /* Transmitter on now */ } else { /* turning off Tx */ lp->tstate = IDLE; /* Turn off Tx by dropping RTS */ wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR); if (!lp->clockmode) { if (lp->speed) /* internally clocked */ { /* Reprogram BRG from 32x clock for Rx DPLL */ /* BRG off, keep PClk source */ wrtscc(lp->cardbase, cmd, R14, BRSRC); br = lp->speed; tc = ((lp->xtal / 32) / (br * 2)) - 2; wrtscc(lp->cardbase, cmd, R12, tc & 0xff); wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff); /* SEARCH mode, BRG source */ wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* Enable the BRG */ wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL); } } /* Flush Rx fifo */ /* Turn Rx off */ wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8); /* Reset error latch */ wrtscc(lp->cardbase, cmd, R0, ERR_RES); /* get status byte from R1 */ (void) rdscc(lp->cardbase, cmd, R1); /* Read and dump data in queue */ (void) rdscc(lp->cardbase, cmd, R8); (void) rdscc(lp->cardbase, cmd, R8); (void) rdscc(lp->cardbase, cmd, R8); /* Now, turn on Rx and hunt for a flag */ wrtscc(lp->cardbase, cmd, R3, RxENABLE | AUTO_ENAB | Rx8 ); lp->rstate = ACTIVE; if (lp->dmachan) { setup_rx_dma(lp); } else { /* Reset buffer pointers */ lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; /* Allow aborts to interrupt us */ wrtscc(lp->cardbase, cmd, R1, INT_ALL_Rx | EXT_INT_ENAB); } wrtscc(lp->cardbase, cmd, R15, BRKIE ); }} /* pt_rts() */static int valid_dma_page(unsigned long addr, unsigned long dev_bufsize){ if (((addr & 0xffff) + dev_bufsize) <= 0x10000) return 1; else return 0;}static int pt_set_mac_address(struct device *dev, void *addr){ struct sockaddr *sa = (struct sockaddr *)addr; memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); /* addr is an AX.25 shifted ASCII */ return 0; /* mac address */}/* Allocate a buffer which does not cross a DMA page boundary */static char * get_dma_buffer(unsigned long *mem_ptr){ char *ret; ret = (char *) *mem_ptr; if (!valid_dma_page(*mem_ptr, DMA_BUFF_SIZE + sizeof(struct mbuf))) { *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); ret = (char *) *mem_ptr; } *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf)); return (ret);} /* get_dma_buffer() *//* * Sets up all the structures for the PT device */static int pt_probe(struct device *dev){ short ioaddr; struct pt_local *lp; unsigned long flags; unsigned long mem_ptr; ioaddr = dev->base_addr; /* * Initialise the device structure. * Must be done before chipset_init() * Make sure data structures used by the PT are aligned */ dev->priv = (void *) (((int) dev->priv + 7) & ~7); lp = (struct pt_local*) dev->priv; memset(dev->priv, 0, sizeof(struct pt_local)); /* Allocate some buffers which do not cross DMA boundaries */ mem_ptr = (unsigned long) dev->priv + sizeof(struct pt_local); lp->txdmabuf = get_dma_buffer(&mem_ptr); lp->rxdmabuf1 = (struct mbuf *) get_dma_buffer(&mem_ptr); lp->rxdmabuf2 = (struct mbuf *) get_dma_buffer(&mem_ptr); /* Initialise the Rx buffer */ lp->rcvbuf = lp->rxdmabuf1; lp->rcp = lp->rcvbuf->data; lp->rcvbuf->cnt = 0; /* Initialise the transmit queue head structure */ skb_queue_head_init(&lp->sndq); lp->base = dev->base_addr; lp->cardbase = dev->base_addr & 0x3f0; /* These need to be initialised before scc_init() is called. */ lp->xtal = XTAL; if (dev->base_addr & CHANA) { lp->speed = DEF_A_SPEED; lp->txdelay = DEF_A_TXDELAY; lp->persist = DEF_A_PERSIST; lp->slotime = DEF_A_SLOTIME; lp->squeldelay = DEF_A_SQUELDELAY; lp->clockmode = DEF_A_CLOCKMODE; lp->nrzi = DEF_A_NRZI; } else { lp->speed = DEF_B_SPEED; lp->txdelay = DEF_B_TXDELAY; lp->persist = DEF_B_PERSIST; lp->slotime = DEF_B_SLOTIME; lp->squeldelay = DEF_B_SQUELDELAY; lp->clockmode = DEF_B_CLOCKMODE; lp->nrzi = DEF_B_NRZI; } lp->bufsiz = DMA_BUFF_SIZE; lp->tstate = IDLE; chipset_init(dev); if (dev->base_addr & CHANA) { /* Note that a single IRQ services 2 devices (A and B channels) */ /* * We disable the dma for a while, we have to get ints working * properly first!! */ lp->dmachan = 0; if (dev->irq < 2) { autoirq_setup(0); /* Turn on PT interrupts */ save_flags(flags); cli(); outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG); restore_flags(flags); /* Set a timer interrupt */ tdelay(lp, 1); dev->irq = autoirq_report(20); /* Turn off PT interrupts */ save_flags(flags); cli(); outb_p( (pt_sercfg &= ~ PT_EI), lp->cardbase + INT_CFG); restore_flags(flags); if (!dev->irq) { printk(KERN_ERR "PT: ERROR: Failed to detect IRQ line, assuming IRQ7.\n"); } } printk(KERN_INFO "PT: Autodetected IRQ %d, assuming DMA %d\n", dev->irq, dev->dma); /* This board has jumpered interrupts. Snarf the interrupt vector * now. There is no point in waiting since no other device can use * the interrupt, and this marks the 'irqaction' as busy. */ { int irqval = request_irq(dev->irq, &pt_interrupt,0, "pt", dev); if (irqval) { printk(KERN_ERR "PT: ERROR: Unable to get IRQ %d (irqval = %d).\n", dev->irq, irqval); return EAGAIN; } } /* Grab the region */ request_region(ioaddr & 0x3f0, PT_TOTAL_SIZE, "pt" ); } /* A port */ dev->open = pt_open; dev->stop = pt_close; dev->do_ioctl = pt_ioctl; dev->hard_start_xmit = pt_send_packet; dev->get_stats = pt_get_stats; /* Fill in the fields of the device structure */ dev_init_buffers(dev);#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) dev->hard_header = ax25_encapsulate; dev->rebuild_header = ax25_rebuild_header;#endif dev->set_mac_address = pt_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ dev->hard_header_len = 73; /* We do digipeaters now */ dev->mtu = 1500; /* eth_mtu is default */ dev->addr_len = 7; /* sizeof an ax.25 address */ memcpy(dev->broadcast, ax25_bcast, 7); memcpy(dev->dev_addr, ax25_test, 7); /* New style flags */ dev->flags = 0; return 0;} /* pt_probe() *//* Open/initialise the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even * registers that 'should' only be set once at boot, so that there is * a non-reboot way to recover if something goes wrong. * derived from last half of tsync_attach() */static int pt_open(struct device *dev){ unsigned long flags; struct pt_local *lp = dev->priv; static first_time = 1; if (dev->base_addr & CHANA) { if (first_time)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -