iPXE
pci_settings.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdio.h>
00027 #include <errno.h>
00028 #include <ipxe/pci.h>
00029 #include <ipxe/settings.h>
00030 #include <ipxe/init.h>
00031 
00032 /** @file
00033  *
00034  * PCI device settings
00035  *
00036  */
00037 
00038 /** PCI device settings scope */
00039 static const struct settings_scope pci_settings_scope;
00040 
00041 /**
00042  * Check applicability of PCI device setting
00043  *
00044  * @v settings          Settings block
00045  * @v setting           Setting
00046  * @ret applies         Setting applies within this settings block
00047  */
00048 static int pci_settings_applies ( struct settings *settings __unused,
00049                                   const struct setting *setting ) {
00050 
00051         return ( setting->scope == &pci_settings_scope );
00052 }
00053 
00054 /**
00055  * Fetch value of PCI device setting
00056  *
00057  * @v settings          Settings block
00058  * @v setting           Setting to fetch
00059  * @v data              Buffer to fill with setting data
00060  * @v len               Length of buffer
00061  * @ret len             Length of setting data, or negative error
00062  */
00063 static int pci_settings_fetch ( struct settings *settings __unused,
00064                                 struct setting *setting,
00065                                 void *data, size_t len ) {
00066         struct pci_device pci;
00067         unsigned int tag_busdevfn;
00068         unsigned int tag_offset;
00069         unsigned int tag_len;
00070         unsigned int i;
00071 
00072         /* Extract busdevfn, offset, and length from tag */
00073         tag_busdevfn = ( setting->tag >> 16 );
00074         tag_offset = ( ( setting->tag >> 8 ) & 0xff );
00075         tag_len = ( ( setting->tag >> 0 ) & 0xff );
00076 
00077         /* Locate PCI device */
00078         memset ( &pci, 0, sizeof ( pci ) );
00079         pci_init ( &pci, tag_busdevfn );
00080         DBG ( PCI_FMT " reading %#02x+%#x\n", PCI_ARGS ( &pci ),
00081               tag_offset, tag_len );
00082 
00083         /* Read data one byte at a time, in reverse order (since PCI
00084          * is little-endian and iPXE settings are essentially
00085          * big-endian).
00086          */
00087         tag_offset += tag_len;
00088         for ( i = 0 ; ( ( i < tag_len ) && ( i < len ) ); i++ ) {
00089                 pci_read_config_byte ( &pci, --tag_offset, data++ );
00090         }
00091 
00092         /* Set type to ":hexraw" if not already specified */
00093         if ( ! setting->type )
00094                 setting->type = &setting_type_hexraw;
00095 
00096         return tag_len;
00097 }
00098 
00099 /** PCI device settings operations */
00100 static struct settings_operations pci_settings_operations = {
00101         .applies = pci_settings_applies,
00102         .fetch = pci_settings_fetch,
00103 };
00104 
00105 /** PCI device settings */
00106 static struct settings pci_settings = {
00107         .refcnt = NULL,
00108         .siblings = LIST_HEAD_INIT ( pci_settings.siblings ),
00109         .children = LIST_HEAD_INIT ( pci_settings.children ),
00110         .op = &pci_settings_operations,
00111         .default_scope = &pci_settings_scope,
00112 };
00113 
00114 /** Initialise PCI device settings */
00115 static void pci_settings_init ( void ) {
00116         int rc;
00117 
00118         if ( ( rc = register_settings ( &pci_settings, NULL, "pci" ) ) != 0 ) {
00119                 DBG ( "PCI could not register settings: %s\n",
00120                       strerror ( rc ) );
00121                 return;
00122         }
00123 }
00124 
00125 /** PCI device settings initialiser */
00126 struct init_fn pci_settings_init_fn __init_fn ( INIT_NORMAL ) = {
00127         .initialise = pci_settings_init,
00128 };