summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/drivers/net/undionly.c
blob: 9c9ca1274ebc4e6a8d61138c68fea1f3aa6eaaac (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
139
140
141
142
143
144
145
/*
 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *
 * You can also choose to distribute this program under the terms of
 * the Unmodified Binary Distribution Licence (as given in the file
 * COPYING.UBDL), provided that you have satisfied its requirements.
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ipxe/device.h>
#include <ipxe/init.h>
#include <ipxe/pci.h>
#include <undi.h>
#include <undinet.h>
#include <undipreload.h>

/** @file
 *
 * "Pure" UNDI driver
 *
 * This is the UNDI driver without explicit support for PCI or any
 * other bus type.  It is capable only of using the preloaded UNDI
 * device.  It must not be combined in an image with any other
 * drivers.
 *
 * If you want a PXE-loadable image that contains only the UNDI
 * driver, build "bin/undionly.kpxe".
 *
 * If you want any other image format, or any other drivers in
 * addition to the UNDI driver, build e.g. "bin/undi.dsk".
 */

/** UNDI root bus device */
static struct device undibus_dev;

/**
 * Probe UNDI root bus
 *
 * @v rootdev		UNDI bus root device
 *
 * Scans the UNDI bus for devices and registers all devices it can
 * find.
 */
static int undibus_probe ( struct root_device *rootdev ) {
	struct undi_device *undi = &preloaded_undi;
	struct device *dev = &undibus_dev;
	int rc;

	/* Check for a valie preloaded UNDI device */
	if ( ! undi->entry.segment ) {
		DBG ( "No preloaded UNDI device found!\n" );
		return -ENODEV;
	}

	/* Add to device hierarchy */
	dev->driver_name = "undionly";
	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
		dev->desc.bus_type = BUS_TYPE_PCI;
		dev->desc.location = undi->pci_busdevfn;
		dev->desc.vendor = undi->pci_vendor;
		dev->desc.device = undi->pci_device;
		snprintf ( dev->name, sizeof ( dev->name ),
			   "0000:%02x:%02x.%x", PCI_BUS ( undi->pci_busdevfn ),
			   PCI_SLOT ( undi->pci_busdevfn ),
			   PCI_FUNC ( undi->pci_busdevfn ) );
	} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
		dev->desc.bus_type = BUS_TYPE_ISAPNP;
		snprintf ( dev->name, sizeof ( dev->name ), "ISAPNP" );
	}
	dev->parent = &rootdev->dev;
	list_add ( &dev->siblings, &rootdev->dev.children);
	INIT_LIST_HEAD ( &dev->children );

	/* Create network device */
	if ( ( rc = undinet_probe ( undi, dev ) ) != 0 )
		goto err;

	return 0;

 err:
	list_del ( &dev->siblings );
	return rc;
}

/**
 * Remove UNDI root bus
 *
 * @v rootdev		UNDI bus root device
 */
static void undibus_remove ( struct root_device *rootdev __unused ) {
	struct undi_device *undi = &preloaded_undi;
	struct device *dev = &undibus_dev;

	undinet_remove ( undi );
	list_del ( &dev->siblings );
}

/** UNDI bus root device driver */
static struct root_driver undi_root_driver = {
	.probe = undibus_probe,
	.remove = undibus_remove,
};

/** UNDI bus root device */
struct root_device undi_root_device __root_device = {
	.dev = { .name = "UNDI" },
	.driver = &undi_root_driver,
};

/**
 * Prepare for exit
 *
 * @v booting		System is shutting down for OS boot
 */
static void undionly_shutdown ( int booting ) {
	/* If we are shutting down to boot an OS, clear the "keep PXE
	 * stack" flag.
	 */
	if ( booting )
		preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
}

struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
	.shutdown = undionly_shutdown,
};