📄 xirc2ps_cs.c
字号:
*/ reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_0; reg.Value = link->io.BasePort2 & 0xff; if ((err = pcmcia_access_configuration_register(link->handle, ®))) { cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_1; reg.Value = (link->io.BasePort2 >> 8) & 0xff; if ((err = pcmcia_access_configuration_register(link->handle, ®))) { cs_error(link->handle, AccessConfigurationRegister, err); goto config_error; } /* There is no config entry for the Ethernet part which * is at 0x0800. So we allocate a window into the attribute * memory and write direct to the CIS registers */ req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; if ((err = pcmcia_request_window(&link->handle, &req, &link->win))) { cs_error(link->handle, RequestWindow, err); goto config_error; } local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; mem.CardOffset = 0x0; mem.Page = 0; if ((err = pcmcia_map_mem_page(link->win, &mem))) { cs_error(link->handle, MapMemPage, err); goto config_error; } /* Setup the CCRs; there are no infos in the CIS about the Ethernet * part. */ writeb(0x47, local->dingo_ccr + CISREG_COR); ioaddr = link->io.BasePort1; writeb(ioaddr & 0xff , local->dingo_ccr + CISREG_IOBASE_0); writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1); #if 0 { u_char tmp; printk(KERN_INFO "ECOR:"); for (i=0; i < 7; i++) { tmp = readb(local->dingo_ccr + i*2); printk(" %02x", tmp); } printk("\n"); printk(KERN_INFO "DCOR:"); for (i=0; i < 4; i++) { tmp = readb(local->dingo_ccr + 0x20 + i*2); printk(" %02x", tmp); } printk("\n"); printk(KERN_INFO "SCOR:"); for (i=0; i < 10; i++) { tmp = readb(local->dingo_ccr + 0x40 + i*2); printk(" %02x", tmp); } printk("\n"); } #endif writeb(0x01, local->dingo_ccr + 0x20); writeb(0x0c, local->dingo_ccr + 0x22); writeb(0x00, local->dingo_ccr + 0x24); writeb(0x00, local->dingo_ccr + 0x26); writeb(0x00, local->dingo_ccr + 0x28); } /* The if_port symbol can be set when the module is loaded */ local->probe_port=0; if (!if_port) { local->probe_port = dev->if_port = 1; } else if ((if_port >= 1 && if_port <= 2) || (local->mohawk && if_port==4)) dev->if_port = if_port; else printk(KNOT_XIRC "invalid if_port requested\n"); /* we can now register the device with the net subsystem */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; if (local->dingo) do_reset(dev, 1); /* a kludge to make the cem56 work */ link->dev = &local->node; link->state &= ~DEV_CONFIG_PENDING; SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); link->dev = NULL; goto config_error; } strcpy(local->node.dev_name, dev->name); /* give some infos about the hardware */ printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr", dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq); for (i = 0; i < 6; i++) printk("%c%02X", i?':':' ', dev->dev_addr[i]); printk("\n"); return; config_error: link->state &= ~DEV_CONFIG_PENDING; xirc2ps_release(link); return; cis_error: printk(KNOT_XIRC "unable to parse CIS\n"); failure: link->state &= ~DEV_CONFIG_PENDING;} /* xirc2ps_config *//**************** * After a card is removed, xirc2ps_release() will unregister the net * device, and release the PCMCIA configuration. If the device is * still open, this will be postponed until it is closed. */static voidxirc2ps_release(dev_link_t *link){ DEBUG(0, "release(0x%p)\n", link); if (link->win) { struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); if (local->dingo) iounmap(local->dingo_ccr - 0x0800); pcmcia_release_window(link->win); } pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG;} /* xirc2ps_release *//*====================================================================*//**************** * The card status event handler. Mostly, this schedules other * stuff to run after an event is received. A CARD_REMOVAL event * also sets some flags to discourage the net drivers from trying * to talk to the card any more. * * When a CARD_REMOVAL event is received, we immediately set a flag * to block future accesses to this device. All the functions that * actually access the device should check this flag to make sure * the card is still present. */static intxirc2ps_event(event_t event, int priority, event_callback_args_t * args){ dev_link_t *link = args->client_data; struct net_device *dev = link->priv; DEBUG(0, "event(%d)\n", (int)event); switch (event) { case CS_EVENT_REGISTRATION_COMPLETE: DEBUG(0, "registration complete\n"); break; case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) netif_device_detach(dev); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; xirc2ps_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { netif_device_detach(dev); do_powerdown(dev); } pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { do_reset(dev,1); netif_device_attach(dev); } } break; } return 0;} /* xirc2ps_event *//*====================================================================*//**************** * This is the Interrupt service route. */static irqreturn_txirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_id; local_info_t *lp = netdev_priv(dev); kio_addr_t ioaddr; u_char saved_page; unsigned bytes_rcvd; unsigned int_status, eth_status, rx_status, tx_status; unsigned rsr, pktlen; ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days * is this something to worry about? * -- on a laptop? */ if (!netif_device_present(dev)) return IRQ_HANDLED; ioaddr = dev->base_addr; if (lp->mohawk) { /* must disable the interrupt */ PutByte(XIRCREG_CR, 0); } DEBUG(6, "%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); saved_page = GetByte(XIRCREG_PR); /* Read the ISR to see whats the cause for the interrupt. * This also clears the interrupt flags on CE2 cards */ int_status = GetByte(XIRCREG_ISR); bytes_rcvd = 0; loop_entry: if (int_status == 0xff) { /* card may be ejected */ DEBUG(3, "%s: interrupt %d for dead card\n", dev->name, irq); goto leave; } eth_status = GetByte(XIRCREG_ESR); SelectPage(0x40); rx_status = GetByte(XIRCREG40_RXST0); PutByte(XIRCREG40_RXST0, (~rx_status & 0xff)); tx_status = GetByte(XIRCREG40_TXST0); tx_status |= GetByte(XIRCREG40_TXST1) << 8; PutByte(XIRCREG40_TXST0, 0); PutByte(XIRCREG40_TXST1, 0); DEBUG(3, "%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n", dev->name, int_status, eth_status, rx_status, tx_status); /***** receive section ******/ SelectPage(0); while (eth_status & FullPktRcvd) { rsr = GetByte(XIRCREG0_RSR); if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) { /* too many bytes received during this int, drop the rest of the * packets */ lp->stats.rx_dropped++; DEBUG(2, "%s: RX drop, too much done\n", dev->name); } else if (rsr & PktRxOk) { struct sk_buff *skb; pktlen = GetWord(XIRCREG0_RBC); bytes_rcvd += pktlen; DEBUG(5, "rsr=%#02x packet_length=%u\n", rsr, pktlen); skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */ if (!skb) { printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n", pktlen); lp->stats.rx_dropped++; } else { /* okay get the packet */ skb_reserve(skb, 2); if (lp->silicon == 0 ) { /* work around a hardware bug */ unsigned rhsa; /* receive start address */ SelectPage(5); rhsa = GetWord(XIRCREG5_RHSA0); SelectPage(0); rhsa += 3; /* skip control infos */ if (rhsa >= 0x8000) rhsa = 0; if (rhsa + pktlen > 0x8000) { unsigned i; u_char *buf = skb_put(skb, pktlen); for (i=0; i < pktlen ; i++, rhsa++) { buf[i] = GetByte(XIRCREG_EDP); if (rhsa == 0x8000) { rhsa = 0; i--; } } } else { insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), (pktlen+1)>>1); } } #if 0 else if (lp->mohawk) { /* To use this 32 bit access we should use * a manual optimized loop * Also the words are swapped, we can get more * performance by using 32 bit access and swapping * the words in a register. Will need this for cardbus * * Note: don't forget to change the ALLOC_SKB to .. +3 */ unsigned i; u_long *p = skb_put(skb, pktlen); register u_long a; kio_addr_t edpreg = ioaddr+XIRCREG_EDP-2; for (i=0; i < len ; i += 4, p++) { a = inl(edpreg); __asm__("rorl $16,%0\n\t" :"=q" (a) : "0" (a)); *p = a; } } #endif else { insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), (pktlen+1)>>1); } skb->protocol = eth_type_trans(skb, dev); skb->dev = dev; netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; if (!(rsr & PhyPkt)) lp->stats.multicast++; } } else { /* bad packet */ DEBUG(5, "rsr=%#02x\n", rsr); } if (rsr & PktTooLong) { lp->stats.rx_frame_errors++; DEBUG(3, "%s: Packet too long\n", dev->name); } if (rsr & CRCErr) { lp->stats.rx_crc_errors++; DEBUG(3, "%s: CRC error\n", dev->name); } if (rsr & AlignErr) { lp->stats.rx_fifo_errors++; /* okay ? */ DEBUG(3, "%s: Alignment error\n", dev->name); } /* clear the received/dropped/error packet */ PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ /* get the new ethernet status */ eth_status = GetByte(XIRCREG_ESR); } if (rx_status & 0x10) { /* Receive overrun */ lp->stats.rx_over_errors++; PutByte(XIRCREG_CR, ClearRxOvrun); DEBUG(3, "receive overrun cleared\n"); } /***** transmit section ******/ if (int_status & PktTxed) { unsigned n, nn; n = lp->last_ptr_value; nn = GetByte(XIRCREG0_PTR); lp->last_ptr_value = nn; if (nn < n) /* rollover */ lp->stats.tx_packets += 256 - n; else if (n == nn) { /* happens sometimes - don't know why */ DEBUG(0, "PTR not changed?\n"); } else lp->stats.tx_packets += lp->last_ptr_value - n; netif_wake_queue(dev); } if (tx_status & 0x0002) { /* Execessive collissions */ DEBUG(0, "tx restarted due to execssive collissions\n"); PutByte(XIRCREG_CR, RestartTx); /* restart transmitter process */ } if (tx_status & 0x0040) lp->stats.tx_aborted_errors++; /* recalculate our work chunk so that we limit the duration of this * ISR to about 1/10 of a second. * Calculate only if we received a reasonable amount of bytes. */ if (bytes_rcvd > 1000) { u_long duration = jiffies - start_ticks; if (duration >= HZ/10) { /* if more than about 1/10 second */ maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration; if (maxrx_bytes < 2000) maxrx_bytes = 2000; else if (maxrx_bytes > 22000) maxrx_bytes = 22000; DEBUG(1, "set maxrx=%u (rcvd=%u ticks=%lu)\n", maxrx_bytes, bytes_rcvd, duration); } else if (!duration && maxrx_bytes < 22000) { /* now much faster */ maxrx_bytes += 2000; if (maxrx_bytes > 22000) maxrx_bytes = 22000; DEBUG(1, "set maxrx=%u\n", maxrx_bytes); } } leave: if (lockup_hack) { if (int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0) goto loop_entry; } SelectPage(saved_page); PutByte(XIRCREG_CR, EnableIntr); /* re-enable interrupts */ /* Instead of dropping packets during a receive, we could * force an interrupt with this command: * PutByte(XIRCREG_CR, EnableIntr|ForceIntr); */ return IRQ_HANDLED;} /* xirc2ps_interrupt *//*====================================================================*/static voiddo_tx_timeout(struct net_device *dev){ local_info_t *lp = netdev_priv(dev); printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); lp->stats.tx_errors++; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; netif_wake_queue(dev);}static intdo_start_xmit(struct sk_buff *skb, struct net_device *dev){ local_info_t *lp = netdev_priv(dev); kio_addr_t ioaddr = dev->base_addr; int okay; unsigned freespace; unsigned pktlen = skb? skb->len : 0; DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", skb, dev, pktlen); /* adjust the packet length to min. required * and hope that the buffer is large enough * to provide some random data. * fixme: For Mohawk we can change this by sending * a larger packetlen than we actually have; the chip will * pad this in his buffer with random bytes */ if (pktlen < ETH_ZLEN) { skb = skb_padto(skb, ETH_ZLEN); if (skb == NULL) return 0; pktlen = ETH_ZLEN; } netif_stop_queue(dev); SelectPage(0); PutWord(XIRCREG0_TRS, (u_short)pktlen+2); freespace = GetWord(XIRCREG0_TSO); okay = freespace & 0x8000; freespace &= 0x7fff; /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ okay = pktlen +2 < freespace; DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ return 1; /* upper layer may decide to requeue this packet */ } /* send the packet */ PutWord(XIRCREG_EDP, (u_short)pktlen); outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1); if (pktlen & 1) PutByte(XIRCREG_EDP, skb->data[pktlen-1]); if (lp->mohawk) PutByte(XIRCREG_CR, TransmitPacket|EnableIntr); dev_kfree_skb (skb); dev->trans_start = jiffies; lp->stats.tx_bytes += pktlen; netif_start_queue(dev); return 0;}static struct net_device_stats *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -