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/iobuf.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
20FILE_LICENCE ( GPL2_OR_LATER );
21
22struct nic nic;
23
24static int legacy_registered = 0;
25
26static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
27	struct nic *nic = netdev->priv;
28	struct ethhdr *ethhdr;
29
30	DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) );
31	iob_pad ( iobuf, ETH_ZLEN );
32	ethhdr = iobuf->data;
33	iob_pull ( iobuf, sizeof ( *ethhdr ) );
34	nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
35				ntohs ( ethhdr->h_protocol ),
36				iob_len ( iobuf ), iobuf->data );
37	netdev_tx_complete ( netdev, iobuf );
38	return 0;
39}
40
41static void legacy_poll ( struct net_device *netdev ) {
42	struct nic *nic = netdev->priv;
43	struct io_buffer *iobuf;
44
45	iobuf = alloc_iob ( ETH_FRAME_LEN );
46	if ( ! iobuf )
47		return;
48
49	nic->packet = iobuf->data;
50	if ( nic->nic_op->poll ( nic, 1 ) ) {
51		DBG ( "Received %d bytes\n", nic->packetlen );
52		iob_put ( iobuf, nic->packetlen );
53		netdev_rx ( netdev, iobuf );
54	} else {
55		free_iob ( iobuf );
56	}
57}
58
59static int legacy_open ( struct net_device *netdev __unused ) {
60	/* Nothing to do */
61	return 0;
62}
63
64static void legacy_close ( struct net_device *netdev __unused ) {
65	/* Nothing to do */
66}
67
68static void legacy_irq ( struct net_device *netdev __unused, int enable ) {
69	struct nic *nic = netdev->priv;
70
71	nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) );
72}
73
74static struct net_device_operations legacy_operations = {
75	.open		= legacy_open,
76	.close		= legacy_close,
77	.transmit	= legacy_transmit,
78	.poll		= legacy_poll,
79	.irq   		= legacy_irq,
80};
81
82int legacy_probe ( void *hwdev,
83		   void ( * set_drvdata ) ( void *hwdev, void *priv ),
84		   struct device *dev,
85		   int ( * probe ) ( struct nic *nic, void *hwdev ),
86		   void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
87	struct net_device *netdev;
88	int rc;
89
90	if ( legacy_registered )
91		return -EBUSY;
92
93	netdev = alloc_etherdev ( 0 );
94	if ( ! netdev )
95		return -ENOMEM;
96	netdev_init ( netdev, &legacy_operations );
97	netdev->priv = &nic;
98	memset ( &nic, 0, sizeof ( nic ) );
99	set_drvdata ( hwdev, netdev );
100	netdev->dev = dev;
101
102	nic.node_addr = netdev->hw_addr;
103	nic.irqno = dev->desc.irq;
104
105	if ( ! probe ( &nic, hwdev ) ) {
106		rc = -ENODEV;
107		goto err_probe;
108	}
109
110	/* Overwrite the IRQ number.  Some legacy devices set
111	 * nic->irqno to 0 in the probe routine to indicate that they
112	 * don't support interrupts; doing this allows the timer
113	 * interrupt to be used instead.
114	 */
115	dev->desc.irq = nic.irqno;
116
117	/* Mark as link up; legacy devices don't handle link state */
118	netdev_link_up ( netdev );
119
120	if ( ( rc = register_netdev ( netdev ) ) != 0 )
121		goto err_register;
122
123	/* Do not remove this message */
124	printf ( "WARNING: Using legacy NIC wrapper on %s\n",
125		 netdev->ll_protocol->ntoa ( nic.node_addr ) );
126
127	legacy_registered = 1;
128	return 0;
129
130 err_register:
131	disable ( &nic, hwdev );
132 err_probe:
133	netdev_nullify ( netdev );
134	netdev_put ( netdev );
135	return rc;
136}
137
138void legacy_remove ( void *hwdev,
139		     void * ( * get_drvdata ) ( void *hwdev ),
140		     void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
141	struct net_device *netdev = get_drvdata ( hwdev );
142	struct nic *nic = netdev->priv;
143
144	unregister_netdev ( netdev );
145	disable ( nic, hwdev );
146	netdev_nullify ( netdev );
147	netdev_put ( netdev );
148	legacy_registered = 0;
149}
150
151int dummy_connect ( struct nic *nic __unused ) {
152	return 1;
153}
154
155void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
156	return;
157}
158