iPXE
legacy.c
Go to the documentation of this file.
00001 #include <stdint.h>
00002 #include <stdio.h>
00003 #include <errno.h>
00004 #include <ipxe/if_ether.h>
00005 #include <ipxe/netdevice.h>
00006 #include <ipxe/ethernet.h>
00007 #include <ipxe/iobuf.h>
00008 #include <nic.h>
00009 
00010 /*
00011  * Quick and dirty compatibility layer
00012  *
00013  * This should allow old-API PCI drivers to at least function until
00014  * they are updated.  It will not help non-PCI drivers.
00015  *
00016  * No drivers should rely on this code.  It will be removed asap.
00017  *
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00021 
00022 struct nic nic;
00023 
00024 static int legacy_registered = 0;
00025 
00026 static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
00027         struct nic *nic = netdev->priv;
00028         struct ethhdr *ethhdr;
00029 
00030         DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) );
00031         iob_pad ( iobuf, ETH_ZLEN );
00032         ethhdr = iobuf->data;
00033         iob_pull ( iobuf, sizeof ( *ethhdr ) );
00034         nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
00035                                 ntohs ( ethhdr->h_protocol ),
00036                                 iob_len ( iobuf ), iobuf->data );
00037         netdev_tx_complete ( netdev, iobuf );
00038         return 0;
00039 }
00040 
00041 static void legacy_poll ( struct net_device *netdev ) {
00042         struct nic *nic = netdev->priv;
00043         struct io_buffer *iobuf;
00044 
00045         iobuf = alloc_iob ( ETH_FRAME_LEN );
00046         if ( ! iobuf )
00047                 return;
00048 
00049         nic->packet = iobuf->data;
00050         if ( nic->nic_op->poll ( nic, 1 ) ) {
00051                 DBG ( "Received %d bytes\n", nic->packetlen );
00052                 iob_put ( iobuf, nic->packetlen );
00053                 netdev_rx ( netdev, iobuf );
00054         } else {
00055                 free_iob ( iobuf );
00056         }
00057 }
00058 
00059 static int legacy_open ( struct net_device *netdev __unused ) {
00060         /* Nothing to do */
00061         return 0;
00062 }
00063 
00064 static void legacy_close ( struct net_device *netdev __unused ) {
00065         /* Nothing to do */
00066 }
00067 
00068 static void legacy_irq ( struct net_device *netdev __unused, int enable ) {
00069         struct nic *nic = netdev->priv;
00070 
00071         nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) );
00072 }
00073 
00074 static struct net_device_operations legacy_operations = {
00075         .open           = legacy_open,
00076         .close          = legacy_close,
00077         .transmit       = legacy_transmit,
00078         .poll           = legacy_poll,
00079         .irq            = legacy_irq,
00080 };
00081 
00082 int legacy_probe ( void *hwdev,
00083                    void ( * set_drvdata ) ( void *hwdev, void *priv ),
00084                    struct device *dev,
00085                    int ( * probe ) ( struct nic *nic, void *hwdev ),
00086                    void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
00087         struct net_device *netdev;
00088         int rc;
00089 
00090         if ( legacy_registered )
00091                 return -EBUSY;
00092         
00093         netdev = alloc_etherdev ( 0 );
00094         if ( ! netdev )
00095                 return -ENOMEM;
00096         netdev_init ( netdev, &legacy_operations );
00097         netdev->priv = &nic;
00098         memset ( &nic, 0, sizeof ( nic ) );
00099         set_drvdata ( hwdev, netdev );
00100         netdev->dev = dev;
00101 
00102         nic.node_addr = netdev->hw_addr;
00103         nic.irqno = dev->desc.irq;
00104 
00105         if ( ! probe ( &nic, hwdev ) ) {
00106                 rc = -ENODEV;
00107                 goto err_probe;
00108         }
00109 
00110         /* Overwrite the IRQ number.  Some legacy devices set
00111          * nic->irqno to 0 in the probe routine to indicate that they
00112          * don't support interrupts; doing this allows the timer
00113          * interrupt to be used instead.
00114          */
00115         dev->desc.irq = nic.irqno;
00116 
00117         if ( ( rc = register_netdev ( netdev ) ) != 0 )
00118                 goto err_register;
00119 
00120         /* Mark as link up; legacy devices don't handle link state */
00121         netdev_link_up ( netdev );
00122 
00123         /* Do not remove this message */
00124         printf ( "WARNING: Using legacy NIC wrapper on %s\n",
00125                  netdev->ll_protocol->ntoa ( nic.node_addr ) );
00126 
00127         legacy_registered = 1;
00128         return 0;
00129 
00130  err_register:
00131         disable ( &nic, hwdev );
00132  err_probe:
00133         netdev_nullify ( netdev );
00134         netdev_put ( netdev );
00135         return rc;
00136 }
00137 
00138 void legacy_remove ( void *hwdev,
00139                      void * ( * get_drvdata ) ( void *hwdev ),
00140                      void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
00141         struct net_device *netdev = get_drvdata ( hwdev );
00142         struct nic *nic = netdev->priv;
00143 
00144         unregister_netdev ( netdev );
00145         disable ( nic, hwdev );
00146         netdev_nullify ( netdev );
00147         netdev_put ( netdev );
00148         legacy_registered = 0;
00149 }
00150 
00151 int dummy_connect ( struct nic *nic __unused ) {
00152         return 1;
00153 }
00154 
00155 void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
00156         return;
00157 }