⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pi2.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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);}static int pi_probe(struct device *dev, int card_type){    short ioaddr;    struct pi_local *lp;    unsigned long flags;    unsigned long mem_ptr;    ioaddr = dev->base_addr;    /* Initialize the device structure. */    /* Must be done before chipset_init */    /* Make certain the data structures used by the PI2 are aligned. */    dev->priv = (void *) (((int) dev->priv + 7) & ~7);    lp = (struct pi_local *) dev->priv;    memset(dev->priv, 0, sizeof(struct pi_local));    /* Allocate some buffers which do not cross DMA page boundaries */    mem_ptr = (unsigned long) dev->priv + sizeof(struct pi_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);    /* Initialize rx buffer */    lp->rcvbuf = lp->rxdmabuf1;    lp->rcp = lp->rcvbuf->data;    lp->rcvbuf->cnt = 0;    /* Initialize the transmit queue head structure */    skb_queue_head_init(&lp->sndq);    /* These need to be initialized before scc_init is called. */    if (card_type == 1)	lp->xtal = (unsigned long) SINGLE / 2;    else	lp->xtal = (unsigned long) DOUBLE / 2;    lp->base = dev->base_addr;    lp->cardbase = dev->base_addr & 0x3f0;    if (dev->base_addr & CHANA) {	lp->speed = DEF_A_SPEED;	/* default channel access Params */	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;    } else {	lp->speed = DEF_B_SPEED;	/* default channel access Params */	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->bufsiz = DMA_BUFF_SIZE;    lp->tstate = IDLE;    chipset_init(dev);    if (dev->base_addr & CHANA) {	/* Do these things only for the A port */	/* Note that a single IRQ services 2 devices (A and B channels) */	lp->dmachan = dev->dma;	if (lp->dmachan < 1 || lp->dmachan > 3)	    printk(KERN_ERR "PI: DMA channel %d out of range\n", lp->dmachan);	/* chipset_init() was already called */	if (dev->irq < 2) {	    autoirq_setup(0);	    save_flags(flags);	    cli();	    wrtscc(lp->cardbase, CTL + lp->base, R1, EXT_INT_ENAB);	    /* enable PI card interrupts */	    wrtscc(lp->cardbase, CTL + lp->base, R9, MIE | NV);	    restore_flags(flags);	    /* request a timer interrupt for 1 mS hence */	    tdelay(lp, 1);	    /* 20 "jiffies" should be plenty of time... */	    dev->irq = autoirq_report(20);	    if (!dev->irq) {		printk(KERN_ERR "PI: Failed to detect IRQ line.\n");	    }	    save_flags(flags);	    cli();	    wrtscc(lp->cardbase, dev->base_addr + CTL, R9, FHWRES);	/* Hardware reset */	    /* Disable interrupts with master interrupt ctrl reg */	    wrtscc(lp->cardbase, dev->base_addr + CTL, R9, 0);	    restore_flags(flags);	}	printk(KERN_INFO "PI: 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, &pi_interrupt,0, "pi2", dev);	    if (irqval) {		printk(KERN_ERR "PI: unable to get IRQ %d (irqval=%d).\n",		       dev->irq, irqval);		return EAGAIN;	    }	}	/* Grab the region */	request_region(ioaddr & 0x3f0, PI_TOTAL_SIZE, "pi2" );    }				/* Only for A port */    dev->open = pi_open;    dev->stop = pi_close;    dev->do_ioctl = pi_ioctl;    dev->hard_start_xmit = pi_send_packet;    dev->get_stats = pi_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 = pi_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 the 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;}/* Open/initialize 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 need to be set once at boot, so that   there is non-reboot way to recover if something goes wrong.   */static int pi_open(struct device *dev){    unsigned long flags;    static first_time = 1;    struct pi_local *lp = (struct pi_local *) dev->priv;    if (dev->base_addr & 2) {	/* if A channel */	if (first_time) {	    if (request_dma(dev->dma,"pi2")) {		free_irq(dev->irq, dev);		return -EAGAIN;	    }	}	/* Reset the hardware here. */	chipset_init(dev);    }    lp->tstate = IDLE;    if (dev->base_addr & 2) {	/* if A channel */	scc_init(dev);		/* Called once for each channel */	scc_init(dev->next);    }    /* master interrupt enable */    save_flags(flags);    cli();    wrtscc(lp->cardbase, CTL + lp->base, R9, MIE | NV);    restore_flags(flags);    lp->open_time = jiffies;    dev->tbusy = 0;    dev->interrupt = 0;    dev->start = 1;    first_time = 0;    MOD_INC_USE_COUNT;    return 0;}static int pi_send_packet(struct sk_buff *skb, struct device *dev){    struct pi_local *lp = (struct pi_local *) dev->priv;    hardware_send_packet(lp, skb);    dev->trans_start = jiffies;    return 0;}/* The typical workload of the driver:   Handle the network interface interrupts. */static void pi_interrupt(int reg_ptr, void *dev_id, struct pt_regs *regs){/*    int irq = -(((struct pt_regs *) reg_ptr)->orig_eax + 2);*/    struct pi_local *lp;    int st;    unsigned long flags;/*    dev_b = dev_a->next;	 Relies on the order defined in Space.c */#if 0    if (dev_a == NULL) {	printk(KERN_ERR "PI: pi_interrupt(): irq %d for unknown device.\n", irq);	return;    }#endif    /* Read interrupt status register (only valid from channel A)     * Process all pending interrupts in while loop     */    lp = (struct pi_local *) pi0a.priv;	/* Assume channel A */    while ((st = rdscc(lp->cardbase, pi0a.base_addr | CHANA | CTL, R3)) != 0) {	if (st & CHBTxIP) {	    /* Channel B Transmit Int Pending */	    lp = (struct pi_local *) pi0b.priv;	    b_txint(lp);	} else if (st & CHARxIP) {	    /* Channel A Rcv Interrupt Pending */	    lp = (struct pi_local *) pi0a.priv;	    a_rxint(&pi0a, lp);	} else if (st & CHATxIP) {	    /* Channel A Transmit Int Pending */	    lp = (struct pi_local *) pi0a.priv;	    a_txint(lp);	} else if (st & CHAEXT) {	    /* Channel A External Status Int */	    lp = (struct pi_local *) pi0a.priv;	    a_exint(lp);	} else if (st & CHBRxIP) {	    /* Channel B Rcv Interrupt Pending */	    lp = (struct pi_local *) pi0b.priv;	    b_rxint(&pi0b, lp);	} else if (st & CHBEXT) {	    /* Channel B External Status Int */	    lp = (struct pi_local *) pi0b.priv;	    b_exint(lp);	}	/* Reset highest interrupt under service */	save_flags(flags);	cli();	wrtscc(lp->cardbase, lp->base + CTL, R0, RES_H_IUS);	restore_flags(flags);    }				/* End of while loop on int processing */    return;}/* The inverse routine to pi_open(). */static int pi_close(struct device *dev){    unsigned long flags;    struct pi_local *lp;    struct sk_buff *ptr;    save_flags(flags);    cli();    lp = (struct pi_local *) dev->priv;    ptr = NULL;    chipset_init(dev);		/* reset the scc */    disable_dma(lp->dmachan);    lp->open_time = 0;    dev->tbusy = 1;    dev->start = 0;    /* Free any buffers left in the hardware transmit queue */    while ((ptr = skb_dequeue(&lp->sndq)) != NULL)	kfree_skb(ptr);    restore_flags(flags);    MOD_DEC_USE_COUNT;    return 0;}static int pi_ioctl(struct device *dev, struct ifreq *ifr, int cmd){    unsigned long flags;    struct pi_req rq;    struct pi_local *lp = (struct pi_local *) dev->priv;    int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pi_req));    if (ret)	return ret;    if(cmd!=SIOCDEVPRIVATE)    	return -EINVAL;    copy_from_user(&rq, ifr->ifr_data, sizeof(struct pi_req));    switch (rq.cmd) {    case SIOCSPIPARAM:	if (!suser())	    return -EPERM;	save_flags(flags);	cli();	lp->txdelay = rq.txdelay;	lp->persist = rq.persist;	lp->slotime = rq.slotime;	lp->squeldelay = rq.squeldelay;	lp->clockmode = rq.clockmode;	lp->speed = rq.speed;	pi_open(&pi0a); /* both channels get reset %%% */	restore_flags(flags);	ret = 0;	break;    case SIOCSPIDMA:	if (!suser())	    return -EPERM;	ret = 0;	if (dev->base_addr & 2) {   /* if A channel */	   if (rq.dmachan < 1 || rq.dmachan > 3)		return -EINVAL;	   save_flags(flags);	   cli();	   pi_close(dev);	   free_dma(lp->dmachan);	   dev->dma = lp->dmachan = rq.dmachan;	   if (request_dma(lp->dmachan,"pi2"))		ret = -EAGAIN;	   pi_open(dev);	   restore_flags(flags);	}	break;    case SIOCSPIIRQ:	ret = -EINVAL;      /* add this later */	break;    case SIOCGPIPARAM:    case SIOCGPIDMA:    case SIOCGPIIRQ:	rq.speed = lp->speed;	rq.txdelay = lp->txdelay;	rq.persist = lp->persist;	rq.slotime = lp->slotime;	rq.squeldelay = lp->squeldelay;	rq.clockmode = lp->clockmode;	rq.dmachan = lp->dmachan;	rq.irq = dev->irq;	copy_to_user(ifr->ifr_data, &rq, sizeof(struct pi_req));	ret = 0;	break;    default:	ret = -EINVAL;    }    return ret;}/* Get the current statistics.	This may be called with the card open or   closed. */static struct net_device_stats *pi_get_stats(struct device *dev){	struct pi_local *lp = (struct pi_local *) dev->priv;	return &lp->stats;}#ifdef MODULEEXPORT_NO_SYMBOLS;MODULE_AUTHOR("David Perry <dp@hydra.carleton.ca>");MODULE_DESCRIPTION("AX.25 driver for the Ottawa PI and PI/2 HDLC cards");int init_module(void){    return pi_init();}void cleanup_module(void){    free_irq(pi0a.irq, &pi0a);	/* IRQs and IO Ports are shared */    release_region(pi0a.base_addr & 0x3f0, PI_TOTAL_SIZE);    kfree(pi0a.priv);    pi0a.priv = NULL;    unregister_netdev(&pi0a);    kfree(pi0b.priv);    pi0b.priv = NULL;    unregister_netdev(&pi0b);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -