#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 ); struct nic 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 ); 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 ) ) { struct net_device *netdev; int rc; if ( legacy_registered ) return -EBUSY; netdev = alloc_etherdev ( 0 ); if ( ! netdev ) return -ENOMEM; netdev_init ( netdev, &legacy_operations ); 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 ( ! 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: netdev_nullify ( netdev ); netdev_put ( netdev ); 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 ); 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; }