176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h>
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h>
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h>
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h>
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ethernet.h>
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h>
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <nic.h>
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Quick and dirty compatibility layer
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This should allow old-API PCI drivers to at least function until
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * they are updated.  It will not help non-PCI drivers.
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * No drivers should rely on this code.  It will be removed asap.
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER );
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct nic nic;
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int legacy_registered = 0;
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct nic *nic = netdev->priv;
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct ethhdr *ethhdr;
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) );
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iob_pad ( iobuf, ETH_ZLEN );
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ethhdr = iobuf->data;
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iob_pull ( iobuf, sizeof ( *ethhdr ) );
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				ntohs ( ethhdr->h_protocol ),
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				iob_len ( iobuf ), iobuf->data );
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_tx_complete ( netdev, iobuf );
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void legacy_poll ( struct net_device *netdev ) {
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct nic *nic = netdev->priv;
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct io_buffer *iobuf;
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf = alloc_iob ( ETH_FRAME_LEN );
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! iobuf )
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nic->packet = iobuf->data;
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( nic->nic_op->poll ( nic, 1 ) ) {
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Received %d bytes\n", nic->packetlen );
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		iob_put ( iobuf, nic->packetlen );
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		netdev_rx ( netdev, iobuf );
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		free_iob ( iobuf );
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int legacy_open ( struct net_device *netdev __unused ) {
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Nothing to do */
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void legacy_close ( struct net_device *netdev __unused ) {
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Nothing to do */
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void legacy_irq ( struct net_device *netdev __unused, int enable ) {
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct nic *nic = netdev->priv;
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) );
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct net_device_operations legacy_operations = {
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.open		= legacy_open,
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.close		= legacy_close,
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.transmit	= legacy_transmit,
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.poll		= legacy_poll,
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.irq   		= legacy_irq,
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint legacy_probe ( void *hwdev,
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   void ( * set_drvdata ) ( void *hwdev, void *priv ),
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   struct device *dev,
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   int ( * probe ) ( struct nic *nic, void *hwdev ),
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net_device *netdev;
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int rc;
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( legacy_registered )
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EBUSY;
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev = alloc_etherdev ( 0 );
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! netdev )
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_init ( netdev, &legacy_operations );
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev->priv = &nic;
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( &nic, 0, sizeof ( nic ) );
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	set_drvdata ( hwdev, netdev );
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev->dev = dev;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nic.node_addr = netdev->hw_addr;
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nic.irqno = dev->desc.irq;
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! probe ( &nic, hwdev ) ) {
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rc = -ENODEV;
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_probe;
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Overwrite the IRQ number.  Some legacy devices set
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * nic->irqno to 0 in the probe routine to indicate that they
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * don't support interrupts; doing this allows the timer
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * interrupt to be used instead.
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dev->desc.irq = nic.irqno;
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Mark as link up; legacy devices don't handle link state */
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_link_up ( netdev );
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ( rc = register_netdev ( netdev ) ) != 0 )
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_register;
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Do not remove this message */
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf ( "WARNING: Using legacy NIC wrapper on %s\n",
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 netdev->ll_protocol->ntoa ( nic.node_addr ) );
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	legacy_registered = 1;
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_register:
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	disable ( &nic, hwdev );
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_probe:
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_nullify ( netdev );
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_put ( netdev );
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return rc;
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid legacy_remove ( void *hwdev,
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		     void * ( * get_drvdata ) ( void *hwdev ),
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		     void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net_device *netdev = get_drvdata ( hwdev );
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct nic *nic = netdev->priv;
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unregister_netdev ( netdev );
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	disable ( nic, hwdev );
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_nullify ( netdev );
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_put ( netdev );
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	legacy_registered = 0;
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint dummy_connect ( struct nic *nic __unused ) {
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 1;
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return;
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
158