📄 nmclan_cs.c
字号:
static void nmclan_detach(dev_link_t *);/* ----------------------------------------------------------------------------flush_stale_links Clean up stale device structures---------------------------------------------------------------------------- */static void flush_stale_links(void){ dev_link_t *link, *next; for (link = dev_list; link; link = next) { next = link->next; if (link->state & DEV_STALE_LINK) nmclan_detach(link); }}/* ----------------------------------------------------------------------------cs_error Report a Card Services related error.---------------------------------------------------------------------------- */static void cs_error(client_handle_t handle, int func, int ret){ error_info_t err = { func, ret }; CardServices(ReportError, handle, &err);}/* ----------------------------------------------------------------------------nmclan_attach Creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services.---------------------------------------------------------------------------- */static dev_link_t *nmclan_attach(void){ mace_private *lp; dev_link_t *link; struct net_device *dev; client_reg_t client_reg; int i, ret; DEBUG(0, "nmclan_attach()\n"); DEBUG(1, "%s\n", rcsid); flush_stale_links(); /* Create new ethernet device */ lp = kmalloc(sizeof(*lp), GFP_KERNEL); if (!lp) return NULL; memset(lp, 0, sizeof(*lp)); link = &lp->link; dev = &lp->dev; link->priv = dev->priv = link->irq.Instance = lp; link->release.function = &nmclan_release; link->release.data = (u_long)link; link->io.NumPorts1 = 32; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 5; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = &mace_interrupt; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; lp->tx_free_frames=AM2150_MAX_TX_FRAMES; dev->hard_start_xmit = &mace_start_xmit; dev->set_config = &mace_config; dev->get_stats = &mace_get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); init_dev_name(dev, lp->node); dev->open = &mace_open; dev->stop = &mace_close;#ifdef HAVE_TX_TIMEOUT dev->tx_timeout = mace_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT;#endif /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &nmclan_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); nmclan_detach(link); return NULL; } return link;} /* nmclan_attach *//* ----------------------------------------------------------------------------nmclan_detach This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released.---------------------------------------------------------------------------- */static void nmclan_detach(dev_link_t *link){ mace_private *lp = link->priv; dev_link_t **linkp; DEBUG(0, "nmclan_detach(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; del_timer(&link->release); if (link->state & DEV_CONFIG) { nmclan_release((u_long)link); if (link->state & DEV_STALE_CONFIG) { link->state |= DEV_STALE_LINK; return; } } if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ *linkp = link->next; if (link->dev) unregister_netdev(&lp->dev); kfree(lp);} /* nmclan_detach *//* ----------------------------------------------------------------------------mace_read Reads a MACE register. This is bank independent; however, the caller must ensure that this call is not interruptable. We are assuming that during normal operation, the MACE is always in bank 0.---------------------------------------------------------------------------- */static int mace_read(ioaddr_t ioaddr, int reg){ int data = 0xFF; unsigned long flags; switch (reg >> 4) { case 0: /* register 0-15 */ data = inb(ioaddr + AM2150_MACE_BASE + reg); break; case 1: /* register 16-31 */ save_flags(flags); cli(); MACEBANK(1); data = inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); MACEBANK(0); restore_flags(flags); break; } return (data & 0xFF);} /* mace_read *//* ----------------------------------------------------------------------------mace_write Writes to a MACE register. This is bank independent; however, the caller must ensure that this call is not interruptable. We are assuming that during normal operation, the MACE is always in bank 0.---------------------------------------------------------------------------- */static void mace_write(ioaddr_t ioaddr, int reg, int data){ unsigned long flags; switch (reg >> 4) { case 0: /* register 0-15 */ outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg); break; case 1: /* register 16-31 */ save_flags(flags); cli(); MACEBANK(1); outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); MACEBANK(0); restore_flags(flags); break; }} /* mace_write *//* ----------------------------------------------------------------------------mace_init Resets the MACE chip.---------------------------------------------------------------------------- */static void mace_init(ioaddr_t ioaddr, char *enet_addr){ int i; /* MACE Software reset */ mace_write(ioaddr, MACE_BIUCC, 1); while (mace_read(ioaddr, MACE_BIUCC) & 0x01) { /* Wait for reset bit to be cleared automatically after <= 200ns */; } mace_write(ioaddr, MACE_BIUCC, 0); /* The Am2150 requires that the MACE FIFOs operate in burst mode. */ mace_write(ioaddr, MACE_FIFOCC, 0x0F); mace_write(ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */ mace_write(ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until _open */ /* * Bit 2-1 PORTSEL[1-0] Port Select. * 00 AUI/10Base-2 * 01 10Base-T * 10 DAI Port (reserved in Am2150) * 11 GPSI * For this card, only the first two are valid. * So, PLSCC should be set to * 0x00 for 10Base-2 * 0x02 for 10Base-T * Or just set ASEL in PHYCC below! */ switch (if_port) { case 1: mace_write(ioaddr, MACE_PLSCC, 0x02); break; case 2: mace_write(ioaddr, MACE_PLSCC, 0x00); break; default: mace_write(ioaddr, MACE_PHYCC, /* ASEL */ 4); /* ASEL Auto Select. When set, the PORTSEL[1-0] bits are overridden, and the MACE device will automatically select the operating media interface port. */ break; } mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR); /* Poll ADDRCHG bit */ while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) ; /* Set PADR register */ for (i = 0; i < ETHER_ADDR_LEN; i++) mace_write(ioaddr, MACE_PADR, enet_addr[i]); /* MAC Configuration Control Register should be written last */ /* Let set_multicast_list set this. */ /* mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */ mace_write(ioaddr, MACE_MACCC, 0x00);} /* mace_init *//* ----------------------------------------------------------------------------nmclan_config This routine is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system.---------------------------------------------------------------------------- */#define CS_CHECK(fn, args...) \while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failedstatic void nmclan_config(dev_link_t *link){ client_handle_t handle = link->handle; mace_private *lp = link->priv; struct net_device *dev = &lp->dev; tuple_t tuple; cisparse_t parse; u_char buf[64]; int i, last_ret, last_fn; ioaddr_t ioaddr; DEBUG(0, "nmclan_config(0x%p)\n", link); tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, handle, &tuple); CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; /* Configure card */ link->state |= DEV_CONFIG; CS_CHECK(RequestIO, handle, &link->io); CS_CHECK(RequestIRQ, handle, &link->irq); CS_CHECK(RequestConfiguration, handle, &link->conf); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; i = register_netdev(dev); if (i != 0) { printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); goto failed; } ioaddr = dev->base_addr; /* Read the ethernet address from the CIS. */ tuple.DesiredTuple = 0x80 /* CISTPL_CFTABLE_ENTRY_MISC */; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, handle, &tuple); CS_CHECK(GetTupleData, handle, &tuple); memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN); /* Verify configuration by reading the MACE ID. */ { char sig[2]; sig[0] = mace_read(ioaddr, MACE_CHIPIDL); sig[1] = mace_read(ioaddr, MACE_CHIPIDH); if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) { DEBUG(0, "nmclan_cs configured: mace id=%x %x\n", sig[0], sig[1]); } else { printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should" " be 0x40 0x?9\n", sig[0], sig[1]); link->state &= ~DEV_CONFIG_PENDING; return; } } mace_init(ioaddr, dev->dev_addr); /* The if_port symbol can be set when the module is loaded */ if (if_port <= 2) dev->if_port = if_port; else printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");#if 0 /* Determine which port we are using if auto is selected */ if (if_port==0) { mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); DEBUG(2, "%s: mace_phycc 0x%X.\n", dev->name, mace_read(ioaddr, MACE_PHYCC)); if (mace_read(ioaddr, MACE_PHYCC) & MACE_PHYCC_LNKFL) /* 10base-T receiver is in link fail, MACE is using AUI port. */ dev->if_port = 2; else dev->if_port = 1; mace_write(ioaddr, MACE_MACCC, 0x00); } /* Unfortunately, this doesn't seem to work. LNKFL is always set. LNKFL is supposed to be opposite the green LED on the edge of the card. It doesn't work if it is checked and printed in _open() either. It does work if check in _start_xmit(), but that's not a good place to printk. */#endif copy_dev_name(lp->node, dev); link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ", dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); return;cs_failed: cs_error(link->handle, last_fn, last_ret);failed: nmclan_release((u_long)link); link->state &= ~DEV_CONFIG_PENDING; return;} /* nmclan_config *//* ----------------------------------------------------------------------------nmclan_release After a card is removed, nmclan_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 void nmclan_release(u_long arg){ dev_link_t *link = (dev_link_t *)arg; DEBUG(0, "nmclan_release(0x%p)\n", link); if (link->open) { DEBUG(1, "nmclan_cs: release postponed, '%s' " "still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG;} /* nmclan_release *//* ----------------------------------------------------------------------------nmclan_event 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.---------------------------------------------------------------------------- */static int nmclan_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; mace_private *lp = link->priv; struct net_device *dev = &lp->dev; DEBUG(1, "nmclan_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -