#include #include #include #include #include #include #include #include /* * Quick and dirty compatibility layer * * This should allow old-API PCI drivers to at least function until * they are updated. It will not help non-PCI drivers. * * No drivers should rely on this code. It will be removed asap. * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct nic legacy_nic; static int legacy_registered = 0; static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct nic *nic = netdev->priv; struct ethhdr *ethhdr; DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) ); iob_pad ( iobuf, ETH_ZLEN ); ethhdr = iobuf->data; iob_pull ( iobuf, sizeof ( *ethhdr ) ); nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest, ntohs ( ethhdr->h_protocol ), iob_len ( iobuf ), iobuf->data ); netdev_tx_complete ( netdev, iobuf ); return 0; } static void legacy_poll ( struct net_device *netdev ) { struct nic *nic = netdev->priv; struct io_buffer *iobuf; iobuf = alloc_iob ( ETH_FRAME_LEN + 4 /* possible VLAN */ + 4 /* possible CRC */ ); if ( ! iobuf ) return; nic->packet = iobuf->data; if ( nic->nic_op->poll ( nic, 1 ) ) { DBG ( "Received %d bytes\n", nic->packetlen ); iob_put ( iobuf, nic->packetlen ); netdev_rx ( netdev, iobuf ); } else { free_iob ( iobuf ); } } static int legacy_open ( struct net_device *netdev __unused ) { /* Nothing to do */ return 0; } static void legacy_close ( struct net_device *netdev __unused ) { /* Nothing to do */ } static void legacy_irq ( struct net_device *netdev __unused, int enable ) { struct nic *nic = netdev->priv; nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) ); } static struct net_device_operations legacy_operations = { .open = legacy_open, .close = legacy_close, .transmit = legacy_transmit, .poll = legacy_poll, .irq = legacy_irq, }; int legacy_probe ( void *hwdev, void ( * set_drvdata ) ( void *hwdev, void *priv ), struct device *dev, int ( * probe ) ( struct nic *nic, void *hwdev ), void ( * disable ) ( struct nic *nic, void *hwdev ), size_t fake_bss_len ) { struct net_device *netdev; struct nic *nic; int rc; if ( legacy_registered ) { rc = -EBUSY; goto err_registered; } netdev = alloc_etherdev ( 0 ); if ( ! netdev ) { rc = -ENOMEM; goto err_alloc; } netdev_init ( netdev, &legacy_operations ); nic = &legacy_nic; netdev->priv = nic; memset ( nic, 0, sizeof ( *nic ) ); set_drvdata ( hwdev, netdev ); netdev->dev = dev; nic->node_addr = netdev->hw_addr; nic->irqno = dev->desc.irq; if ( fake_bss_len ) { nic->fake_bss = malloc_phys ( fake_bss_len, PAGE_SIZE ); if ( ! nic->fake_bss ) { rc = -ENOMEM; goto err_fake_bss; } } nic->fake_bss_len = fake_bss_len; if ( ! probe ( nic, hwdev ) ) { rc = -ENODEV; goto err_probe; } /* Overwrite the IRQ number. Some legacy devices set * nic->irqno to 0 in the probe routine to indicate that they * don't support interrupts; doing this allows the timer * interrupt to be used instead. */ dev->desc.irq = nic->irqno; if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err_register; /* Mark as link up; legacy devices don't handle link state */ netdev_link_up ( netdev ); /* Do not remove this message */ printf ( "WARNING: Using legacy NIC wrapper on %s\n", netdev->ll_protocol->ntoa ( nic->node_addr ) ); legacy_registered = 1; return 0; err_register: disable ( nic, hwdev ); err_probe: if ( fake_bss_len ) free_phys ( nic->fake_bss, fake_bss_len ); err_fake_bss: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: err_registered: return rc; } void legacy_remove ( void *hwdev, void * ( * get_drvdata ) ( void *hwdev ), void ( * disable ) ( struct nic *nic, void *hwdev ) ) { struct net_device *netdev = get_drvdata ( hwdev ); struct nic *nic = netdev->priv; unregister_netdev ( netdev ); disable ( nic, hwdev ); if ( nic->fake_bss_len ) free_phys ( nic->fake_bss, nic->fake_bss_len ); netdev_nullify ( netdev ); netdev_put ( netdev ); legacy_registered = 0; } int dummy_connect ( struct nic *nic __unused ) { return 1; } void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) { return; }