1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 FILE_LICENCE ( GPL2_OR_LATER );
20 
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <gpxe/device.h>
25 #include <gpxe/init.h>
26 #include <undi.h>
27 #include <undinet.h>
28 #include <undipreload.h>
29 
30 /** @file
31  *
32  * "Pure" UNDI driver
33  *
34  * This is the UNDI driver without explicit support for PCI or any
35  * other bus type.  It is capable only of using the preloaded UNDI
36  * device.  It must not be combined in an image with any other
37  * drivers.
38  *
39  * If you want a PXE-loadable image that contains only the UNDI
40  * driver, build "bin/undionly.kpxe".
41  *
42  * If you want any other image format, or any other drivers in
43  * addition to the UNDI driver, build e.g. "bin/undi.dsk".
44  */
45 
46 /**
47  * Probe UNDI root bus
48  *
49  * @v rootdev		UNDI bus root device
50  *
51  * Scans the UNDI bus for devices and registers all devices it can
52  * find.
53  */
undibus_probe(struct root_device * rootdev)54 static int undibus_probe ( struct root_device *rootdev ) {
55 	struct undi_device *undi = &preloaded_undi;
56 	int rc;
57 
58 	/* Check for a valie preloaded UNDI device */
59 	if ( ! undi->entry.segment ) {
60 		DBG ( "No preloaded UNDI device found!\n" );
61 		return -ENODEV;
62 	}
63 
64 	/* Add to device hierarchy */
65 	strncpy ( undi->dev.name, "UNDI",
66 		  ( sizeof ( undi->dev.name ) - 1 ) );
67 	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
68 		undi->dev.desc.bus_type = BUS_TYPE_PCI;
69 		undi->dev.desc.location = undi->pci_busdevfn;
70 		undi->dev.desc.vendor = undi->pci_vendor;
71 		undi->dev.desc.device = undi->pci_device;
72 	} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
73 		undi->dev.desc.bus_type = BUS_TYPE_ISAPNP;
74 	}
75 	undi->dev.parent = &rootdev->dev;
76 	list_add ( &undi->dev.siblings, &rootdev->dev.children);
77 	INIT_LIST_HEAD ( &undi->dev.children );
78 
79 	/* Create network device */
80 	if ( ( rc = undinet_probe ( undi ) ) != 0 )
81 		goto err;
82 
83 	return 0;
84 
85  err:
86 	list_del ( &undi->dev.siblings );
87 	return rc;
88 }
89 
90 /**
91  * Remove UNDI root bus
92  *
93  * @v rootdev		UNDI bus root device
94  */
undibus_remove(struct root_device * rootdev __unused)95 static void undibus_remove ( struct root_device *rootdev __unused ) {
96 	struct undi_device *undi = &preloaded_undi;
97 
98 	undinet_remove ( undi );
99 	list_del ( &undi->dev.siblings );
100 }
101 
102 /** UNDI bus root device driver */
103 static struct root_driver undi_root_driver = {
104 	.probe = undibus_probe,
105 	.remove = undibus_remove,
106 };
107 
108 /** UNDI bus root device */
109 struct root_device undi_root_device __root_device = {
110 	.dev = { .name = "UNDI" },
111 	.driver = &undi_root_driver,
112 };
113 
114 /**
115  * Prepare for exit
116  *
117  * @v flags		Shutdown flags
118  */
undionly_shutdown(int flags)119 static void undionly_shutdown ( int flags ) {
120 	/* If we are shutting down to boot an OS, clear the "keep PXE
121 	 * stack" flag.
122 	 */
123 	if ( flags & SHUTDOWN_BOOT )
124 		preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
125 }
126 
127 struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
128 	.shutdown = undionly_shutdown,
129 };
130