#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <string.h>#include <unistd.h>#include <assert.h>#include <byteswap.h>#include <errno.h>#include <gpxe/ethernet.h>#include <gpxe/if_ether.h>#include <gpxe/io.h>#include <gpxe/iobuf.h>#include <gpxe/malloc.h>#include <gpxe/netdevice.h>#include <gpxe/pci.h>#include <gpxe/timer.h>#include <gpxe/nvs.h>#include "3c90x.h"Go to the source code of this file.
Functions | |
| FILE_LICENCE (BSD2) | |
| static void | a3c90x_internal_IssueCommand (int ioaddr, int cmd, int param) |
| a3c90x_internal_IssueCommand: sends a command to the 3c90x card and waits for it's completion | |
| static void | a3c90x_internal_SetWindow (struct INF_3C90X *inf_3c90x, int window) |
| a3c90x_internal_SetWindow: selects a register window set. | |
| static void | a3c90x_internal_WaitForEeprom (struct INF_3C90X *inf_3c90x) |
| static int | a3c90x_internal_ReadEeprom (struct nvs_device *nvs, unsigned int address, void *data, size_t len) |
| a3c90x_internal_ReadEeprom - nvs routine to read eeprom data We only support reading one word(2 byte). | |
| static int | a3c90x_internal_WriteEeprom (struct nvs_device *nvs __unused, unsigned int address __unused, const void *data __unused, size_t len __unused) |
| a3c90x_internal_WriteEeprom - nvs routine to write eeprom data currently not implemented | |
| static void | a3c90x_internal_ReadEepromContents (struct INF_3C90X *inf_3c90x) |
| static void | a3c90x_reset (struct INF_3C90X *inf_3c90x) |
| a3c90x_reset: exported function that resets the card to its default state. | |
| static int | a3c90x_setup_tx_ring (struct INF_3C90X *p) |
| a3c90x_setup_tx_ring - Allocates TX ring, initialize tx_desc values | |
| static void | a3c90x_process_tx_packets (struct net_device *netdev) |
| a3c90x_process_tx_packets - Checks for successfully sent packets, reports them to gPXE with netdev_tx_complete(); | |
| static void | a3c90x_free_tx_ring (struct INF_3C90X *p) |
| static int | a3c90x_transmit (struct net_device *netdev, struct io_buffer *iob) |
| a3c90x_transmit - Transmits a packet. | |
| static void | a3c90x_prepare_rx_desc (struct INF_3C90X *p, unsigned int index) |
| a3c90x_prepare_rx_desc - fills the rx desc with initial data | |
| static void | a3c90x_refill_rx_ring (struct INF_3C90X *p) |
| a3c90x_refill_rx_ring -checks every entry in the rx ring and reallocates them as necessary. | |
| static int | a3c90x_setup_rx_ring (struct INF_3C90X *p) |
| a3c90x_setup_rx_ring - Allocates RX ring, initialize rx_desc values | |
| static void | a3c90x_free_rx_ring (struct INF_3C90X *p) |
| static void | a3c90x_free_rx_iobuf (struct INF_3C90X *p) |
| static void | a3c90x_process_rx_packets (struct net_device *netdev) |
| a3c90x_process_rx_packets - Checks for received packets, reports them to gPXE with netdev_rx() or netdev_rx_err() if there was an error while receiving the packet | |
| static void | a3c90x_poll (struct net_device *netdev) |
| a3c90x_poll - Routine that gets called periodically. | |
| static void | a3c90x_free_resources (struct INF_3C90X *p) |
| static void | a3c90x_remove (struct pci_device *pci) |
| a3c90x_remove - Routine to remove the card. | |
| static void | a3c90x_irq (struct net_device *netdev, int enable) |
| static void | a3c90x_hw_start (struct net_device *netdev) |
| a3c90x_hw_start - Initialize hardware, copy MAC address to NIC registers, set default receiver | |
| static int | a3c90x_open (struct net_device *netdev) |
| a3c90x_open - Routine to initialize the card. | |
| static void | a3c90x_close (struct net_device *netdev) |
| a3c90x_close - free()s TX and RX ring, disablex RX/TX, resets NIC | |
| static int | a3c90x_probe (struct pci_device *pci, const struct pci_device_id *pci_id __unused) |
| a3c90x_probe: exported routine to probe for the 3c905 card. | |
Variables | |
| static struct net_device_operations | a3c90x_operations |
| static struct pci_device_id | a3c90x_nics [] |
| struct pci_driver a3c90x_driver | __pci_driver |
| FILE_LICENCE | ( | BSD2 | ) |
| static void a3c90x_internal_IssueCommand | ( | int | ioaddr, | |
| int | cmd, | |||
| int | param | |||
| ) | [static] |
a3c90x_internal_IssueCommand: sends a command to the 3c90x card and waits for it's completion
| ioaddr | IOAddress of the NIC | |
| cmd | Command to be issued | |
| param | Command parameter |
Definition at line 70 of file 3c90x.c.
References DBG, DBG2, DBGP, INT_CMDINPROGRESS, inw, outw, and regCommandIntStatus_w.
Referenced by a3c90x_hw_start(), a3c90x_internal_SetWindow(), a3c90x_irq(), a3c90x_open(), a3c90x_poll(), a3c90x_prepare_rx_desc(), a3c90x_reset(), and a3c90x_transmit().
00071 { 00072 unsigned int val = (cmd << 11) | param; 00073 int cnt = 0; 00074 00075 DBGP("a3c90x_internal_IssueCommand\n"); 00076 00077 /* Send the cmd to the cmd register */ 00078 outw(val, ioaddr + regCommandIntStatus_w); 00079 00080 /* Wait for the cmd to complete */ 00081 for (cnt = 0; cnt < 100000; cnt++) { 00082 if (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS) { 00083 continue; 00084 } else { 00085 DBG2("Command 0x%04X finished in time. cnt = %d.\n", cmd, cnt); 00086 return; 00087 } 00088 } 00089 00090 DBG("Command 0x%04X DID NOT finish in time. cnt = %d.\n", cmd, cnt); 00091 }
| static void a3c90x_internal_SetWindow | ( | struct INF_3C90X * | inf_3c90x, | |
| int | window | |||
| ) | [static] |
a3c90x_internal_SetWindow: selects a register window set.
| inf_3c90x | private NIC data | |
| window | window to be selected |
Definition at line 99 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), cmdSelectRegisterWindow, INF_3C90X::CurrentWindow, DBGP, and INF_3C90X::IOAddr.
Referenced by a3c90x_hw_start(), a3c90x_internal_ReadEeprom(), and a3c90x_reset().
00100 { 00101 DBGP("a3c90x_internal_SetWindow\n"); 00102 /* Window already as set? */ 00103 if (inf_3c90x->CurrentWindow == window) 00104 return; 00105 00106 /* Issue the window command. */ 00107 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00108 cmdSelectRegisterWindow, window); 00109 inf_3c90x->CurrentWindow = window; 00110 00111 return; 00112 }
| static void a3c90x_internal_WaitForEeprom | ( | struct INF_3C90X * | inf_3c90x | ) | [static] |
Definition at line 114 of file 3c90x.c.
References DBG, DBGP, EEPROM_TIMEOUT, eepromBusy, inw, INF_3C90X::IOAddr, regEepromCommand_0_w, and udelay().
Referenced by a3c90x_internal_ReadEeprom().
00115 { 00116 int cnt = 0; 00117 00118 DBGP("a3c90x_internal_WaitForEeprom\n"); 00119 00120 while (eepromBusy & inw(inf_3c90x->IOAddr + regEepromCommand_0_w)) { 00121 if (cnt == EEPROM_TIMEOUT) { 00122 DBG("Read from eeprom failed: timeout\n"); 00123 return; 00124 } 00125 udelay(1); 00126 cnt++; 00127 } 00128 }
| static int a3c90x_internal_ReadEeprom | ( | struct nvs_device * | nvs, | |
| unsigned int | address, | |||
| void * | data, | |||
| size_t | len | |||
| ) | [static] |
a3c90x_internal_ReadEeprom - nvs routine to read eeprom data We only support reading one word(2 byte).
The nvs subsystem will make sure that the routine will never be called with len != 2.
| nvs | nvs data. | |
| address | eeprom address to read data from. | |
| data | data is put here. | |
| len | number of bytes to read. |
Definition at line 141 of file 3c90x.c.
References a3c90x_internal_SetWindow(), a3c90x_internal_WaitForEeprom(), assert, container_of, DBGP, dest, eepromRead, eepromRead_556, inw, INF_3C90X::IOAddr, INF_3C90X::is3c556, outw, regEepromCommand_0_w, regEepromData_0_w, and winEepromBios0.
Referenced by a3c90x_probe().
00142 { 00143 unsigned short *dest = (unsigned short *) data; 00144 struct INF_3C90X *inf_3c90x = 00145 container_of(nvs, struct INF_3C90X, nvs); 00146 00147 DBGP("a3c90x_internal_ReadEeprom\n"); 00148 00149 /* we support reading 2 bytes only */ 00150 assert(len == 2); 00151 00152 /* Select correct window */ 00153 a3c90x_internal_SetWindow(inf_3c90x, winEepromBios0); 00154 00155 /* set eepromRead bits in command sent to NIC */ 00156 address += (inf_3c90x->is3c556 ? eepromRead_556 : eepromRead); 00157 00158 a3c90x_internal_WaitForEeprom(inf_3c90x); 00159 /* send address to NIC */ 00160 outw(address, inf_3c90x->IOAddr + regEepromCommand_0_w); 00161 a3c90x_internal_WaitForEeprom(inf_3c90x); 00162 00163 /* read value */ 00164 *dest = inw(inf_3c90x->IOAddr + regEepromData_0_w); 00165 00166 return 0; 00167 }
| static int a3c90x_internal_WriteEeprom | ( | struct nvs_device *nvs | __unused, | |
| unsigned int address | __unused, | |||
| const void *data | __unused, | |||
| size_t len | __unused | |||
| ) | [static] |
a3c90x_internal_WriteEeprom - nvs routine to write eeprom data currently not implemented
| nvs | nvs data. | |
| address | eeprom address to read data from. | |
| data | data is put here. | |
| len | number of bytes to read. |
Definition at line 179 of file 3c90x.c.
References ENOTSUP.
Referenced by a3c90x_probe().
00182 { 00183 return -ENOTSUP; 00184 }
| static void a3c90x_internal_ReadEepromContents | ( | struct INF_3C90X * | inf_3c90x | ) | [static] |
Definition at line 186 of file 3c90x.c.
References DBGP, INF_3C90X::eeprom, INF_3C90X::isBrev, INF_3C90X::nvs, and nvs_read().
Referenced by a3c90x_probe().
00187 { 00188 int eeprom_size = (inf_3c90x->isBrev ? 0x20 : 0x17) * 2; 00189 00190 DBGP("a3c90x_internal_ReadEepromContents\n"); 00191 00192 nvs_read(&inf_3c90x->nvs, 0, inf_3c90x->eeprom, eeprom_size); 00193 }
| static void a3c90x_reset | ( | struct INF_3C90X * | inf_3c90x | ) | [static] |
a3c90x_reset: exported function that resets the card to its default state.
This is so the Linux driver can re-set the card up the way it wants to. If CFG_3C90X_PRESERVE_XCVR is defined, then the reset will not alter the selected transceiver that we used to download the boot image.
| inf_3c90x | Private NIC data |
Definition at line 204 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), a3c90x_internal_SetWindow(), cmdAcknowledgeInterrupt, cmdGlobalReset, cmdRxEnable, cmdRxReset, cmdSetIndicationEnable, cmdSetInterruptEnable, cmdTxEnable, cmdTxReset, DBG, DBGP, INT_TXCOMPLETE, INT_UPCOMPLETE, INF_3C90X::IOAddr, INF_3C90X::isBrev, outw, regStationMask_2_3w, and winAddressing2.
Referenced by a3c90x_close(), a3c90x_open(), a3c90x_probe(), and a3c90x_remove().
00205 { 00206 DBGP("a3c90x_reset\n"); 00207 /* Send the reset command to the card */ 00208 DBG("3c90x: Issuing RESET\n"); 00209 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdGlobalReset, 0); 00210 00211 /* global reset command resets station mask, non-B revision cards 00212 * require explicit reset of values 00213 */ 00214 a3c90x_internal_SetWindow(inf_3c90x, winAddressing2); 00215 outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 0); 00216 outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 2); 00217 outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 4); 00218 00219 /* Issue transmit reset, wait for command completion */ 00220 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxReset, 0); 00221 00222 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0); 00223 00224 /* 00225 * reset of the receiver on B-revision cards re-negotiates the link 00226 * takes several seconds (a computer eternity) 00227 */ 00228 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxReset, 00229 inf_3c90x->isBrev ? 0x04 : 0x00); 00230 00231 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0); 00232 00233 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00234 cmdSetInterruptEnable, 0); 00235 /* enable rxComplete and txComplete */ 00236 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00237 cmdSetIndicationEnable, 00238 INT_TXCOMPLETE | INT_UPCOMPLETE); 00239 /* acknowledge any pending status flags */ 00240 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00241 cmdAcknowledgeInterrupt, 0x661); 00242 00243 return; 00244 }
| static int a3c90x_setup_tx_ring | ( | struct INF_3C90X * | p | ) | [static] |
a3c90x_setup_tx_ring - Allocates TX ring, initialize tx_desc values
| p | Private NIC data |
| Returns | 0 on success, negative on failure |
Definition at line 253 of file 3c90x.c.
References DBG, DBGP, ENOMEM, malloc_dma(), memset(), INF_3C90X::tx_cnt, INF_3C90X::tx_cur, INF_3C90X::tx_ring, TX_RING_ALIGN, TX_RING_SIZE, and INF_3C90X::tx_tail.
Referenced by a3c90x_open().
00254 { 00255 DBGP("a3c90x_setup_tx_ring\n"); 00256 p->tx_ring = 00257 malloc_dma(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN); 00258 00259 if (!p->tx_ring) { 00260 DBG("Could not allocate TX-ring\n"); 00261 return -ENOMEM; 00262 } 00263 00264 memset(p->tx_ring, 0, TX_RING_SIZE * sizeof(struct TXD)); 00265 p->tx_cur = 0; 00266 p->tx_cnt = 0; 00267 p->tx_tail = 0; 00268 00269 return 0; 00270 }
| static void a3c90x_process_tx_packets | ( | struct net_device * | netdev | ) | [static] |
a3c90x_process_tx_packets - Checks for successfully sent packets, reports them to gPXE with netdev_tx_complete();
| netdev | Network device info |
Definition at line 278 of file 3c90x.c.
References DBG, DBGP, inl, INF_3C90X::IOAddr, iob_len(), netdev_priv(), netdev_tx_complete(), regDnListPtr_l, INF_3C90X::tx_cnt, INF_3C90X::tx_cur, INF_3C90X::tx_iobuf, INF_3C90X::tx_ring, TX_RING_SIZE, INF_3C90X::tx_tail, and virt_to_bus().
Referenced by a3c90x_poll().
00279 { 00280 struct INF_3C90X *p = netdev_priv(netdev); 00281 unsigned int downlist_ptr; 00282 00283 DBGP("a3c90x_process_tx_packets\n"); 00284 00285 DBG(" tx_cnt: %d\n", p->tx_cnt); 00286 00287 while (p->tx_tail != p->tx_cur) { 00288 00289 downlist_ptr = inl(p->IOAddr + regDnListPtr_l); 00290 00291 DBG(" downlist_ptr: %#08x\n", downlist_ptr); 00292 DBG(" tx_tail: %d tx_cur: %d\n", p->tx_tail, p->tx_cur); 00293 00294 /* NIC is currently working on this tx desc */ 00295 if(downlist_ptr == virt_to_bus(p->tx_ring + p->tx_tail)) 00296 return; 00297 00298 netdev_tx_complete(netdev, p->tx_iobuf[p->tx_tail]); 00299 00300 DBG("transmitted packet\n"); 00301 DBG(" size: %zd\n", iob_len(p->tx_iobuf[p->tx_tail])); 00302 00303 p->tx_tail = (p->tx_tail + 1) % TX_RING_SIZE; 00304 p->tx_cnt--; 00305 } 00306 }
| static void a3c90x_free_tx_ring | ( | struct INF_3C90X * | p | ) | [static] |
Definition at line 308 of file 3c90x.c.
References DBGP, free_dma(), NULL, INF_3C90X::tx_ring, and TX_RING_SIZE.
Referenced by a3c90x_free_resources().
00309 { 00310 DBGP("a3c90x_free_tx_ring\n"); 00311 00312 free_dma(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD)); 00313 p->tx_ring = NULL; 00314 /* io_buffers are free()ed by netdev_tx_complete[,_err]() */ 00315 }
| static int a3c90x_transmit | ( | struct net_device * | netdev, | |
| struct io_buffer * | iob | |||
| ) | [static] |
a3c90x_transmit - Transmits a packet.
| Returns | 0 on success, negative on failure |
Definition at line 325 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), cmdStallCtl, io_buffer::data, TXD::DataAddr, TXD::DataLength, DBG, DBGP, TXD::DnNextPtr, dnStall, dnUnStall, downLastFrag, ENOBUFS, TXD::FrameStartHeader, fshTxIndicate, inl, INF_3C90X::IOAddr, iob_len(), INF_3C90X::isBrev, netdev_priv(), outl, regDnListPtr_l, INF_3C90X::tx_cnt, INF_3C90X::tx_cur, INF_3C90X::tx_iobuf, INF_3C90X::tx_ring, TX_RING_SIZE, and virt_to_bus().
00327 { 00328 struct INF_3C90X *inf_3c90x = netdev_priv(netdev); 00329 struct TXD *tx_cur_desc; 00330 struct TXD *tx_prev_desc; 00331 00332 unsigned int len; 00333 unsigned int downlist_ptr; 00334 00335 DBGP("a3c90x_transmit\n"); 00336 00337 if (inf_3c90x->tx_cnt == TX_RING_SIZE) { 00338 DBG("TX-Ring overflow\n"); 00339 return -ENOBUFS; 00340 } 00341 00342 inf_3c90x->tx_iobuf[inf_3c90x->tx_cur] = iob; 00343 tx_cur_desc = inf_3c90x->tx_ring + inf_3c90x->tx_cur; 00344 00345 tx_prev_desc = inf_3c90x->tx_ring + 00346 (((inf_3c90x->tx_cur + TX_RING_SIZE) - 1) % TX_RING_SIZE); 00347 00348 len = iob_len(iob); 00349 00350 /* Setup the DPD (download descriptor) */ 00351 tx_cur_desc->DnNextPtr = 0; 00352 00353 /* FrameStartHeader differs in 90x and >= 90xB 00354 * It contains length in 90x and a round up boundary and packet ID for 00355 * 90xB and 90xC. We can leave this to 0 for 90xB and 90xC. 00356 */ 00357 tx_cur_desc->FrameStartHeader = 00358 fshTxIndicate | (inf_3c90x->isBrev ? 0x00 : len); 00359 00360 tx_cur_desc->DataAddr = virt_to_bus(iob->data); 00361 tx_cur_desc->DataLength = len | downLastFrag; 00362 00363 /* We have to stall the download engine, so the NIC won't access the 00364 * tx descriptor while we modify it. There is a way around this 00365 * from revision B and upwards. To stay compatible with older revisions 00366 * we don't use it here. 00367 */ 00368 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl, 00369 dnStall); 00370 00371 tx_prev_desc->DnNextPtr = virt_to_bus(tx_cur_desc); 00372 00373 downlist_ptr = inl(inf_3c90x->IOAddr + regDnListPtr_l); 00374 if (downlist_ptr == 0) { 00375 /* currently no DownList, sending a new one */ 00376 outl(virt_to_bus(tx_cur_desc), 00377 inf_3c90x->IOAddr + regDnListPtr_l); 00378 } 00379 00380 /* End Stall */ 00381 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl, 00382 dnUnStall); 00383 00384 inf_3c90x->tx_cur = (inf_3c90x->tx_cur + 1) % TX_RING_SIZE; 00385 inf_3c90x->tx_cnt++; 00386 00387 return 0; 00388 }
| static void a3c90x_prepare_rx_desc | ( | struct INF_3C90X * | p, | |
| unsigned int | index | |||
| ) | [static] |
a3c90x_prepare_rx_desc - fills the rx desc with initial data
| p | NIC private data | |
| index | Index for rx_iobuf and rx_ring array |
Definition at line 397 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), cmdStallCtl, io_buffer::data, RXD::DataAddr, RXD::DataLength, DBG, DBGP, INF_3C90X::IOAddr, RX_BUF_SIZE, INF_3C90X::rx_iobuf, INF_3C90X::rx_ring, upLastFrag, RXD::UpPktStatus, upStall, upUnStall, and virt_to_bus().
Referenced by a3c90x_refill_rx_ring().
00398 { 00399 DBGP("a3c90x_prepare_rx_desc\n"); 00400 DBG("Populating rx_desc %d\n", index); 00401 00402 /* We have to stall the upload engine, so the NIC won't access the 00403 * rx descriptor while we modify it. There is a way around this 00404 * from revision B and upwards. To stay compatible with older revisions 00405 * we don't use it here. 00406 */ 00407 a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upStall); 00408 00409 p->rx_ring[index].DataAddr = virt_to_bus(p->rx_iobuf[index]->data); 00410 p->rx_ring[index].DataLength = RX_BUF_SIZE | upLastFrag; 00411 p->rx_ring[index].UpPktStatus = 0; 00412 00413 /* unstall upload engine */ 00414 a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upUnStall); 00415 }
| static void a3c90x_refill_rx_ring | ( | struct INF_3C90X * | p | ) | [static] |
a3c90x_refill_rx_ring -checks every entry in the rx ring and reallocates them as necessary.
Then it calls a3c90x_prepare_rx_desc to fill the rx desc with initial data.
| p | NIC private data |
Definition at line 424 of file 3c90x.c.
References a3c90x_prepare_rx_desc(), alloc_iob(), DBG, DBGP, NULL, RX_BUF_SIZE, INF_3C90X::rx_iobuf, INF_3C90X::rx_ring, RX_RING_SIZE, upComplete, and RXD::UpPktStatus.
Referenced by a3c90x_process_rx_packets(), and a3c90x_setup_rx_ring().
00425 { 00426 int i; 00427 unsigned int status; 00428 struct RXD *rx_cur_desc; 00429 00430 DBGP("a3c90x_refill_rx_ring\n"); 00431 00432 for (i = 0; i < RX_RING_SIZE; i++) { 00433 rx_cur_desc = p->rx_ring + i; 00434 status = rx_cur_desc->UpPktStatus; 00435 00436 /* only refill used descriptor */ 00437 if (!(status & upComplete)) 00438 continue; 00439 00440 /* we still need to process this descriptor */ 00441 if (p->rx_iobuf[i] != NULL) 00442 continue; 00443 00444 p->rx_iobuf[i] = alloc_iob(RX_BUF_SIZE); 00445 if (p->rx_iobuf[i] == NULL) { 00446 DBG("alloc_iob() failed\n"); 00447 break; 00448 } 00449 00450 a3c90x_prepare_rx_desc(p, i); 00451 } 00452 }
| static int a3c90x_setup_rx_ring | ( | struct INF_3C90X * | p | ) | [static] |
a3c90x_setup_rx_ring - Allocates RX ring, initialize rx_desc values
| p | Private NIC data |
| Returns | 0 on success, negative on failure |
Definition at line 461 of file 3c90x.c.
References a3c90x_refill_rx_ring(), DBG, DBGP, ENOMEM, malloc_dma(), NULL, INF_3C90X::rx_cur, INF_3C90X::rx_iobuf, INF_3C90X::rx_ring, RX_RING_ALIGN, RX_RING_SIZE, upComplete, RXD::UpNextPtr, RXD::UpPktStatus, and virt_to_bus().
Referenced by a3c90x_open().
00462 { 00463 int i; 00464 00465 DBGP("a3c90x_setup_rx_ring\n"); 00466 00467 p->rx_ring = 00468 malloc_dma(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN); 00469 00470 if (!p->rx_ring) { 00471 DBG("Could not allocate RX-ring\n"); 00472 return -ENOMEM; 00473 } 00474 00475 p->rx_cur = 0; 00476 00477 for (i = 0; i < RX_RING_SIZE; i++) { 00478 p->rx_ring[i].UpNextPtr = 00479 virt_to_bus(p->rx_ring + (i + 1)); 00480 00481 /* these are needed so refill_rx_ring initializes the ring */ 00482 p->rx_ring[i].UpPktStatus = upComplete; 00483 p->rx_iobuf[i] = NULL; 00484 } 00485 00486 /* Loop the ring */ 00487 p->rx_ring[i - 1].UpNextPtr = virt_to_bus(p->rx_ring); 00488 00489 a3c90x_refill_rx_ring(p); 00490 00491 return 0; 00492 }
| static void a3c90x_free_rx_ring | ( | struct INF_3C90X * | p | ) | [static] |
Definition at line 494 of file 3c90x.c.
References DBGP, free_dma(), NULL, INF_3C90X::rx_ring, and RX_RING_SIZE.
Referenced by a3c90x_free_resources().
00495 { 00496 DBGP("a3c90x_free_rx_ring\n"); 00497 00498 free_dma(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD)); 00499 p->rx_ring = NULL; 00500 }
| static void a3c90x_free_rx_iobuf | ( | struct INF_3C90X * | p | ) | [static] |
Definition at line 502 of file 3c90x.c.
References DBGP, free_iob(), NULL, INF_3C90X::rx_iobuf, and RX_RING_SIZE.
Referenced by a3c90x_free_resources().
00503 { 00504 int i; 00505 00506 DBGP("a3c90x_free_rx_iobuf\n"); 00507 00508 for (i = 0; i < RX_RING_SIZE; i++) { 00509 free_iob(p->rx_iobuf[i]); 00510 p->rx_iobuf[i] = NULL; 00511 } 00512 }
| static void a3c90x_process_rx_packets | ( | struct net_device * | netdev | ) | [static] |
a3c90x_process_rx_packets - Checks for received packets, reports them to gPXE with netdev_rx() or netdev_rx_err() if there was an error while receiving the packet
| netdev | Network device info |
Definition at line 521 of file 3c90x.c.
References a3c90x_refill_rx_ring(), DBG, DBGP, EINVAL, iob_put, netdev_priv(), netdev_rx(), netdev_rx_err(), NULL, INF_3C90X::rx_cur, INF_3C90X::rx_iobuf, INF_3C90X::rx_ring, RX_RING_SIZE, upComplete, upError, and RXD::UpPktStatus.
Referenced by a3c90x_poll().
00522 { 00523 int i; 00524 unsigned int rx_status; 00525 struct INF_3C90X *p = netdev_priv(netdev); 00526 struct RXD *rx_cur_desc; 00527 00528 DBGP("a3c90x_process_rx_packets\n"); 00529 00530 for (i = 0; i < RX_RING_SIZE; i++) { 00531 rx_cur_desc = p->rx_ring + p->rx_cur; 00532 rx_status = rx_cur_desc->UpPktStatus; 00533 00534 if (!(rx_status & upComplete) && !(rx_status & upError)) 00535 break; 00536 00537 if (p->rx_iobuf[p->rx_cur] == NULL) 00538 break; 00539 00540 if (rx_status & upError) { 00541 DBG("Corrupted packet received\n"); 00542 netdev_rx_err(netdev, p->rx_iobuf[p->rx_cur], 00543 -EINVAL); 00544 } else { 00545 /* if we're here, we've got good packet */ 00546 int packet_len; 00547 00548 packet_len = rx_status & 0x1FFF; 00549 iob_put(p->rx_iobuf[p->rx_cur], packet_len); 00550 00551 DBG("received packet\n"); 00552 DBG(" size: %d\n", packet_len); 00553 00554 netdev_rx(netdev, p->rx_iobuf[p->rx_cur]); 00555 } 00556 00557 p->rx_iobuf[p->rx_cur] = NULL; /* invalidate rx desc */ 00558 p->rx_cur = (p->rx_cur + 1) % RX_RING_SIZE; 00559 } 00560 a3c90x_refill_rx_ring(p); 00561 00562 }
| static void a3c90x_poll | ( | struct net_device * | netdev | ) | [static] |
a3c90x_poll - Routine that gets called periodically.
Here we hanle transmitted and received packets. We could also check the link status from time to time, which we currently don't do.
| netdev | Network device info |
Definition at line 572 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), a3c90x_process_rx_packets(), a3c90x_process_tx_packets(), cmdAcknowledgeInterrupt, DBG, DBGP, INT_TXCOMPLETE, inw, INF_3C90X::IOAddr, netdev_priv(), outb, regCommandIntStatus_w, and regTxStatus_b.
00573 { 00574 struct INF_3C90X *p = netdev_priv(netdev); 00575 uint16_t raw_status, int_status; 00576 00577 DBGP("a3c90x_poll\n"); 00578 00579 raw_status = inw(p->IOAddr + regCommandIntStatus_w); 00580 int_status = (raw_status & 0x0FFF); 00581 00582 if ( int_status == 0 ) 00583 return; 00584 00585 a3c90x_internal_IssueCommand(p->IOAddr, cmdAcknowledgeInterrupt, 00586 int_status); 00587 00588 if (int_status & INT_TXCOMPLETE) 00589 outb(0x00, p->IOAddr + regTxStatus_b); 00590 00591 DBG("poll: status = %#04x\n", raw_status); 00592 00593 a3c90x_process_tx_packets(netdev); 00594 00595 a3c90x_process_rx_packets(netdev); 00596 }
| static void a3c90x_free_resources | ( | struct INF_3C90X * | p | ) | [static] |
Definition at line 600 of file 3c90x.c.
References a3c90x_free_rx_iobuf(), a3c90x_free_rx_ring(), a3c90x_free_tx_ring(), and DBGP.
Referenced by a3c90x_close(), and a3c90x_open().
00601 { 00602 DBGP("a3c90x_free_resources\n"); 00603 00604 a3c90x_free_tx_ring(p); 00605 a3c90x_free_rx_ring(p); 00606 a3c90x_free_rx_iobuf(p); 00607 }
| static void a3c90x_remove | ( | struct pci_device * | pci | ) | [static] |
a3c90x_remove - Routine to remove the card.
Unregisters the NIC from gPXE, disables RX/TX and resets the card.
| pci | PCI device info |
Definition at line 615 of file 3c90x.c.
References a3c90x_reset(), cmdRxDisable, cmdTxDisable, DBGP, INF_3C90X::IOAddr, netdev, netdev_nullify(), netdev_priv(), netdev_put(), outw, pci_get_drvdata(), regCommandIntStatus_w, and unregister_netdev().
00616 { 00617 struct net_device *netdev = pci_get_drvdata(pci); 00618 struct INF_3C90X *inf_3c90x = netdev_priv(netdev); 00619 00620 DBGP("a3c90x_remove\n"); 00621 00622 a3c90x_reset(inf_3c90x); 00623 00624 /* Disable the receiver and transmitter. */ 00625 outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w); 00626 outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w); 00627 00628 unregister_netdev(netdev); 00629 netdev_nullify(netdev); 00630 netdev_put(netdev); 00631 }
| static void a3c90x_irq | ( | struct net_device * | netdev, | |
| int | enable | |||
| ) | [static] |
Definition at line 633 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), cmdAcknowledgeInterrupt, cmdSetInterruptEnable, DBGP, INT_TXCOMPLETE, INT_UPCOMPLETE, INF_3C90X::IOAddr, and netdev_priv().
00634 { 00635 struct INF_3C90X *p = netdev_priv(netdev); 00636 00637 DBGP("a3c90x_irq\n"); 00638 00639 if (enable == 0) { 00640 /* disable interrupts */ 00641 a3c90x_internal_IssueCommand(p->IOAddr, 00642 cmdSetInterruptEnable, 0); 00643 } else { 00644 a3c90x_internal_IssueCommand(p->IOAddr, 00645 cmdSetInterruptEnable, 00646 INT_TXCOMPLETE | 00647 INT_UPCOMPLETE); 00648 a3c90x_internal_IssueCommand(p->IOAddr, 00649 cmdAcknowledgeInterrupt, 00650 0x661); 00651 } 00652 }
| static void a3c90x_hw_start | ( | struct net_device * | netdev | ) | [static] |
a3c90x_hw_start - Initialize hardware, copy MAC address to NIC registers, set default receiver
Definition at line 658 of file 3c90x.c.
References a3c90x_internal_IssueCommand(), a3c90x_internal_SetWindow(), cfg, cmdAcknowledgeInterrupt, cmdEnableDcConverter, cmdSetIndicationEnable, cmdSetInterruptEnable, cmdSetRxFilter, cmdTxReset, DBG, DBGP, INF_3C90X::eeprom, ETH_ALEN, inl, INT_TXCOMPLETE, INT_UPCOMPLETE, inw, INF_3C90X::IOAddr, INF_3C90X::is3c556, INF_3C90X::isBrev, link100BaseFX, link10Base2, linkAUI, linkAutoneg, linkExternalMII, linkMII, net_device::ll_addr, netdev_priv(), outb, outl, outw, regInternalConfig_3_l, regResetMediaOptions_3_w, regResetOptions_2_w, regStationAddress_2_3w, regStationMask_2_3w, regTxFreeThresh_b, winAddressing2, winTxRxOptions3, and XCVR_MAGIC.
Referenced by a3c90x_open().
00659 { 00660 int i, c; 00661 unsigned int cfg; 00662 unsigned int mopt; 00663 unsigned short linktype; 00664 struct INF_3C90X *inf_3c90x = netdev_priv(netdev); 00665 00666 DBGP("a3c90x_hw_start\n"); 00667 00668 /* 3C556: Invert MII power */ 00669 if (inf_3c90x->is3c556) { 00670 unsigned int tmp; 00671 a3c90x_internal_SetWindow(inf_3c90x, winAddressing2); 00672 tmp = inw(inf_3c90x->IOAddr + regResetOptions_2_w); 00673 tmp |= 0x4000; 00674 outw(tmp, inf_3c90x->IOAddr + regResetOptions_2_w); 00675 } 00676 00677 /* Copy MAC address into the NIC registers */ 00678 a3c90x_internal_SetWindow(inf_3c90x, winAddressing2); 00679 for (i = 0; i < ETH_ALEN; i++) 00680 outb(netdev->ll_addr[i], 00681 inf_3c90x->IOAddr + regStationAddress_2_3w + i); 00682 for (i = 0; i < ETH_ALEN; i++) 00683 outb(0, inf_3c90x->IOAddr + regStationMask_2_3w + i); 00684 00685 /* Read the media options register, print a message and set default 00686 * xcvr. 00687 * 00688 * Uses Media Option command on B revision, Reset Option on non-B 00689 * revision cards -- same register address 00690 */ 00691 a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3); 00692 mopt = inw(inf_3c90x->IOAddr + regResetMediaOptions_3_w); 00693 00694 /* mask out VCO bit that is defined as 10baseFL bit on B-rev cards */ 00695 if (!inf_3c90x->isBrev) { 00696 mopt &= 0x7F; 00697 } 00698 00699 DBG("Connectors present: "); 00700 c = 0; 00701 linktype = 0x0008; 00702 if (mopt & 0x01) { 00703 DBG("%s100Base-T4", (c++) ? ", " : ""); 00704 linktype = linkMII; 00705 } 00706 if (mopt & 0x04) { 00707 DBG("%s100Base-FX", (c++) ? ", " : ""); 00708 linktype = link100BaseFX; 00709 } 00710 if (mopt & 0x10) { 00711 DBG("%s10Base-2", (c++) ? ", " : ""); 00712 linktype = link10Base2; 00713 } 00714 if (mopt & 0x20) { 00715 DBG("%sAUI", (c++) ? ", " : ""); 00716 linktype = linkAUI; 00717 } 00718 if (mopt & 0x40) { 00719 DBG("%sMII", (c++) ? ", " : ""); 00720 linktype = linkMII; 00721 } 00722 if ((mopt & 0xA) == 0xA) { 00723 DBG("%s10Base-T / 100Base-TX", (c++) ? ", " : ""); 00724 linktype = linkAutoneg; 00725 } else if ((mopt & 0xA) == 0x2) { 00726 DBG("%s100Base-TX", (c++) ? ", " : ""); 00727 linktype = linkAutoneg; 00728 } else if ((mopt & 0xA) == 0x8) { 00729 DBG("%s10Base-T", (c++) ? ", " : ""); 00730 linktype = linkAutoneg; 00731 } 00732 DBG(".\n"); 00733 00734 /* Determine transceiver type to use, depending on value stored in 00735 * eeprom 0x16 00736 */ 00737 if (inf_3c90x->isBrev) { 00738 if ((inf_3c90x->eeprom[0x16] & 0xFF00) == XCVR_MAGIC) { 00739 /* User-defined */ 00740 linktype = inf_3c90x->eeprom[0x16] & 0x000F; 00741 } 00742 } else { 00743 /* I don't know what MII MAC only mode is!!! */ 00744 if (linktype == linkExternalMII) { 00745 if (inf_3c90x->isBrev) 00746 DBG("WARNING: MII External MAC Mode only supported on B-revision " "cards!!!!\nFalling Back to MII Mode\n"); 00747 linktype = linkMII; 00748 } 00749 } 00750 00751 /* enable DC converter for 10-Base-T */ 00752 if (linktype == link10Base2) { 00753 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00754 cmdEnableDcConverter, 0); 00755 } 00756 00757 /* Set the link to the type we just determined. */ 00758 a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3); 00759 cfg = inl(inf_3c90x->IOAddr + regInternalConfig_3_l); 00760 cfg &= ~(0xF << 20); 00761 cfg |= (linktype << 20); 00762 00763 DBG("Setting internal cfg register: 0x%08X (linktype: 0x%02X)\n", 00764 cfg, linktype); 00765 00766 outl(cfg, inf_3c90x->IOAddr + regInternalConfig_3_l); 00767 00768 /* Now that we set the xcvr type, reset the Tx and Rx */ 00769 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxReset, 0x00); 00770 00771 if (!inf_3c90x->isBrev) 00772 outb(0x01, inf_3c90x->IOAddr + regTxFreeThresh_b); 00773 00774 /* Set the RX filter = receive only individual pkts & multicast & bcast. */ 00775 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdSetRxFilter, 00776 0x01 + 0x02 + 0x04); 00777 00778 00779 /* 00780 * set Indication and Interrupt flags , acknowledge any IRQ's 00781 */ 00782 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00783 cmdSetInterruptEnable, 00784 INT_TXCOMPLETE | INT_UPCOMPLETE); 00785 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00786 cmdSetIndicationEnable, 00787 INT_TXCOMPLETE | INT_UPCOMPLETE); 00788 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, 00789 cmdAcknowledgeInterrupt, 0x661); 00790 }
| static int a3c90x_open | ( | struct net_device * | netdev | ) | [static] |
a3c90x_open - Routine to initialize the card.
Initialize hardware, allocate TX and RX ring, send RX ring address to the NIC.
| netdev | Network device info |
| Returns | 0 on success, negative on failure |
Definition at line 800 of file 3c90x.c.
References a3c90x_free_resources(), a3c90x_hw_start(), a3c90x_internal_IssueCommand(), a3c90x_reset(), a3c90x_setup_rx_ring(), a3c90x_setup_tx_ring(), cmdRxEnable, cmdTxEnable, DBG, DBGP, INF_3C90X::IOAddr, netdev_priv(), outl, regUpListPtr_l, INF_3C90X::rx_ring, and virt_to_bus().
00801 { 00802 int rc; 00803 struct INF_3C90X *inf_3c90x = netdev_priv(netdev); 00804 00805 DBGP("a3c90x_open\n"); 00806 00807 a3c90x_hw_start(netdev); 00808 00809 rc = a3c90x_setup_tx_ring(inf_3c90x); 00810 if (rc != 0) { 00811 DBG("Error setting up TX Ring\n"); 00812 goto error; 00813 } 00814 00815 rc = a3c90x_setup_rx_ring(inf_3c90x); 00816 if (rc != 0) { 00817 DBG("Error setting up RX Ring\n"); 00818 goto error; 00819 } 00820 00821 /* send rx_ring address to NIC */ 00822 outl(virt_to_bus(inf_3c90x->rx_ring), 00823 inf_3c90x->IOAddr + regUpListPtr_l); 00824 00825 /* enable packet transmission and reception */ 00826 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0); 00827 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0); 00828 00829 return 0; 00830 00831 error: 00832 a3c90x_free_resources(inf_3c90x); 00833 a3c90x_reset(inf_3c90x); 00834 return rc; 00835 }
| static void a3c90x_close | ( | struct net_device * | netdev | ) | [static] |
a3c90x_close - free()s TX and RX ring, disablex RX/TX, resets NIC
| netdev | Network device info |
Definition at line 842 of file 3c90x.c.
References a3c90x_free_resources(), a3c90x_reset(), cmdRxDisable, cmdTxDisable, DBGP, INF_3C90X::IOAddr, netdev_priv(), outw, and regCommandIntStatus_w.
00843 { 00844 struct INF_3C90X *inf_3c90x = netdev_priv(netdev); 00845 00846 DBGP("a3c90x_close\n"); 00847 00848 a3c90x_reset(inf_3c90x); 00849 outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w); 00850 outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w); 00851 a3c90x_free_resources(inf_3c90x); 00852 }
| static int a3c90x_probe | ( | struct pci_device * | pci, | |
| const struct pci_device_id *pci_id | __unused | |||
| ) | [static] |
a3c90x_probe: exported routine to probe for the 3c905 card.
If this routine is called, the pci functions did find the card. We read the eeprom here and get the MAC address. Initialization is done in a3c90x_open().
| rc | Returns 0 on success, negative on failure |
Definition at line 873 of file 3c90x.c.
References a3c90x_internal_ReadEeprom(), a3c90x_internal_ReadEepromContents(), a3c90x_internal_WriteEeprom(), a3c90x_reset(), adjust_pci_device(), alloc_etherdev(), nvs_device::block_size, INF_3C90X::CurrentWindow, DBG, DBGP, pci_device::dev, net_device::dev, pci_device::device, INF_3C90X::eeprom, eepromHwAddrOffset, EINVAL, ENOMEM, net_device::hw_addr, INF_3C90X::IOAddr, pci_device::ioaddr, INF_3C90X::is3c556, INF_3C90X::isBrev, memset(), netdev, netdev_init(), netdev_link_up(), netdev_priv(), netdev_put(), INF_3C90X::nvs, pci_set_drvdata(), nvs_device::read, register_netdev(), nvs_device::size, pci_device::vendor, winNone, nvs_device::word_len_log2, and nvs_device::write.
00875 { 00876 00877 struct net_device *netdev; 00878 struct INF_3C90X *inf_3c90x; 00879 unsigned char *HWAddr; 00880 int rc; 00881 00882 DBGP("a3c90x_probe\n"); 00883 00884 if (pci->ioaddr == 0) 00885 return -EINVAL; 00886 00887 netdev = alloc_etherdev(sizeof(*inf_3c90x)); 00888 if (!netdev) 00889 return -ENOMEM; 00890 00891 netdev_init(netdev, &a3c90x_operations); 00892 pci_set_drvdata(pci, netdev); 00893 netdev->dev = &pci->dev; 00894 00895 inf_3c90x = netdev_priv(netdev); 00896 memset(inf_3c90x, 0, sizeof(*inf_3c90x)); 00897 00898 adjust_pci_device(pci); 00899 00900 inf_3c90x->is3c556 = (pci->device == 0x6055); 00901 inf_3c90x->IOAddr = pci->ioaddr; 00902 inf_3c90x->CurrentWindow = winNone; 00903 00904 inf_3c90x->isBrev = 1; 00905 switch (pci->device) { 00906 case 0x9000: /* 10 Base TPO */ 00907 case 0x9001: /* 10/100 T4 */ 00908 case 0x9050: /* 10/100 TPO */ 00909 case 0x9051: /* 10 Base Combo */ 00910 inf_3c90x->isBrev = 0; 00911 break; 00912 } 00913 00914 DBG("[3c90x]: found NIC(0x%04X, 0x%04X), isBrev=%d, is3c556=%d\n", 00915 pci->vendor, pci->device, inf_3c90x->isBrev, 00916 inf_3c90x->is3c556); 00917 00918 /* initialize nvs device */ 00919 inf_3c90x->nvs.word_len_log2 = 1; /* word */ 00920 inf_3c90x->nvs.size = (inf_3c90x->isBrev ? 0x20 : 0x17); 00921 inf_3c90x->nvs.block_size = 1; 00922 inf_3c90x->nvs.read = a3c90x_internal_ReadEeprom; 00923 inf_3c90x->nvs.write = a3c90x_internal_WriteEeprom; 00924 00925 /* reset NIC before accessing any data from it */ 00926 a3c90x_reset(inf_3c90x); 00927 00928 /* load eeprom contents to inf_3c90x->eeprom */ 00929 a3c90x_internal_ReadEepromContents(inf_3c90x); 00930 00931 HWAddr = netdev->hw_addr; 00932 00933 /* Retrieve the Hardware address */ 00934 HWAddr[0] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] >> 8; 00935 HWAddr[1] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] & 0xFF; 00936 HWAddr[2] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] >> 8; 00937 HWAddr[3] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] & 0xFF; 00938 HWAddr[4] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] >> 8; 00939 HWAddr[5] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] & 0xFF; 00940 00941 /* we don't handle linkstates yet, so we're always up */ 00942 netdev_link_up(netdev); 00943 00944 if ((rc = register_netdev(netdev)) != 0) { 00945 DBG("3c90x: register_netdev() failed\n"); 00946 netdev_put(netdev); 00947 return rc; 00948 } 00949 00950 return 0; 00951 }
struct net_device_operations a3c90x_operations [static] |
Initial value:
{
.open = a3c90x_open,
.close = a3c90x_close,
.poll = a3c90x_poll,
.transmit = a3c90x_transmit,
.irq = a3c90x_irq,
}
struct pci_device_id a3c90x_nics[] [static] |
Initial value:
{
PCI_ROM(0x10b7, 0x6055, "3c556", "3C556", 0),
PCI_ROM(0x10b7, 0x9000, "3c905-tpo", "3Com900-TPO", 0),
PCI_ROM(0x10b7, 0x9001, "3c905-t4", "3Com900-Combo", 0),
PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX", 0),
PCI_ROM(0x10b7, 0x9051, "3c905-combo", "3Com905-T4", 0),
PCI_ROM(0x10b7, 0x9004, "3c905b-tpo", "3Com900B-TPO", 0),
PCI_ROM(0x10b7, 0x9005, "3c905b-combo", "3Com900B-Combo", 0),
PCI_ROM(0x10b7, 0x9006, "3c905b-tpb2", "3Com900B-2/T", 0),
PCI_ROM(0x10b7, 0x900a, "3c905b-fl", "3Com900B-FL", 0),
PCI_ROM(0x10b7, 0x9055, "3c905b-tpo100", "3Com905B-TX", 0),
PCI_ROM(0x10b7, 0x9056, "3c905b-t4", "3Com905B-T4", 0),
PCI_ROM(0x10b7, 0x9058, "3c905b-9058", "3Com905B-9058", 0),
PCI_ROM(0x10b7, 0x905a, "3c905b-fx", "3Com905B-FL", 0),
PCI_ROM(0x10b7, 0x9200, "3c905c-tpo", "3Com905C-TXM", 0),
PCI_ROM(0x10b7, 0x9202, "3c920b-emb-ati", "3c920B-EMB-WNM (ATI Radeon 9100 IGP)", 0),
PCI_ROM(0x10b7, 0x9210, "3c920b-emb-wnm", "3Com20B-EMB WNM", 0),
PCI_ROM(0x10b7, 0x9800, "3c980", "3Com980-Cyclone", 0),
PCI_ROM(0x10b7, 0x9805, "3c9805", "3Com9805", 0),
PCI_ROM(0x10b7, 0x7646, "3csoho100-tx", "3CSOHO100-TX", 0),
PCI_ROM(0x10b7, 0x4500, "3c450", "3Com450 HomePNA Tornado", 0),
PCI_ROM(0x10b7, 0x1201, "3c982a", "3Com982A", 0),
PCI_ROM(0x10b7, 0x1202, "3c982b", "3Com982B", 0),
}
| struct pci_driver a3c90x_driver __pci_driver |
Initial value:
{
.ids = a3c90x_nics,
.id_count = (sizeof(a3c90x_nics) / sizeof(a3c90x_nics[0])),
.probe = a3c90x_probe,
.remove = a3c90x_remove,
}
1.5.7.1