+static int __devinit skge_probe_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ SK_AC *pAC;
+ DEV_NET *pNet = NULL;
+ struct net_device *dev = NULL;
+ static int boards_found = 0;
+ int error = -ENODEV;
+ int using_dac = 0;
+ char DeviceStr[80];
+
+ if (pci_enable_device(pdev))
+ goto out;
+
+ /* Configure DMA attributes. */
+ if (sizeof(dma_addr_t) > sizeof(u32) &&
+ !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+ using_dac = 1;
+ error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error < 0) {
+ printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+ "for consistent allocations\n", pci_name(pdev));
+ goto out_disable_device;
+ }
+ } else {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+ pci_name(pdev));
+ goto out_disable_device;
+ }
+ }
+
+ error = -ENOMEM;
+ dev = alloc_etherdev(sizeof(DEV_NET));
+ if (!dev) {
+ printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+ "structure!\n");
+ goto out_disable_device;
+ }
+
+ pNet = netdev_priv(dev);
+ pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
+ if (!pNet->pAC) {
+ printk(KERN_ERR "sk98lin: unable to allocate adapter "
+ "structure!\n");
+ goto out_free_netdev;
+ }
+
+ pAC = pNet->pAC;
+ pAC->PciDev = pdev;
+
+ pAC->dev[0] = dev;
+ pAC->dev[1] = dev;
+ pAC->CheckQueue = SK_FALSE;
+
+ dev->irq = pdev->irq;
+
+ error = SkGeInitPCI(pAC);
+ if (error) {
+ printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
+ goto out_free_netdev;
+ }
+
+ SET_MODULE_OWNER(dev);
+ dev->open = &SkGeOpen;
+ dev->stop = &SkGeClose;
+ dev->hard_start_xmit = &SkGeXmit;
+ dev->get_stats = &SkGeStats;
+ dev->set_multicast_list = &SkGeSetRxMode;
+ dev->set_mac_address = &SkGeSetMacAddr;
+ dev->do_ioctl = &SkGeIoctl;
+ dev->change_mtu = &SkGeChangeMtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = &SkGePollController;
+#endif
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+ /* Use only if yukon hardware */
+ if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+ dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+ dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+ pAC->RxPort[0].RxCsum = 1;
+#endif
+ }
+
+ if (using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ pAC->Index = boards_found++;
+
+ error = SkGeBoardInit(dev, pAC);
+ if (error)
+ goto out_free_netdev;
+
+ /* Read Adapter name from VPD */
+ if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+ error = -EIO;
+ printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
+ goto out_free_resources;
+ }
+
+ /* Register net device */
+ error = register_netdev(dev);
+ if (error) {
+ printk(KERN_ERR "sk98lin: Could not register device.\n");
+ goto out_free_resources;
+ }
+
+ /* Print adapter specific string from vpd */
+ printk("%s: %s\n", dev->name, DeviceStr);
+
+ /* Print configuration settings */
+ printk(" PrefPort:%c RlmtMode:%s\n",
+ 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber,
+ (pAC->RlmtMode==0) ? "Check Link State" :
+ ((pAC->RlmtMode==1) ? "Check Link State" :
+ ((pAC->RlmtMode==3) ? "Check Local Port" :
+ ((pAC->RlmtMode==7) ? "Check Segmentation" :
+ ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
+
+ SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+ memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ pNet->PortNr = 0;
+ pNet->NetNr = 0;
+
+ boards_found++;
+
+ pci_set_drvdata(pdev, dev);
+
+ /* More then one port found */
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ dev = alloc_etherdev(sizeof(DEV_NET));
+ if (!dev) {
+ printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+ "structure!\n");
+ goto single_port;
+ }
+
+ pNet = netdev_priv(dev);
+ pNet->PortNr = 1;
+ pNet->NetNr = 1;
+ pNet->pAC = pAC;
+
+ dev->open = &SkGeOpen;
+ dev->stop = &SkGeClose;
+ dev->hard_start_xmit = &SkGeXmit;
+ dev->get_stats = &SkGeStats;
+ dev->set_multicast_list = &SkGeSetRxMode;
+ dev->set_mac_address = &SkGeSetMacAddr;
+ dev->do_ioctl = &SkGeIoctl;
+ dev->change_mtu = &SkGeChangeMtu;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+ if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+ dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+ dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+ pAC->RxPort[1].RxCsum = 1;
+#endif
+ }
+
+ if (using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ error = register_netdev(dev);
+ if (error) {
+ printk(KERN_ERR "sk98lin: Could not register device"
+ " for second port. (%d)\n", error);
+ free_netdev(dev);
+ goto single_port;
+ }
+
+ pAC->dev[1] = dev;
+ memcpy(&dev->dev_addr,
+ &pAC->Addr.Net[1].CurrentMacAddress, 6);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ printk("%s: %s\n", dev->name, DeviceStr);
+ printk(" PrefPort:B RlmtMode:Dual Check Link State\n");
+ }
+
+single_port:
+
+ /* Save the hardware revision */
+ pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
+ (pAC->GIni.GIPciHwRev & 0x0F);
+
+ /* Set driver globals */
+ pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME;
+ pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE;
+
+ memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
+ memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
+
+ return 0;
+
+ out_free_resources:
+ FreeResources(dev);
+ out_free_netdev:
+ free_netdev(dev);
+ out_disable_device:
+ pci_disable_device(pdev);
+ out:
+ return error;
+}
+
+static void __devexit skge_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ struct net_device *otherdev = pAC->dev[1];
+
+ unregister_netdev(dev);
+
+ SkGeYellowLED(pAC, pAC->IoBase, 0);
+
+ if (pAC->BoardLevel == SK_INIT_RUN) {
+ SK_EVPARA EvPara;
+ unsigned long Flags;
+
+ /* board is still alive */
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ EvPara.Para32[0] = 0;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ EvPara.Para32[0] = 1;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ SkEventDispatcher(pAC, pAC->IoBase);
+ /* disable interrupts */
+ SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+ SkGeDeInit(pAC, pAC->IoBase);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ pAC->BoardLevel = SK_INIT_DATA;
+ /* We do NOT check here, if IRQ was pending, of course*/
+ }
+
+ if (pAC->BoardLevel == SK_INIT_IO) {
+ /* board is still alive */
+ SkGeDeInit(pAC, pAC->IoBase);
+ pAC->BoardLevel = SK_INIT_DATA;
+ }
+
+ FreeResources(dev);
+ free_netdev(dev);
+ if (otherdev != dev)
+ free_netdev(otherdev);
+ kfree(pAC);
+}
+
+#ifdef CONFIG_PM
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ struct net_device *otherdev = pAC->dev[1];
+
+ if (netif_running(dev)) {
+ netif_carrier_off(dev);
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */
+ netif_device_detach(dev);
+ }
+ if (otherdev != dev) {
+ if (netif_running(otherdev)) {
+ netif_carrier_off(otherdev);
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvDeInitAdapter(pAC, 1); /* performs SkGeClose */
+ netif_device_detach(otherdev);
+ }
+ }
+
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ if (pAC->AllocFlag & SK_ALLOC_IRQ) {
+ free_irq(dev->irq, dev);
+ }
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int skge_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ struct net_device *otherdev = pAC->dev[1];
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
+ if (pAC->GIni.GIMacsFound == 2)
+ ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+ else
+ ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
+ if (ret) {
+ printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
+ pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+ dev->irq = 0;
+ pci_disable_device(pdev);
+ return -EBUSY;
+ }
+
+ netif_device_attach(dev);
+ if (netif_running(dev)) {
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvInitAdapter(pAC, 0); /* first device */
+ }
+ if (otherdev != dev) {
+ netif_device_attach(otherdev);
+ if (netif_running(otherdev)) {
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvInitAdapter(pAC, 1); /* second device */
+ }
+ }
+
+ return 0;
+}
+#else
+#define skge_suspend NULL
+#define skge_resume NULL
+#endif
+
+static struct pci_device_id skge_pci_tbl[] = {
+ { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+/* DLink card does not have valid VPD so this driver gags
+ * { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ */
+ { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
+ { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
+
+static struct pci_driver skge_driver = {
+ .name = "sk98lin",
+ .id_table = skge_pci_tbl,
+ .probe = skge_probe_one,
+ .remove = __devexit_p(skge_remove_one),
+ .suspend = skge_suspend,
+ .resume = skge_resume,
+};
+
+static int __init skge_init(void)
+{
+ return pci_register_driver(&skge_driver);
+}
+
+static void __exit skge_exit(void)
+{
+ pci_unregister_driver(&skge_driver);
+}
+
+module_init(skge_init);
+module_exit(skge_exit);