176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanEtherboot - BOOTP/TFTP Bootstrap Program 376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanBochs Pseudo NIC driver for Etherboot 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2, or (at 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * your option) any later version. 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * See pnic_api.h for an explanation of the Bochs Pseudo NIC. 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/io.h> 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h> 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h> 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ethernet.h> 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h> 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h> 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "pnic_api.h" 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct pnic { 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned short ioaddr; 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Utility functions: issue a PNIC command, retrieve result. Use 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pnic_command_quiet if you don't want failure codes to be 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * automatically printed. Returns the PNIC status code. 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set output_length to NULL only if you expect to receive exactly 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * output_max_length bytes, otherwise it'll complain that you didn't 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * get enough data (on the assumption that if you not interested in 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * discovering the output length then you're expecting a fixed amount 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * of data). 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic uint16_t pnic_command_quiet ( struct pnic *pnic, uint16_t command, 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const void *input, uint16_t input_length, 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *output, uint16_t output_max_length, 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t *output_length ) { 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t status; 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t _output_length; 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( input != NULL ) { 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write input length */ 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outw ( input_length, pnic->ioaddr + PNIC_REG_LEN ); 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write input data */ 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outsb ( pnic->ioaddr + PNIC_REG_DATA, input, input_length ); 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write command */ 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman outw ( command, pnic->ioaddr + PNIC_REG_CMD ); 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Retrieve status */ 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = inw ( pnic->ioaddr + PNIC_REG_STAT ); 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Retrieve output length */ 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman _output_length = inw ( pnic->ioaddr + PNIC_REG_LEN ); 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( output_length == NULL ) { 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( _output_length != output_max_length ) { 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf ( "pnic_command %#hx: wrong data length " 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "returned (expected %d, got %d)\n", command, 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman output_max_length, _output_length ); 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *output_length = _output_length; 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( output != NULL ) { 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( _output_length > output_max_length ) { 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf ( "pnic_command %#hx: output buffer too small " 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "(have %d, need %d)\n", command, 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman output_max_length, _output_length ); 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman _output_length = output_max_length; 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Retrieve output data */ 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman insb ( pnic->ioaddr + PNIC_REG_DATA, output, _output_length ); 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status; 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic uint16_t pnic_command ( struct pnic *pnic, uint16_t command, 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const void *input, uint16_t input_length, 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *output, uint16_t output_max_length, 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t *output_length ) { 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t status = pnic_command_quiet ( pnic, command, 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman input, input_length, 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman output, output_max_length, 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman output_length ); 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( status == PNIC_STATUS_OK ) return status; 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf ( "PNIC command %#hx (len %#hx) failed with status %#hx\n", 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman command, input_length, status ); 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status; 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Check API version matches that of NIC */ 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int pnic_api_check ( uint16_t api_version ) { 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( api_version != PNIC_API_VERSION ) { 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf ( "Warning: API version mismatch! " 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "(NIC's is %d.%d, ours is %d.%d)\n", 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman api_version >> 8, api_version & 0xff, 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff ); 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( api_version < PNIC_API_VERSION ) { 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf ( "** You may need to update your copy of Bochs **\n" ); 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ( api_version == PNIC_API_VERSION ); 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 11576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPOLL - Wait for a frame 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pnic_poll ( struct net_device *netdev ) { 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct pnic *pnic = netdev->priv; 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf; 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t length; 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t qlen; 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fetch all available packets */ 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( 1 ) { 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0, 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &qlen, sizeof ( qlen ), NULL ) 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman != PNIC_STATUS_OK ) 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( qlen == 0 ) 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf = alloc_iob ( ETH_FRAME_LEN ); 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! iobuf ) { 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "could not allocate buffer\n" ); 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_err ( netdev, NULL, -ENOMEM ); 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0, 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iobuf->data, ETH_FRAME_LEN, &length ) 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman != PNIC_STATUS_OK ) { 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_err ( netdev, iobuf, -EIO ); 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_put ( iobuf, length ); 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx ( netdev, iobuf ); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 14976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanTRANSMIT - Transmit a frame 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct pnic *pnic = netdev->priv; 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Pad the packet */ 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_pad ( iobuf, ETH_ZLEN ); 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Send packet */ 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pnic_command ( pnic, PNIC_CMD_XMIT, iobuf->data, iob_len ( iobuf ), 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL, 0, NULL ); 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete ( netdev, iobuf ); 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 16676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanOPEN - Open network device 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int pnic_open ( struct net_device *netdev __unused ) { 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Nothing to do */ 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 17476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanCLOSE - Close network device 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pnic_close ( struct net_device *netdev __unused ) { 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Nothing to do */ 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 18176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanIRQ - Enable/disable interrupts 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pnic_irq ( struct net_device *netdev, int enable ) { 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct pnic *pnic = netdev->priv; 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t mask = ( enable ? 1 : 0 ); 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ), 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL, 0, NULL ); 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 19276d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanOPERATIONS TABLE 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct net_device_operations pnic_operations = { 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .open = pnic_open, 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .close = pnic_close, 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .transmit = pnic_transmit, 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .poll = pnic_poll, 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .irq = pnic_irq, 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 20376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanDISABLE - Turn off ethernet interface 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pnic_remove ( struct pci_device *pci ) { 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev = pci_get_drvdata ( pci ); 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct pnic *pnic = netdev->priv; 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unregister_netdev ( netdev ); 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL ); 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify ( netdev ); 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put ( netdev ); 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/************************************************************************** 21676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPROBE - Look for an adapter, this routine's visible to the outside 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman***************************************************************************/ 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int pnic_probe ( struct pci_device *pci, 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct pci_device_id *id __unused ) { 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct pnic *pnic; 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t api_version; 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t status; 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Allocate net device */ 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev = alloc_etherdev ( sizeof ( *pnic ) ); 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! netdev ) 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_init ( netdev, &pnic_operations ); 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pnic = netdev->priv; 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_set_drvdata ( pci, netdev ); 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->dev = &pci->dev; 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pnic->ioaddr = pci->ioaddr; 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fix up PCI device */ 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adjust_pci_device ( pci ); 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* API version check */ 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0, 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &api_version, 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sizeof ( api_version ), NULL ); 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( status != PNIC_STATUS_OK ) { 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf ( "PNIC failed installation check, code %#hx\n", 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status ); 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rc = -EIO; 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pnic_api_check ( api_version ); 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Get MAC address */ 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0, 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->hw_addr, ETH_ALEN, NULL ); 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Mark as link up; PNIC has no concept of link state */ 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_up ( netdev ); 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Register network device */ 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = register_netdev ( netdev ) ) != 0 ) 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err: 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Free net device */ 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify ( netdev ); 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put ( netdev ); 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id pnic_nics[] = { 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* genrules.pl doesn't let us use macros for PCI IDs...*/ 27376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ), 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct pci_driver pnic_driver __pci_driver = { 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .ids = pnic_nics, 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ), 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .probe = pnic_probe, 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .remove = pnic_remove, 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 282