| #include <stdint.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <ipxe/if_ether.h> |
| #include <ipxe/netdevice.h> |
| #include <ipxe/ethernet.h> |
| #include <ipxe/iobuf.h> |
| #include <nic.h> |
| |
| /* |
| * 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 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; |
| } |