1 /* 2 * Copyright (C) 2007 Michael Brown <mbrown (at) 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 */ 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 */ 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 */ 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