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

📄 pcnet_cs.c

📁 ARM S3C2410 linux2.4 内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
reschedule:    info->watchdog.expires = jiffies + HZ;    add_timer(&info->watchdog);}/*====================================================================*/static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){    pcnet_dev_t *info = (pcnet_dev_t *)dev;    u16 *data = (u16 *)&rq->ifr_data;    ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;    switch (cmd) {    case SIOCDEVPRIVATE:	data[0] = info->phy_id;    case SIOCDEVPRIVATE+1:	data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f);	return 0;    case SIOCDEVPRIVATE+2:	if (!capable(CAP_NET_ADMIN))	    return -EPERM;	mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]);	return 0;    }    return -EOPNOTSUPP;}/*====================================================================*/static void dma_get_8390_hdr(struct net_device *dev,			     struct e8390_pkt_hdr *hdr,			     int ring_page){    ioaddr_t nic_base = dev->base_addr;    if (ei_status.dmaing) {	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."	       "[DMAstat:%1x][irqlock:%1x]\n",	       dev->name, ei_status.dmaing, ei_status.irqlock);	return;    }        ei_status.dmaing |= 0x01;    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);    outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);    outb_p(0, nic_base + EN0_RCNTHI);    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */    outb_p(ring_page, nic_base + EN0_RSARHI);    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);    insw(nic_base + PCNET_DATAPORT, hdr,	    sizeof(struct e8390_pkt_hdr)>>1);    /* Fix for big endian systems */    hdr->count = le16_to_cpu(hdr->count);    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */    ei_status.dmaing &= ~0x01;}/*====================================================================*/static void dma_block_input(struct net_device *dev, int count,			    struct sk_buff *skb, int ring_offset){    ioaddr_t nic_base = dev->base_addr;    int xfer_count = count;    char *buf = skb->data;#ifdef PCMCIA_DEBUG    if ((ei_debug > 4) && (count != 4))	printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4);#endif    if (ei_status.dmaing) {	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."	       "[DMAstat:%1x][irqlock:%1x]\n",	       dev->name, ei_status.dmaing, ei_status.irqlock);	return;    }    ei_status.dmaing |= 0x01;    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);    outb_p(count & 0xff, nic_base + EN0_RCNTLO);    outb_p(count >> 8, nic_base + EN0_RCNTHI);    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);    insw(nic_base + PCNET_DATAPORT,buf,count>>1);    if (count & 0x01)	buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++;    /* This was for the ALPHA version only, but enough people have       encountering problems that it is still here. */#ifdef PCMCIA_DEBUG    if (ei_debug > 4) {		/* DMA termination address check... */	int addr, tries = 20;	do {	    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here	       -- it's broken for Rx on some cards! */	    int high = inb_p(nic_base + EN0_RSARHI);	    int low = inb_p(nic_base + EN0_RSARLO);	    addr = (high << 8) + low;	    if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))		break;	} while (--tries > 0);	if (tries <= 0)	    printk(KERN_NOTICE "%s: RX transfer address mismatch,"		   "%#4.4x (expected) vs. %#4.4x (actual).\n",		   dev->name, ring_offset + xfer_count, addr);    }#endif    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */    ei_status.dmaing &= ~0x01;} /* dma_block_input *//*====================================================================*/static void dma_block_output(struct net_device *dev, int count,			     const u_char *buf, const int start_page){    ioaddr_t nic_base = dev->base_addr;    pcnet_dev_t *info = (pcnet_dev_t *)dev;#ifdef PCMCIA_DEBUG    int retries = 0;#endif    u_long dma_start;#ifdef PCMCIA_DEBUG    if (ei_debug > 4)	printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);#endif    /* Round the count up for word writes.  Do we need to do this?       What effect will an odd byte count have on the 8390?       I should check someday. */    if (count & 0x01)	count++;    if (ei_status.dmaing) {	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output."	       "[DMAstat:%1x][irqlock:%1x]\n",	       dev->name, ei_status.dmaing, ei_status.irqlock);	return;    }    ei_status.dmaing |= 0x01;    /* We should already be in page 0, but to be safe... */    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);#ifdef PCMCIA_DEBUG  retry:#endif    outb_p(ENISR_RDC, nic_base + EN0_ISR);    /* Now the normal output. */    outb_p(count & 0xff, nic_base + EN0_RCNTLO);    outb_p(count >> 8,   nic_base + EN0_RCNTHI);    outb_p(0x00, nic_base + EN0_RSARLO);    outb_p(start_page, nic_base + EN0_RSARHI);    outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);    outsw(nic_base + PCNET_DATAPORT, buf, count>>1);    dma_start = jiffies;#ifdef PCMCIA_DEBUG    /* This was for the ALPHA version only, but enough people have       encountering problems that it is still here. */    if (ei_debug > 4) {	/* DMA termination address check... */	int addr, tries = 20;	do {	    int high = inb_p(nic_base + EN0_RSARHI);	    int low = inb_p(nic_base + EN0_RSARLO);	    addr = (high << 8) + low;	    if ((start_page << 8) + count == addr)		break;	} while (--tries > 0);	if (tries <= 0) {	    printk(KERN_NOTICE "%s: Tx packet transfer address mismatch,"		   "%#4.4x (expected) vs. %#4.4x (actual).\n",		   dev->name, (start_page << 8) + count, addr);	    if (retries++ == 0)		goto retry;	}    }#endif    while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)	if (jiffies - dma_start > PCNET_RDC_TIMEOUT) {	    printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",		   dev->name);	    pcnet_reset_8390(dev);	    NS8390_init(dev, 1);	    break;	}    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */    if (info->flags & DELAY_OUTPUT)	udelay((long)delay_time);    ei_status.dmaing &= ~0x01;}/*====================================================================*/static int setup_dma_config(dev_link_t *link, int start_pg,			    int stop_pg){    struct net_device *dev = link->priv;    ei_status.tx_start_page = start_pg;    ei_status.rx_start_page = start_pg + TX_PAGES;    ei_status.stop_page = stop_pg;    /* set up block i/o functions */    ei_status.get_8390_hdr = &dma_get_8390_hdr;    ei_status.block_input = &dma_block_input;    ei_status.block_output = &dma_block_output;    return 0;}/*====================================================================*/static void copyin(u_char *dest, u_char *src, int c){    u_short *d = (u_short *)dest, *s = (u_short *)src;    int odd;    if (c <= 0)	return;    odd = (c & 1); c >>= 1;    if (c) {	do { *d++ = __raw_readw(s++); } while (--c);    }    /* get last byte by fetching a word and masking */    if (odd)	*((u_char *)d) = readw(s) & 0xff;}static void copyout(u_char *dest, const u_char *src, int c){    u_short *d = (u_short *)dest, *s = (u_short *)src;    int odd;    if (c <= 0)	return;    odd = (c & 1); c >>= 1;    if (c) {	do { __raw_writew(*s++, d++); } while (--c);    }    /* copy last byte doing a read-modify-write */    if (odd)	writew((readw(d) & 0xff00) | *(u_char *)s, d);}/*====================================================================*/static void shmem_get_8390_hdr(struct net_device *dev,			       struct e8390_pkt_hdr *hdr,			       int ring_page){    void *xfer_start = (void *)(dev->rmem_start + (ring_page << 8)				- (ei_status.rx_start_page << 8));        copyin((void *)hdr, xfer_start, sizeof(struct e8390_pkt_hdr));    /* Fix for big endian systems */    hdr->count = le16_to_cpu(hdr->count);}/*====================================================================*/static void shmem_block_input(struct net_device *dev, int count,			      struct sk_buff *skb, int ring_offset){    void *xfer_start = (void *)(dev->rmem_start + ring_offset				- (ei_status.rx_start_page << 8));    char *buf = skb->data;        if (xfer_start + count > (void *)dev->rmem_end) {	/* We must wrap the input move. */	int semi_count = (void*)dev->rmem_end - xfer_start;	copyin(buf, xfer_start, semi_count);	buf += semi_count;	ring_offset = ei_status.rx_start_page << 8;	xfer_start = (void *)dev->rmem_start;	count -= semi_count;    }    copyin(buf, xfer_start, count);}/*====================================================================*/static void shmem_block_output(struct net_device *dev, int count,			       const u_char *buf, const int start_page){    void *shmem = (void *)dev->mem_start + (start_page << 8);    shmem -= ei_status.tx_start_page << 8;    copyout(shmem, buf, count);}/*====================================================================*/static int setup_shmem_window(dev_link_t *link, int start_pg,			      int stop_pg, int cm_offset){    struct net_device *dev = link->priv;    pcnet_dev_t *info = link->priv;    win_req_t req;    memreq_t mem;    int i, window_size, offset, last_ret, last_fn;    window_size = (stop_pg - start_pg) << 8;    if (window_size > 32 * 1024)	window_size = 32 * 1024;    /* Make sure it's a power of two.  */    while ((window_size & (window_size - 1)) != 0)	window_size += window_size & ~(window_size - 1);    /* Allocate a memory window */    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;    req.Attributes |= WIN_USE_WAIT;    req.Base = 0; req.Size = window_size;    req.AccessSpeed = mem_speed;    link->win = (window_handle_t)link->handle;    CS_CHECK(RequestWindow, &link->win, &req);    mem.CardOffset = (start_pg << 8) + cm_offset;    offset = mem.CardOffset % window_size;    mem.CardOffset -= offset;    mem.Page = 0;    CS_CHECK(MapMemPage, link->win, &mem);    /* Try scribbling on the buffer */    info->base = ioremap(req.Base, window_size);    for (i = 0; i < (TX_PAGES<<8); i += 2)	__raw_writew((i>>1), info->base+offset+i);    udelay(100);    for (i = 0; i < (TX_PAGES<<8); i += 2)	if (__raw_readw(info->base+offset+i) != (i>>1)) break;    pcnet_reset_8390(dev);    if (i != (TX_PAGES<<8)) {	iounmap(info->base);	CardServices(ReleaseWindow, link->win);	info->base = NULL; link->win = NULL;	goto failed;    }        dev->mem_start = (u_long)info->base + offset;    dev->rmem_start = dev->mem_start + (TX_PAGES<<8);    dev->mem_end = dev->rmem_end = (u_long)info->base + req.Size;    ei_status.tx_start_page = start_pg;    ei_status.rx_start_page = start_pg + TX_PAGES;    ei_status.stop_page = start_pg + ((req.Size - offset) >> 8);    /* set up block i/o functions */    ei_status.get_8390_hdr = &shmem_get_8390_hdr;    ei_status.block_input = &shmem_block_input;    ei_status.block_output = &shmem_block_output;    info->flags |= USE_SHMEM;    return 0;cs_failed:    cs_error(link->handle, last_fn, last_ret);failed:    return 1;}/*====================================================================*/static int __init init_pcnet_cs(void){    servinfo_t serv;    DEBUG(0, "%s\n", version);    CardServices(GetCardServicesInfo, &serv);    if (serv.Revision != CS_RELEASE_CODE) {	printk(KERN_NOTICE "pcnet_cs: Card Services release "	       "does not match!\n");	return -1;    }    register_pccard_driver(&dev_info, &pcnet_attach, &pcnet_detach);    return 0;}static void __exit exit_pcnet_cs(void){    DEBUG(0, "pcnet_cs: unloading\n");    unregister_pccard_driver(&dev_info);    while (dev_list != NULL)	pcnet_detach(dev_list);}module_init(init_pcnet_cs);module_exit(exit_pcnet_cs);

⌨️ 快捷键说明

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