Fix padding problem - from Michael
[people/pcmattman/gpxe.git] / src / drivers / net / legacy.c
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <gpxe/if_ether.h>
5 #include <gpxe/netdevice.h>
6 #include <gpxe/ethernet.h>
7 #include <gpxe/pkbuff.h>
8 #include <nic.h>
9
10 /*
11  * Quick and dirty compatibility layer
12  *
13  * This should allow old-API PCI drivers to at least function until
14  * they are updated.  It will not help non-PCI drivers.
15  *
16  * No drivers should rely on this code.  It will be removed asap.
17  *
18  */
19
20 struct nic nic;
21
22 static int legacy_registered = 0;
23
24 static int legacy_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
25         struct nic *nic = netdev->priv;
26         struct ethhdr *ethhdr = pkb->data;
27         int pad_len;
28
29         DBG ( "Transmitting %d bytes\n", pkb_len ( pkb ) );
30         pkb_pad ( pkb, ETH_ZLEN );
31         pkb_pull ( pkb, sizeof ( *ethhdr ) );
32         nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
33                                 ntohs ( ethhdr->h_protocol ),
34                                 pkb_len ( pkb ), pkb->data );
35         netdev_tx_complete ( netdev, pkb );
36         return 0;
37 }
38
39 static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) {
40         struct nic *nic = netdev->priv;
41         struct pk_buff *pkb;
42
43         if ( ! rx_quota )
44                 return;
45
46         pkb = alloc_pkb ( ETH_FRAME_LEN );
47         if ( ! pkb )
48                 return;
49
50         nic->packet = pkb->data;
51         if ( nic->nic_op->poll ( nic, 1 ) ) {
52                 DBG ( "Received %d bytes\n", nic->packetlen );
53                 pkb_put ( pkb, nic->packetlen );
54                 netdev_rx ( netdev, pkb );
55         } else {
56                 free_pkb ( pkb );
57         }
58 }
59
60 static int legacy_open ( struct net_device *netdev __unused ) {
61         return 0;
62 }
63
64 static void legacy_close ( struct net_device *netdev __unused ) {
65         /* Nothing to do */
66 }
67
68 int legacy_probe ( struct pci_device *pci,
69                    const struct pci_device_id *id __unused,
70                    int ( * probe ) ( struct nic *nic,
71                                      struct pci_device *pci ),
72                    void ( * disable ) ( struct nic *nic ) ) {
73         struct net_device *netdev;
74         int rc;
75
76         if ( legacy_registered )
77                 return -EBUSY;
78         
79         netdev = alloc_etherdev ( 0 );
80         if ( ! netdev )
81                 return -ENOMEM;
82         netdev->priv = &nic;
83         memset ( &nic, 0, sizeof ( nic ) );
84         pci_set_drvdata ( pci, netdev );
85         netdev->dev = &pci->dev;
86
87         netdev->open = legacy_open;
88         netdev->close = legacy_close;
89         netdev->transmit = legacy_transmit;
90         netdev->poll = legacy_poll;
91         nic.node_addr = netdev->ll_addr;
92
93         if ( ! probe ( &nic, pci ) ) {
94                 free_netdev ( netdev );
95                 return -ENODEV;
96         }
97
98         if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
99                 disable ( &nic );
100                 free_netdev ( netdev );
101                 return rc;
102         }
103
104         /* Do not remove this message */
105         printf ( "WARNING: Using legacy NIC wrapper on %s\n",
106                  ethernet_protocol.ntoa ( nic.node_addr ) );
107
108         legacy_registered = 1;
109         return 0;
110 }
111
112 void legacy_remove ( struct pci_device *pci,
113                      void ( * disable ) ( struct nic *nic ) ) {
114         struct net_device *netdev = pci_get_drvdata ( pci );
115         struct nic *nic = netdev->priv;
116
117         unregister_netdev ( netdev );
118         disable ( nic );
119         free_netdev ( netdev );
120         legacy_registered = 0;
121 }
122
123 void pci_fill_nic ( struct nic *nic, struct pci_device *pci ) {
124         nic->ioaddr = pci->ioaddr;
125         nic->irqno = pci->irq;
126 }
127
128 int dummy_connect ( struct nic *nic __unused ) {
129         return 1;
130 }
131
132 void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
133         return;
134 }
135
136 REQUIRE_OBJECT ( pci );