📄 pcnet_cs.c
字号:
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 + -