2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
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 (at your option) any later version.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER );
25 #include <ipxe/settings.h>
26 #include <ipxe/init.h>
34 /** PCI device settings scope */
35 static const struct settings_scope pci_settings_scope;
38 * Check applicability of PCI device setting
40 * @v settings Settings block
42 * @ret applies Setting applies within this settings block
44 static int pci_settings_applies ( struct settings *settings __unused,
45 const struct setting *setting ) {
47 return ( setting->scope == &pci_settings_scope );
51 * Fetch value of PCI device setting
53 * @v settings Settings block
54 * @v setting Setting to fetch
55 * @v data Buffer to fill with setting data
56 * @v len Length of buffer
57 * @ret len Length of setting data, or negative error
59 static int pci_settings_fetch ( struct settings *settings __unused,
60 struct setting *setting,
61 void *data, size_t len ) {
62 struct pci_device pci;
63 unsigned int tag_busdevfn;
64 unsigned int tag_offset;
68 /* Extract busdevfn, offset, and length from tag */
69 tag_busdevfn = ( ( setting->tag >> 16 ) & 0xffff );
70 tag_offset = ( ( setting->tag >> 8 ) & 0xff );
71 tag_len = ( ( setting->tag >> 0 ) & 0xff );
73 /* Locate PCI device */
74 memset ( &pci, 0, sizeof ( pci ) );
75 pci_init ( &pci, tag_busdevfn );
76 DBG ( PCI_FMT " reading %#02x+%#x\n", PCI_ARGS ( &pci ),
77 tag_offset, tag_len );
79 /* Read data one byte at a time, in reverse order (since PCI
80 * is little-endian and iPXE settings are essentially
83 tag_offset += tag_len;
84 for ( i = 0 ; ( ( i < tag_len ) && ( i < len ) ); i++ ) {
85 pci_read_config_byte ( &pci, --tag_offset, data++ );
88 /* Set type to ":hexraw" if not already specified */
89 if ( ! setting->type )
90 setting->type = &setting_type_hexraw;
95 /** PCI device settings operations */
96 static struct settings_operations pci_settings_operations = {
97 .applies = pci_settings_applies,
98 .fetch = pci_settings_fetch,
101 /** PCI device settings */
102 static struct settings pci_settings = {
104 .siblings = LIST_HEAD_INIT ( pci_settings.siblings ),
105 .children = LIST_HEAD_INIT ( pci_settings.children ),
106 .op = &pci_settings_operations,
107 .default_scope = &pci_settings_scope,
110 /** Initialise PCI device settings */
111 static void pci_settings_init ( void ) {
114 if ( ( rc = register_settings ( &pci_settings, NULL, "pci" ) ) != 0 ) {
115 DBG ( "PCI could not register settings: %s\n",
121 /** PCI device settings initialiser */
122 struct init_fn pci_settings_init_fn __init_fn ( INIT_NORMAL ) = {
123 .initialise = pci_settings_init,