| /************************************************************************** | |
| * | |
| * dmfe.c -- Etherboot device driver for the Davicom | |
| * DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast ethernet card | |
| * | |
| * Written 2003-2003 by Timothy Legge <tlegge@rogers.com> | |
| * | |
| * This program is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation; either version 2 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| * 02110-1301, USA. | |
| * | |
| * Portions of this code based on: | |
| * | |
| * dmfe.c: A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 | |
| * NIC fast ethernet driver for Linux. | |
| * Copyright (C) 1997 Sten Wang | |
| * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. | |
| * | |
| * | |
| * REVISION HISTORY: | |
| * ================ | |
| * v1.0 10-02-2004 timlegge Boots ltsp needs cleanup | |
| * | |
| * Indent Options: indent -kr -i8 | |
| * | |
| * | |
| ***************************************************************************/ | |
| FILE_LICENCE ( GPL2_OR_LATER ); | |
| /* to get some global routines like printf */ | |
| #include "etherboot.h" | |
| /* to get the interface to the body of the program */ | |
| #include "nic.h" | |
| /* to get the PCI support functions, if this is a PCI NIC */ | |
| #include <ipxe/pci.h> | |
| #include <ipxe/ethernet.h> | |
| /* #define EDEBUG 1 */ | |
| #ifdef EDEBUG | |
| #define dprintf(x) printf x | |
| #else | |
| #define dprintf(x) | |
| #endif | |
| /* Condensed operations for readability. */ | |
| #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) | |
| #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) | |
| /* Board/System/Debug information/definition ---------------- */ | |
| #define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */ | |
| #define PCI_DM9102_ID 0x91021282 /* Davicom DM9102 ID */ | |
| #define PCI_DM9100_ID 0x91001282 /* Davicom DM9100 ID */ | |
| #define PCI_DM9009_ID 0x90091282 /* Davicom DM9009 ID */ | |
| #define DM9102_IO_SIZE 0x80 | |
| #define DM9102A_IO_SIZE 0x100 | |
| #define TX_MAX_SEND_CNT 0x1 /* Maximum tx packet per time */ | |
| #define TX_DESC_CNT 0x10 /* Allocated Tx descriptors */ | |
| #define RX_DESC_CNT 0x20 /* Allocated Rx descriptors */ | |
| #define TX_FREE_DESC_CNT (TX_DESC_CNT - 2) /* Max TX packet count */ | |
| #define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3) /* TX wakeup count */ | |
| #define DESC_ALL_CNT (TX_DESC_CNT + RX_DESC_CNT) | |
| #define TX_BUF_ALLOC 0x600 | |
| #define RX_ALLOC_SIZE 0x620 | |
| #define DM910X_RESET 1 | |
| #define CR0_DEFAULT 0x00E00000 /* TX & RX burst mode */ | |
| #define CR6_DEFAULT 0x00080000 /* HD */ | |
| #define CR7_DEFAULT 0x180c1 | |
| #define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */ | |
| #define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */ | |
| #define MAX_PACKET_SIZE 1514 | |
| #define DMFE_MAX_MULTICAST 14 | |
| #define RX_COPY_SIZE 100 | |
| #define MAX_CHECK_PACKET 0x8000 | |
| #define DM9801_NOISE_FLOOR 8 | |
| #define DM9802_NOISE_FLOOR 5 | |
| #define DMFE_10MHF 0 | |
| #define DMFE_100MHF 1 | |
| #define DMFE_10MFD 4 | |
| #define DMFE_100MFD 5 | |
| #define DMFE_AUTO 8 | |
| #define DMFE_1M_HPNA 0x10 | |
| #define DMFE_TXTH_72 0x400000 /* TX TH 72 byte */ | |
| #define DMFE_TXTH_96 0x404000 /* TX TH 96 byte */ | |
| #define DMFE_TXTH_128 0x0000 /* TX TH 128 byte */ | |
| #define DMFE_TXTH_256 0x4000 /* TX TH 256 byte */ | |
| #define DMFE_TXTH_512 0x8000 /* TX TH 512 byte */ | |
| #define DMFE_TXTH_1K 0xC000 /* TX TH 1K byte */ | |
| #define DMFE_TIMER_WUT (jiffies + HZ * 1) /* timer wakeup time : 1 second */ | |
| #define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ | |
| #define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ | |
| #define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) | |
| #define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); | |
| /* CR9 definition: SROM/MII */ | |
| #define CR9_SROM_READ 0x4800 | |
| #define CR9_SRCS 0x1 | |
| #define CR9_SRCLK 0x2 | |
| #define CR9_CRDOUT 0x8 | |
| #define SROM_DATA_0 0x0 | |
| #define SROM_DATA_1 0x4 | |
| #define PHY_DATA_1 0x20000 | |
| #define PHY_DATA_0 0x00000 | |
| #define MDCLKH 0x10000 | |
| #define PHY_POWER_DOWN 0x800 | |
| #define SROM_V41_CODE 0x14 | |
| #define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5); | |
| #define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE | |
| #define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) | |
| /* Sten Check */ | |
| #define DEVICE net_device | |
| /* Structure/enum declaration ------------------------------- */ | |
| struct tx_desc { | |
| u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ | |
| void * tx_buf_ptr; /* Data for us */ | |
| struct tx_desc * next_tx_desc; | |
| } __attribute__ ((aligned(32))); | |
| struct rx_desc { | |
| u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ | |
| void * rx_skb_ptr; /* Data for us */ | |
| struct rx_desc * next_rx_desc; | |
| } __attribute__ ((aligned(32))); | |
| static struct dmfe_private { | |
| u32 chip_id; /* Chip vendor/Device ID */ | |
| u32 chip_revision; /* Chip revision */ | |
| u32 cr0_data; | |
| // u32 cr5_data; | |
| u32 cr6_data; | |
| u32 cr7_data; | |
| u32 cr15_data; | |
| u16 HPNA_command; /* For HPNA register 16 */ | |
| u16 HPNA_timer; /* For HPNA remote device check */ | |
| u16 NIC_capability; /* NIC media capability */ | |
| u16 PHY_reg4; /* Saved Phyxcer register 4 value */ | |
| u8 HPNA_present; /* 0:none, 1:DM9801, 2:DM9802 */ | |
| u8 chip_type; /* Keep DM9102A chip type */ | |
| u8 media_mode; /* user specify media mode */ | |
| u8 op_mode; /* real work media mode */ | |
| u8 phy_addr; | |
| u8 dm910x_chk_mode; /* Operating mode check */ | |
| /* NIC SROM data */ | |
| unsigned char srom[128]; | |
| /* Etherboot Only */ | |
| u8 cur_tx; | |
| u8 cur_rx; | |
| } dfx; | |
| static struct dmfe_private *db; | |
| enum dmfe_offsets { | |
| DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20, | |
| DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48, | |
| DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = | |
| 0x70, | |
| DCR15 = 0x78 | |
| }; | |
| enum dmfe_CR6_bits { | |
| CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, | |
| CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000, | |
| CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000 | |
| }; | |
| /* Global variable declaration ----------------------------- */ | |
| static struct nic_operations dmfe_operations; | |
| static unsigned char dmfe_media_mode = DMFE_AUTO; | |
| static u32 dmfe_cr6_user_set; | |
| /* For module input parameter */ | |
| static u8 chkmode = 1; | |
| static u8 HPNA_mode; /* Default: Low Power/High Speed */ | |
| static u8 HPNA_rx_cmd; /* Default: Disable Rx remote command */ | |
| static u8 HPNA_tx_cmd; /* Default: Don't issue remote command */ | |
| static u8 HPNA_NoiseFloor; /* Default: HPNA NoiseFloor */ | |
| static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control | |
| 4: TX pause packet */ | |
| /********************************************** | |
| * Descriptor Ring and Buffer defination | |
| ***********************************************/ | |
| struct dmfe_bss { | |
| struct tx_desc txd[TX_DESC_CNT] __attribute__ ((aligned(32))); | |
| unsigned char txb[TX_BUF_ALLOC * TX_DESC_CNT] | |
| __attribute__ ((aligned(32))); | |
| struct rx_desc rxd[RX_DESC_CNT] __attribute__ ((aligned(32))); | |
| unsigned char rxb[RX_ALLOC_SIZE * RX_DESC_CNT] | |
| __attribute__ ((aligned(32))); | |
| }; | |
| #define dmfe_bufs NIC_FAKE_BSS ( struct dmfe_bss ) | |
| #define txd dmfe_bufs.txd | |
| #define txb dmfe_bufs.txb | |
| #define rxd dmfe_bufs.rxd | |
| #define rxb dmfe_bufs.rxb | |
| /* NIC specific static variables go here */ | |
| static long int BASE; | |
| static u16 read_srom_word(long ioaddr, int offset); | |
| static void dmfe_init_dm910x(struct nic *nic); | |
| static void dmfe_descriptor_init(struct nic *, unsigned long ioaddr); | |
| static void update_cr6(u32, unsigned long); | |
| static void send_filter_frame(struct nic *nic); | |
| static void dm9132_id_table(struct nic *nic); | |
| static u16 phy_read(unsigned long, u8, u8, u32); | |
| static void phy_write(unsigned long, u8, u8, u16, u32); | |
| static void phy_write_1bit(unsigned long, u32); | |
| static u16 phy_read_1bit(unsigned long); | |
| static void dmfe_set_phyxcer(struct nic *nic); | |
| static void dmfe_parse_srom(struct nic *nic); | |
| static void dmfe_program_DM9801(struct nic *nic, int); | |
| static void dmfe_program_DM9802(struct nic *nic); | |
| static void dmfe_reset(struct nic *nic) | |
| { | |
| /* system variable init */ | |
| db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set; | |
| db->NIC_capability = 0xf; /* All capability */ | |
| db->PHY_reg4 = 0x1e0; | |
| /* CR6 operation mode decision */ | |
| if (!chkmode || (db->chip_id == PCI_DM9132_ID) || | |
| (db->chip_revision >= 0x02000030)) { | |
| db->cr6_data |= DMFE_TXTH_256; | |
| db->cr0_data = CR0_DEFAULT; | |
| db->dm910x_chk_mode = 4; /* Enter the normal mode */ | |
| } else { | |
| db->cr6_data |= CR6_SFT; /* Store & Forward mode */ | |
| db->cr0_data = 0; | |
| db->dm910x_chk_mode = 1; /* Enter the check mode */ | |
| } | |
| /* Initialize DM910X board */ | |
| dmfe_init_dm910x(nic); | |
| return; | |
| } | |
| /* Initialize DM910X board | |
| * Reset DM910X board | |
| * Initialize TX/Rx descriptor chain structure | |
| * Send the set-up frame | |
| * Enable Tx/Rx machine | |
| */ | |
| static void dmfe_init_dm910x(struct nic *nic) | |
| { | |
| unsigned long ioaddr = BASE; | |
| /* Reset DM910x MAC controller */ | |
| outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */ | |
| udelay(100); | |
| outl(db->cr0_data, ioaddr + DCR0); | |
| udelay(5); | |
| /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */ | |
| db->phy_addr = 1; | |
| /* Parser SROM and media mode */ | |
| dmfe_parse_srom(nic); | |
| db->media_mode = dmfe_media_mode; | |
| /* RESET Phyxcer Chip by GPR port bit 7 */ | |
| outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ | |
| if (db->chip_id == PCI_DM9009_ID) { | |
| outl(0x80, ioaddr + DCR12); /* Issue RESET signal */ | |
| mdelay(300); /* Delay 300 ms */ | |
| } | |
| outl(0x0, ioaddr + DCR12); /* Clear RESET signal */ | |
| /* Process Phyxcer Media Mode */ | |
| if (!(db->media_mode & 0x10)) /* Force 1M mode */ | |
| dmfe_set_phyxcer(nic); | |
| /* Media Mode Process */ | |
| if (!(db->media_mode & DMFE_AUTO)) | |
| db->op_mode = db->media_mode; /* Force Mode */ | |
| /* Initiliaze Transmit/Receive descriptor and CR3/4 */ | |
| dmfe_descriptor_init(nic, ioaddr); | |
| /* tx descriptor start pointer */ | |
| outl(virt_to_le32desc(&txd[0]), ioaddr + DCR4); /* TX DESC address */ | |
| /* rx descriptor start pointer */ | |
| outl(virt_to_le32desc(&rxd[0]), ioaddr + DCR3); /* RX DESC address */ | |
| /* Init CR6 to program DM910x operation */ | |
| update_cr6(db->cr6_data, ioaddr); | |
| /* Send setup frame */ | |
| if (db->chip_id == PCI_DM9132_ID) { | |
| dm9132_id_table(nic); /* DM9132 */ | |
| } else { | |
| send_filter_frame(nic); /* DM9102/DM9102A */ | |
| } | |
| /* Init CR7, interrupt active bit */ | |
| db->cr7_data = CR7_DEFAULT; | |
| outl(db->cr7_data, ioaddr + DCR7); | |
| /* Init CR15, Tx jabber and Rx watchdog timer */ | |
| outl(db->cr15_data, ioaddr + DCR15); | |
| /* Enable DM910X Tx/Rx function */ | |
| db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000; | |
| update_cr6(db->cr6_data, ioaddr); | |
| } | |
| #ifdef EDEBUG | |
| void hex_dump(const char *data, const unsigned int len); | |
| #endif | |
| /************************************************************************** | |
| POLL - Wait for a frame | |
| ***************************************************************************/ | |
| static int dmfe_poll(struct nic *nic, int retrieve) | |
| { | |
| u32 rdes0; | |
| int entry = db->cur_rx % RX_DESC_CNT; | |
| int rxlen; | |
| rdes0 = le32_to_cpu(rxd[entry].rdes0); | |
| if (rdes0 & 0x80000000) | |
| return 0; | |
| if (!retrieve) | |
| return 1; | |
| if ((rdes0 & 0x300) != 0x300) { | |
| /* A packet without First/Last flag */ | |
| printf("strange Packet\n"); | |
| rxd[entry].rdes0 = cpu_to_le32(0x80000000); | |
| return 0; | |
| } else { | |
| /* A packet with First/Last flag */ | |
| rxlen = ((rdes0 >> 16) & 0x3fff) - 4; | |
| /* error summary bit check */ | |
| if (rdes0 & 0x8000) { | |
| printf("Error\n"); | |
| return 0; | |
| } | |
| if (!(rdes0 & 0x8000) || | |
| ((db->cr6_data & CR6_PM) && (rxlen > 6))) { | |
| if (db->dm910x_chk_mode & 1) | |
| printf("Silly check mode\n"); | |
| nic->packetlen = rxlen; | |
| memcpy(nic->packet, rxb + (entry * RX_ALLOC_SIZE), | |
| nic->packetlen); | |
| } | |
| } | |
| rxd[entry].rdes0 = cpu_to_le32(0x80000000); | |
| db->cur_rx++; | |
| return 1; | |
| } | |
| static void dmfe_irq(struct nic *nic __unused, irq_action_t action __unused) | |
| { | |
| switch ( action ) { | |
| case DISABLE : | |
| break; | |
| case ENABLE : | |
| break; | |
| case FORCE : | |
| break; | |
| } | |
| } | |
| /************************************************************************** | |
| TRANSMIT - Transmit a frame | |
| ***************************************************************************/ | |
| static void dmfe_transmit(struct nic *nic, | |
| const char *dest, /* Destination */ | |
| unsigned int type, /* Type */ | |
| unsigned int size, /* size */ | |
| const char *packet) /* Packet */ | |
| { | |
| u16 nstype; | |
| u8 *ptxb; | |
| ptxb = &txb[db->cur_tx]; | |
| /* Stop Tx */ | |
| outl(0, BASE + DCR7); | |
| memcpy(ptxb, dest, ETH_ALEN); | |
| memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); | |
| nstype = htons((u16) type); | |
| memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); | |
| memcpy(ptxb + ETH_HLEN, packet, size); | |
| size += ETH_HLEN; | |
| while (size < ETH_ZLEN) | |
| ptxb[size++] = '\0'; | |
| /* setup the transmit descriptor */ | |
| txd[db->cur_tx].tdes1 = cpu_to_le32(0xe1000000 | size); | |
| txd[db->cur_tx].tdes0 = cpu_to_le32(0x80000000); /* give ownership to device */ | |
| /* immediate transmit demand */ | |
| outl(0x1, BASE + DCR1); | |
| outl(db->cr7_data, BASE + DCR7); | |
| /* Point to next TX descriptor */ | |
| db->cur_tx++; | |
| db->cur_tx = db->cur_tx % TX_DESC_CNT; | |
| } | |
| /************************************************************************** | |
| DISABLE - Turn off ethernet interface | |
| ***************************************************************************/ | |
| static void dmfe_disable ( struct nic *nic __unused, void *hwdev __unused ) { | |
| /* Reset & stop DM910X board */ | |
| outl(DM910X_RESET, BASE + DCR0); | |
| udelay(5); | |
| phy_write(BASE, db->phy_addr, 0, 0x8000, db->chip_id); | |
| } | |
| /************************************************************************** | |
| PROBE - Look for an adapter, this routine's visible to the outside | |
| ***************************************************************************/ | |
| #define board_found 1 | |
| #define valid_link 0 | |
| static int dmfe_probe ( struct nic *nic, struct pci_device *pci ) { | |
| uint32_t dev_rev, pci_pmr; | |
| int i; | |
| if (pci->ioaddr == 0) | |
| return 0; | |
| BASE = pci->ioaddr; | |
| printf("dmfe.c: Found %s Vendor=0x%hX Device=0x%hX\n", | |
| pci->id->name, pci->vendor, pci->device); | |
| /* Read Chip revision */ | |
| pci_read_config_dword(pci, PCI_REVISION, &dev_rev); | |
| dprintf(("Revision %lX\n", dev_rev)); | |
| /* point to private storage */ | |
| db = &dfx; | |
| db->chip_id = ((u32) pci->device << 16) | pci->vendor; | |
| BASE = pci_bar_start(pci, PCI_BASE_ADDRESS_0); | |
| db->chip_revision = dev_rev; | |
| pci_read_config_dword(pci, 0x50, &pci_pmr); | |
| pci_pmr &= 0x70000; | |
| if ((pci_pmr == 0x10000) && (dev_rev == 0x02000031)) | |
| db->chip_type = 1; /* DM9102A E3 */ | |
| else | |
| db->chip_type = 0; | |
| dprintf(("Chip type : %d\n", db->chip_type)); | |
| /* read 64 word srom data */ | |
| for (i = 0; i < 64; i++) | |
| ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(BASE, i)); | |
| /* Set Node address */ | |
| for (i = 0; i < 6; i++) | |
| nic->node_addr[i] = db->srom[20 + i]; | |
| /* Print out some hardware info */ | |
| DBG ( "%s: %s at ioaddr %4.4lx\n", | |
| pci->id->name, eth_ntoa ( nic->node_addr ), BASE ); | |
| /* Set the card as PCI Bus Master */ | |
| adjust_pci_device(pci); | |
| dmfe_reset(nic); | |
| nic->irqno = 0; | |
| nic->ioaddr = pci->ioaddr; | |
| /* point to NIC specific routines */ | |
| nic->nic_op = &dmfe_operations; | |
| return 1; | |
| } | |
| /* | |
| * Initialize transmit/Receive descriptor | |
| * Using Chain structure, and allocate Tx/Rx buffer | |
| */ | |
| static void dmfe_descriptor_init(struct nic *nic __unused, unsigned long ioaddr) | |
| { | |
| int i; | |
| db->cur_tx = 0; | |
| db->cur_rx = 0; | |
| /* tx descriptor start pointer */ | |
| outl(virt_to_le32desc(&txd[0]), ioaddr + DCR4); /* TX DESC address */ | |
| /* rx descriptor start pointer */ | |
| outl(virt_to_le32desc(&rxd[0]), ioaddr + DCR3); /* RX DESC address */ | |
| /* Init Transmit chain */ | |
| for (i = 0; i < TX_DESC_CNT; i++) { | |
| txd[i].tx_buf_ptr = &txb[i]; | |
| txd[i].tdes0 = cpu_to_le32(0); | |
| txd[i].tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ | |
| txd[i].tdes2 = cpu_to_le32(virt_to_bus(&txb[i])); | |
| txd[i].tdes3 = cpu_to_le32(virt_to_bus(&txd[i + 1])); | |
| txd[i].next_tx_desc = &txd[i + 1]; | |
| } | |
| /* Mark the last entry as wrapping the ring */ | |
| txd[i - 1].tdes3 = virt_to_le32desc(&txd[0]); | |
| txd[i - 1].next_tx_desc = &txd[0]; | |
| /* receive descriptor chain */ | |
| for (i = 0; i < RX_DESC_CNT; i++) { | |
| rxd[i].rx_skb_ptr = &rxb[i * RX_ALLOC_SIZE]; | |
| rxd[i].rdes0 = cpu_to_le32(0x80000000); | |
| rxd[i].rdes1 = cpu_to_le32(0x01000600); | |
| rxd[i].rdes2 = | |
| cpu_to_le32(virt_to_bus(&rxb[i * RX_ALLOC_SIZE])); | |
| rxd[i].rdes3 = cpu_to_le32(virt_to_bus(&rxd[i + 1])); | |
| rxd[i].next_rx_desc = &rxd[i + 1]; | |
| } | |
| /* Mark the last entry as wrapping the ring */ | |
| rxd[i - 1].rdes3 = cpu_to_le32(virt_to_bus(&rxd[0])); | |
| rxd[i - 1].next_rx_desc = &rxd[0]; | |
| } | |
| /* | |
| * Update CR6 value | |
| * Firstly stop DM910X , then written value and start | |
| */ | |
| static void update_cr6(u32 cr6_data, unsigned long ioaddr) | |
| { | |
| u32 cr6_tmp; | |
| cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */ | |
| outl(cr6_tmp, ioaddr + DCR6); | |
| udelay(5); | |
| outl(cr6_data, ioaddr + DCR6); | |
| udelay(5); | |
| } | |
| /* | |
| * Send a setup frame for DM9132 | |
| * This setup frame initialize DM910X address filter mode | |
| */ | |
| static void dm9132_id_table(struct nic *nic __unused) | |
| { | |
| #ifdef LINUX | |
| u16 *addrptr; | |
| u8 dmi_addr[8]; | |
| unsigned long ioaddr = BASE + 0xc0; /* ID Table */ | |
| u32 hash_val; | |
| u16 i, hash_table[4]; | |
| #endif | |
| dprintf(("dm9132_id_table\n")); | |
| printf("FIXME: This function is broken. If you have this card contact " | |
| "Timothy Legge at the etherboot-user list\n"); | |
| #ifdef LINUX | |
| //DMFE_DBUG(0, "dm9132_id_table()", 0); | |
| /* Node address */ | |
| addrptr = (u16 *) nic->node_addr; | |
| outw(addrptr[0], ioaddr); | |
| ioaddr += 4; | |
| outw(addrptr[1], ioaddr); | |
| ioaddr += 4; | |
| outw(addrptr[2], ioaddr); | |
| ioaddr += 4; | |
| /* Clear Hash Table */ | |
| for (i = 0; i < 4; i++) | |
| hash_table[i] = 0x0; | |
| /* broadcast address */ | |
| hash_table[3] = 0x8000; | |
| /* the multicast address in Hash Table : 64 bits */ | |
| for (mcptr = mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { | |
| hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f; | |
| hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); | |
| } | |
| /* Write the hash table to MAC MD table */ | |
| for (i = 0; i < 4; i++, ioaddr += 4) | |
| outw(hash_table[i], ioaddr); | |
| #endif | |
| } | |
| /* | |
| * Send a setup frame for DM9102/DM9102A | |
| * This setup frame initialize DM910X address filter mode | |
| */ | |
| static void send_filter_frame(struct nic *nic) | |
| { | |
| u8 *ptxb; | |
| int i; | |
| dprintf(("send_filter_frame\n")); | |
| /* point to the current txb incase multiple tx_rings are used */ | |
| ptxb = &txb[db->cur_tx]; | |
| /* construct perfect filter frame with mac address as first match | |
| and broadcast address for all others */ | |
| for (i = 0; i < 192; i++) | |
| ptxb[i] = 0xFF; | |
| ptxb[0] = nic->node_addr[0]; | |
| ptxb[1] = nic->node_addr[1]; | |
| ptxb[4] = nic->node_addr[2]; | |
| ptxb[5] = nic->node_addr[3]; | |
| ptxb[8] = nic->node_addr[4]; | |
| ptxb[9] = nic->node_addr[5]; | |
| /* prepare the setup frame */ | |
| txd[db->cur_tx].tdes1 = cpu_to_le32(0x890000c0); | |
| txd[db->cur_tx].tdes0 = cpu_to_le32(0x80000000); | |
| update_cr6(db->cr6_data | 0x2000, BASE); | |
| outl(0x1, BASE + DCR1); /* Issue Tx polling */ | |
| update_cr6(db->cr6_data, BASE); | |
| db->cur_tx++; | |
| } | |
| /* | |
| * Read one word data from the serial ROM | |
| */ | |
| static u16 read_srom_word(long ioaddr, int offset) | |
| { | |
| int i; | |
| u16 srom_data = 0; | |
| long cr9_ioaddr = ioaddr + DCR9; | |
| outl(CR9_SROM_READ, cr9_ioaddr); | |
| outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); | |
| /* Send the Read Command 110b */ | |
| SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr); | |
| SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr); | |
| SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr); | |
| /* Send the offset */ | |
| for (i = 5; i >= 0; i--) { | |
| srom_data = | |
| (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0; | |
| SROM_CLK_WRITE(srom_data, cr9_ioaddr); | |
| } | |
| outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); | |
| for (i = 16; i > 0; i--) { | |
| outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr); | |
| udelay(5); | |
| srom_data = | |
| (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 | |
| : 0); | |
| outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); | |
| udelay(5); | |
| } | |
| outl(CR9_SROM_READ, cr9_ioaddr); | |
| return srom_data; | |
| } | |
| /* | |
| * Auto sense the media mode | |
| */ | |
| #if 0 /* not used */ | |
| static u8 dmfe_sense_speed(struct nic *nic __unused) | |
| { | |
| u8 ErrFlag = 0; | |
| u16 phy_mode; | |
| /* CR6 bit18=0, select 10/100M */ | |
| update_cr6((db->cr6_data & ~0x40000), BASE); | |
| phy_mode = phy_read(BASE, db->phy_addr, 1, db->chip_id); | |
| phy_mode = phy_read(BASE, db->phy_addr, 1, db->chip_id); | |
| if ((phy_mode & 0x24) == 0x24) { | |
| if (db->chip_id == PCI_DM9132_ID) /* DM9132 */ | |
| phy_mode = | |
| phy_read(BASE, db->phy_addr, 7, | |
| db->chip_id) & 0xf000; | |
| else /* DM9102/DM9102A */ | |
| phy_mode = | |
| phy_read(BASE, db->phy_addr, 17, | |
| db->chip_id) & 0xf000; | |
| /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ | |
| switch (phy_mode) { | |
| case 0x1000: | |
| db->op_mode = DMFE_10MHF; | |
| break; | |
| case 0x2000: | |
| db->op_mode = DMFE_10MFD; | |
| break; | |
| case 0x4000: | |
| db->op_mode = DMFE_100MHF; | |
| break; | |
| case 0x8000: | |
| db->op_mode = DMFE_100MFD; | |
| break; | |
| default: | |
| db->op_mode = DMFE_10MHF; | |
| ErrFlag = 1; | |
| break; | |
| } | |
| } else { | |
| db->op_mode = DMFE_10MHF; | |
| //DMFE_DBUG(0, "Link Failed :", phy_mode); | |
| ErrFlag = 1; | |
| } | |
| return ErrFlag; | |
| } | |
| #endif | |
| /* | |
| * Set 10/100 phyxcer capability | |
| * AUTO mode : phyxcer register4 is NIC capability | |
| * Force mode: phyxcer register4 is the force media | |
| */ | |
| static void dmfe_set_phyxcer(struct nic *nic __unused) | |
| { | |
| u16 phy_reg; | |
| /* Select 10/100M phyxcer */ | |
| db->cr6_data &= ~0x40000; | |
| update_cr6(db->cr6_data, BASE); | |
| /* DM9009 Chip: Phyxcer reg18 bit12=0 */ | |
| if (db->chip_id == PCI_DM9009_ID) { | |
| phy_reg = | |
| phy_read(BASE, db->phy_addr, 18, | |
| db->chip_id) & ~0x1000; | |
| phy_write(BASE, db->phy_addr, 18, phy_reg, db->chip_id); | |
| } | |
| /* Phyxcer capability setting */ | |
| phy_reg = phy_read(BASE, db->phy_addr, 4, db->chip_id) & ~0x01e0; | |
| if (db->media_mode & DMFE_AUTO) { | |
| /* AUTO Mode */ | |
| phy_reg |= db->PHY_reg4; | |
| } else { | |
| /* Force Mode */ | |
| switch (db->media_mode) { | |
| case DMFE_10MHF: | |
| phy_reg |= 0x20; | |
| break; | |
| case DMFE_10MFD: | |
| phy_reg |= 0x40; | |
| break; | |
| case DMFE_100MHF: | |
| phy_reg |= 0x80; | |
| break; | |
| case DMFE_100MFD: | |
| phy_reg |= 0x100; | |
| break; | |
| } | |
| if (db->chip_id == PCI_DM9009_ID) | |
| phy_reg &= 0x61; | |
| } | |
| /* Write new capability to Phyxcer Reg4 */ | |
| if (!(phy_reg & 0x01e0)) { | |
| phy_reg |= db->PHY_reg4; | |
| db->media_mode |= DMFE_AUTO; | |
| } | |
| phy_write(BASE, db->phy_addr, 4, phy_reg, db->chip_id); | |
| /* Restart Auto-Negotiation */ | |
| if (db->chip_type && (db->chip_id == PCI_DM9102_ID)) | |
| phy_write(BASE, db->phy_addr, 0, 0x1800, db->chip_id); | |
| if (!db->chip_type) | |
| phy_write(BASE, db->phy_addr, 0, 0x1200, db->chip_id); | |
| } | |
| /* | |
| * Process op-mode | |
| * AUTO mode : PHY controller in Auto-negotiation Mode | |
| * Force mode: PHY controller in force mode with HUB | |
| * N-way force capability with SWITCH | |
| */ | |
| #if 0 /* not used */ | |
| static void dmfe_process_mode(struct nic *nic __unused) | |
| { | |
| u16 phy_reg; | |
| /* Full Duplex Mode Check */ | |
| if (db->op_mode & 0x4) | |
| db->cr6_data |= CR6_FDM; /* Set Full Duplex Bit */ | |
| else | |
| db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */ | |
| /* Transciver Selection */ | |
| if (db->op_mode & 0x10) /* 1M HomePNA */ | |
| db->cr6_data |= 0x40000; /* External MII select */ | |
| else | |
| db->cr6_data &= ~0x40000; /* Internal 10/100 transciver */ | |
| update_cr6(db->cr6_data, BASE); | |
| /* 10/100M phyxcer force mode need */ | |
| if (!(db->media_mode & 0x18)) { | |
| /* Forece Mode */ | |
| phy_reg = phy_read(BASE, db->phy_addr, 6, db->chip_id); | |
| if (!(phy_reg & 0x1)) { | |
| /* parter without N-Way capability */ | |
| phy_reg = 0x0; | |
| switch (db->op_mode) { | |
| case DMFE_10MHF: | |
| phy_reg = 0x0; | |
| break; | |
| case DMFE_10MFD: | |
| phy_reg = 0x100; | |
| break; | |
| case DMFE_100MHF: | |
| phy_reg = 0x2000; | |
| break; | |
| case DMFE_100MFD: | |
| phy_reg = 0x2100; | |
| break; | |
| } | |
| phy_write(BASE, db->phy_addr, 0, phy_reg, | |
| db->chip_id); | |
| if (db->chip_type | |
| && (db->chip_id == PCI_DM9102_ID)) | |
| mdelay(20); | |
| phy_write(BASE, db->phy_addr, 0, phy_reg, | |
| db->chip_id); | |
| } | |
| } | |
| } | |
| #endif | |
| /* | |
| * Write a word to Phy register | |
| */ | |
| static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, | |
| u16 phy_data, u32 chip_id) | |
| { | |
| u16 i; | |
| unsigned long ioaddr; | |
| if (chip_id == PCI_DM9132_ID) { | |
| ioaddr = iobase + 0x80 + offset * 4; | |
| outw(phy_data, ioaddr); | |
| } else { | |
| /* DM9102/DM9102A Chip */ | |
| ioaddr = iobase + DCR9; | |
| /* Send 33 synchronization clock to Phy controller */ | |
| for (i = 0; i < 35; i++) | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| /* Send start command(01) to Phy */ | |
| phy_write_1bit(ioaddr, PHY_DATA_0); | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| /* Send write command(01) to Phy */ | |
| phy_write_1bit(ioaddr, PHY_DATA_0); | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| /* Send Phy address */ | |
| for (i = 0x10; i > 0; i = i >> 1) | |
| phy_write_1bit(ioaddr, | |
| phy_addr & i ? PHY_DATA_1 : | |
| PHY_DATA_0); | |
| /* Send register address */ | |
| for (i = 0x10; i > 0; i = i >> 1) | |
| phy_write_1bit(ioaddr, | |
| offset & i ? PHY_DATA_1 : | |
| PHY_DATA_0); | |
| /* written trasnition */ | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| phy_write_1bit(ioaddr, PHY_DATA_0); | |
| /* Write a word data to PHY controller */ | |
| for (i = 0x8000; i > 0; i >>= 1) | |
| phy_write_1bit(ioaddr, | |
| phy_data & i ? PHY_DATA_1 : | |
| PHY_DATA_0); | |
| } | |
| } | |
| /* | |
| * Read a word data from phy register | |
| */ | |
| static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, | |
| u32 chip_id) | |
| { | |
| int i; | |
| u16 phy_data; | |
| unsigned long ioaddr; | |
| if (chip_id == PCI_DM9132_ID) { | |
| /* DM9132 Chip */ | |
| ioaddr = iobase + 0x80 + offset * 4; | |
| phy_data = inw(ioaddr); | |
| } else { | |
| /* DM9102/DM9102A Chip */ | |
| ioaddr = iobase + DCR9; | |
| /* Send 33 synchronization clock to Phy controller */ | |
| for (i = 0; i < 35; i++) | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| /* Send start command(01) to Phy */ | |
| phy_write_1bit(ioaddr, PHY_DATA_0); | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| /* Send read command(10) to Phy */ | |
| phy_write_1bit(ioaddr, PHY_DATA_1); | |
| phy_write_1bit(ioaddr, PHY_DATA_0); | |
| /* Send Phy address */ | |
| for (i = 0x10; i > 0; i = i >> 1) | |
| phy_write_1bit(ioaddr, | |
| phy_addr & i ? PHY_DATA_1 : | |
| PHY_DATA_0); | |
| /* Send register address */ | |
| for (i = 0x10; i > 0; i = i >> 1) | |
| phy_write_1bit(ioaddr, | |
| offset & i ? PHY_DATA_1 : | |
| PHY_DATA_0); | |
| /* Skip transition state */ | |
| phy_read_1bit(ioaddr); | |
| /* read 16bit data */ | |
| for (phy_data = 0, i = 0; i < 16; i++) { | |
| phy_data <<= 1; | |
| phy_data |= phy_read_1bit(ioaddr); | |
| } | |
| } | |
| return phy_data; | |
| } | |
| /* | |
| * Write one bit data to Phy Controller | |
| */ | |
| static void phy_write_1bit(unsigned long ioaddr, u32 phy_data) | |
| { | |
| outl(phy_data, ioaddr); /* MII Clock Low */ | |
| udelay(1); | |
| outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ | |
| udelay(1); | |
| outl(phy_data, ioaddr); /* MII Clock Low */ | |
| udelay(1); | |
| } | |
| /* | |
| * Read one bit phy data from PHY controller | |
| */ | |
| static u16 phy_read_1bit(unsigned long ioaddr) | |
| { | |
| u16 phy_data; | |
| outl(0x50000, ioaddr); | |
| udelay(1); | |
| phy_data = (inl(ioaddr) >> 19) & 0x1; | |
| outl(0x40000, ioaddr); | |
| udelay(1); | |
| return phy_data; | |
| } | |
| /* | |
| * Parser SROM and media mode | |
| */ | |
| static void dmfe_parse_srom(struct nic *nic) | |
| { | |
| unsigned char *srom = db->srom; | |
| int dmfe_mode, tmp_reg; | |
| /* Init CR15 */ | |
| db->cr15_data = CR15_DEFAULT; | |
| /* Check SROM Version */ | |
| if (((int) srom[18] & 0xff) == SROM_V41_CODE) { | |
| /* SROM V4.01 */ | |
| /* Get NIC support media mode */ | |
| db->NIC_capability = *(u16 *) (srom + 34); | |
| db->PHY_reg4 = 0; | |
| for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { | |
| switch (db->NIC_capability & tmp_reg) { | |
| case 0x1: | |
| db->PHY_reg4 |= 0x0020; | |
| break; | |
| case 0x2: | |
| db->PHY_reg4 |= 0x0040; | |
| break; | |
| case 0x4: | |
| db->PHY_reg4 |= 0x0080; | |
| break; | |
| case 0x8: | |
| db->PHY_reg4 |= 0x0100; | |
| break; | |
| } | |
| } | |
| /* Media Mode Force or not check */ | |
| dmfe_mode = *((int *) srom + 34) & *((int *) srom + 36); | |
| switch (dmfe_mode) { | |
| case 0x4: | |
| dmfe_media_mode = DMFE_100MHF; | |
| break; /* 100MHF */ | |
| case 0x2: | |
| dmfe_media_mode = DMFE_10MFD; | |
| break; /* 10MFD */ | |
| case 0x8: | |
| dmfe_media_mode = DMFE_100MFD; | |
| break; /* 100MFD */ | |
| case 0x100: | |
| case 0x200: | |
| dmfe_media_mode = DMFE_1M_HPNA; | |
| break; /* HomePNA */ | |
| } | |
| /* Special Function setting */ | |
| /* VLAN function */ | |
| if ((SF_mode & 0x1) || (srom[43] & 0x80)) | |
| db->cr15_data |= 0x40; | |
| /* Flow Control */ | |
| if ((SF_mode & 0x2) || (srom[40] & 0x1)) | |
| db->cr15_data |= 0x400; | |
| /* TX pause packet */ | |
| if ((SF_mode & 0x4) || (srom[40] & 0xe)) | |
| db->cr15_data |= 0x9800; | |
| } | |
| /* Parse HPNA parameter */ | |
| db->HPNA_command = 1; | |
| /* Accept remote command or not */ | |
| if (HPNA_rx_cmd == 0) | |
| db->HPNA_command |= 0x8000; | |
| /* Issue remote command & operation mode */ | |
| if (HPNA_tx_cmd == 1) | |
| switch (HPNA_mode) { /* Issue Remote Command */ | |
| case 0: | |
| db->HPNA_command |= 0x0904; | |
| break; | |
| case 1: | |
| db->HPNA_command |= 0x0a00; | |
| break; | |
| case 2: | |
| db->HPNA_command |= 0x0506; | |
| break; | |
| case 3: | |
| db->HPNA_command |= 0x0602; | |
| break; | |
| } else | |
| switch (HPNA_mode) { /* Don't Issue */ | |
| case 0: | |
| db->HPNA_command |= 0x0004; | |
| break; | |
| case 1: | |
| db->HPNA_command |= 0x0000; | |
| break; | |
| case 2: | |
| db->HPNA_command |= 0x0006; | |
| break; | |
| case 3: | |
| db->HPNA_command |= 0x0002; | |
| break; | |
| } | |
| /* Check DM9801 or DM9802 present or not */ | |
| db->HPNA_present = 0; | |
| update_cr6(db->cr6_data | 0x40000, BASE); | |
| tmp_reg = phy_read(BASE, db->phy_addr, 3, db->chip_id); | |
| if ((tmp_reg & 0xfff0) == 0xb900) { | |
| /* DM9801 or DM9802 present */ | |
| db->HPNA_timer = 8; | |
| if (phy_read(BASE, db->phy_addr, 31, db->chip_id) == | |
| 0x4404) { | |
| /* DM9801 HomeRun */ | |
| db->HPNA_present = 1; | |
| dmfe_program_DM9801(nic, tmp_reg); | |
| } else { | |
| /* DM9802 LongRun */ | |
| db->HPNA_present = 2; | |
| dmfe_program_DM9802(nic); | |
| } | |
| } | |
| } | |
| /* | |
| * Init HomeRun DM9801 | |
| */ | |
| static void dmfe_program_DM9801(struct nic *nic __unused, int HPNA_rev) | |
| { | |
| u32 reg17, reg25; | |
| if (!HPNA_NoiseFloor) | |
| HPNA_NoiseFloor = DM9801_NOISE_FLOOR; | |
| switch (HPNA_rev) { | |
| case 0xb900: /* DM9801 E3 */ | |
| db->HPNA_command |= 0x1000; | |
| reg25 = phy_read(BASE, db->phy_addr, 24, db->chip_id); | |
| reg25 = ((reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000; | |
| reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id); | |
| break; | |
| case 0xb901: /* DM9801 E4 */ | |
| reg25 = phy_read(BASE, db->phy_addr, 25, db->chip_id); | |
| reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor; | |
| reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id); | |
| reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3; | |
| break; | |
| case 0xb902: /* DM9801 E5 */ | |
| case 0xb903: /* DM9801 E6 */ | |
| default: | |
| db->HPNA_command |= 0x1000; | |
| reg25 = phy_read(BASE, db->phy_addr, 25, db->chip_id); | |
| reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5; | |
| reg17 = phy_read(BASE, db->phy_addr, 17, db->chip_id); | |
| reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor; | |
| break; | |
| } | |
| phy_write(BASE, db->phy_addr, 16, db->HPNA_command, db->chip_id); | |
| phy_write(BASE, db->phy_addr, 17, reg17, db->chip_id); | |
| phy_write(BASE, db->phy_addr, 25, reg25, db->chip_id); | |
| } | |
| /* | |
| * Init HomeRun DM9802 | |
| */ | |
| static void dmfe_program_DM9802(struct nic *nic __unused) | |
| { | |
| u32 phy_reg; | |
| if (!HPNA_NoiseFloor) | |
| HPNA_NoiseFloor = DM9802_NOISE_FLOOR; | |
| phy_write(BASE, db->phy_addr, 16, db->HPNA_command, db->chip_id); | |
| phy_reg = phy_read(BASE, db->phy_addr, 25, db->chip_id); | |
| phy_reg = (phy_reg & 0xff00) + HPNA_NoiseFloor; | |
| phy_write(BASE, db->phy_addr, 25, phy_reg, db->chip_id); | |
| } | |
| static struct nic_operations dmfe_operations = { | |
| .connect = dummy_connect, | |
| .poll = dmfe_poll, | |
| .transmit = dmfe_transmit, | |
| .irq = dmfe_irq, | |
| }; | |
| static struct pci_device_id dmfe_nics[] = { | |
| PCI_ROM(0x1282, 0x9009, "dmfe9009", "Davicom 9009", 0), | |
| PCI_ROM(0x1282, 0x9100, "dmfe9100", "Davicom 9100", 0), | |
| PCI_ROM(0x1282, 0x9102, "dmfe9102", "Davicom 9102", 0), | |
| PCI_ROM(0x1282, 0x9132, "dmfe9132", "Davicom 9132", 0), /* Needs probably some fixing */ | |
| }; | |
| PCI_DRIVER ( dmfe_driver, dmfe_nics, PCI_NO_CLASS ); | |
| DRIVER ( "DMFE/PCI", nic_driver, pci_driver, dmfe_driver, | |
| dmfe_probe, dmfe_disable, dmfe_bufs ); | |
| /* | |
| * Local variables: | |
| * c-basic-offset: 8 | |
| * c-indent-level: 8 | |
| * tab-width: 8 | |
| * End: | |
| */ |