summaryrefslogtreecommitdiffstats
path: root/src/drivers/net/legacy.c
blob: 1719c82af7b7833ad669cf56a3ea50e2ca1d283b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <gpxe/if_ether.h>
#include <gpxe/netdevice.h>
#include <gpxe/ethernet.h>
#include <gpxe/pkbuff.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.
 *
 */

struct nic nic;

static int legacy_registered = 0;

static int legacy_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
	struct nic *nic = netdev->priv;
	struct ethhdr *ethhdr = pkb->data;
	int pad_len;

	DBG ( "Transmitting %d bytes\n", pkb_len ( pkb ) );
	pad_len = ( ETH_ZLEN - pkb_len ( pkb ) );
	if ( pad_len > 0 )
		memset ( pkb_put ( pkb, pad_len ), 0, pad_len );
	pkb_pull ( pkb, sizeof ( *ethhdr ) );
	nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
				ntohs ( ethhdr->h_protocol ),
				pkb_len ( pkb ), pkb->data );
	netdev_tx_complete ( netdev, pkb );
	return 0;
}

static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) {
	struct nic *nic = netdev->priv;
	struct pk_buff *pkb;

	if ( ! rx_quota )
		return;

	pkb = alloc_pkb ( ETH_FRAME_LEN );
	if ( ! pkb )
		return;

	nic->packet = pkb->data;
	if ( nic->nic_op->poll ( nic, 1 ) ) {
		DBG ( "Received %d bytes\n", nic->packetlen );
		pkb_put ( pkb, nic->packetlen );
		netdev_rx ( netdev, pkb );
	} else {
		free_pkb ( pkb );
	}
}

static int legacy_open ( struct net_device *netdev __unused ) {
	return 0;
}

static void legacy_close ( struct net_device *netdev __unused ) {
	/* Nothing to do */
}

int legacy_probe ( struct pci_device *pci,
		   const struct pci_device_id *id __unused,
		   int ( * probe ) ( struct nic *nic,
				     struct pci_device *pci ),
		   void ( * disable ) ( struct nic *nic ) ) {
	struct net_device *netdev;
	int rc;

	if ( legacy_registered )
		return -EBUSY;
	
	netdev = alloc_etherdev ( 0 );
	if ( ! netdev )
		return -ENOMEM;
	netdev->priv = &nic;
	memset ( &nic, 0, sizeof ( nic ) );
	pci_set_drvdata ( pci, netdev );
	netdev->dev = &pci->dev;

	netdev->open = legacy_open;
	netdev->close = legacy_close;
	netdev->transmit = legacy_transmit;
	netdev->poll = legacy_poll;
	nic.node_addr = netdev->ll_addr;

	if ( ! probe ( &nic, pci ) ) {
		free_netdev ( netdev );
		return -ENODEV;
	}

	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
		disable ( &nic );
		free_netdev ( netdev );
		return rc;
	}

	/* Do not remove this message */
	printf ( "WARNING: Using legacy NIC wrapper on %s\n",
		 ethernet_protocol.ntoa ( nic.node_addr ) );

	legacy_registered = 1;
	return 0;
}

void legacy_remove ( struct pci_device *pci,
		     void ( * disable ) ( struct nic *nic ) ) {
	struct net_device *netdev = pci_get_drvdata ( pci );
	struct nic *nic = netdev->priv;

	unregister_netdev ( netdev );
	disable ( nic );
	free_netdev ( netdev );
	legacy_registered = 0;
}

void pci_fill_nic ( struct nic *nic, struct pci_device *pci ) {
	nic->ioaddr = pci->ioaddr;
	nic->irqno = pci->irq;
}

int dummy_connect ( struct nic *nic __unused ) {
	return 1;
}

void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
	return;
}

REQUIRE_OBJECT ( pci );