(2006-08-06) rescue-bootcd
This commit is contained in:
1
extra/linux-2.6.10/drivers/firmware/.built-in.o.cmd
Normal file
1
extra/linux-2.6.10/drivers/firmware/.built-in.o.cmd
Normal file
@@ -0,0 +1 @@
|
||||
cmd_drivers/firmware/built-in.o := rm -f drivers/firmware/built-in.o; ar rcs drivers/firmware/built-in.o
|
||||
61
extra/linux-2.6.10/drivers/firmware/Kconfig
Normal file
61
extra/linux-2.6.10/drivers/firmware/Kconfig
Normal file
@@ -0,0 +1,61 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see Documentation/kbuild/kconfig-language.txt.
|
||||
#
|
||||
|
||||
menu "Firmware Drivers"
|
||||
|
||||
config EDD
|
||||
tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
depends on !IA64
|
||||
help
|
||||
Say Y or M here if you want to enable BIOS Enhanced Disk Drive
|
||||
Services real mode BIOS calls to determine which disk
|
||||
BIOS tries boot from. This information is then exported via sysfs.
|
||||
|
||||
This option is experimental and is known to fail to boot on some
|
||||
obscure configurations. Most disk controller BIOS vendors do
|
||||
not yet implement this feature.
|
||||
|
||||
config EFI_VARS
|
||||
tristate "EFI Variable Support via sysfs"
|
||||
depends on EFI
|
||||
default n
|
||||
help
|
||||
If you say Y here, you are able to get EFI (Extensible Firmware
|
||||
Interface) variable information via sysfs. You may read,
|
||||
write, create, and destroy EFI variables through this interface.
|
||||
|
||||
Note that using this driver in concert with efibootmgr requires
|
||||
at least test release version 0.5.0-test3 or later, which is
|
||||
available from Matt Domsch's website located at:
|
||||
http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz
|
||||
|
||||
Subsequent efibootmgr releases may be found at:
|
||||
http://linux.dell.com/efibootmgr
|
||||
|
||||
config EFI_PCDP
|
||||
bool "Console device selection via EFI PCDP or HCDP table"
|
||||
depends on ACPI && EFI && IA64
|
||||
default y if IA64
|
||||
help
|
||||
If your firmware supplies the PCDP table, and you want to
|
||||
automatically use the primary console device it describes
|
||||
as the Linux console, say Y here.
|
||||
|
||||
If your firmware supplies the HCDP table, and you want to
|
||||
use the first serial port it describes as the Linux console,
|
||||
say Y here. If your EFI ConOut path contains only a UART
|
||||
device, it will become the console automatically. Otherwise,
|
||||
you must specify the "console=hcdp" kernel boot argument.
|
||||
|
||||
Neither the PCDP nor the HCDP affects naming of serial devices,
|
||||
so a serial console may be /dev/ttyS0, /dev/ttyS1, etc, depending
|
||||
on how the driver discovers devices.
|
||||
|
||||
You must also enable the appropriate drivers (serial, VGA, etc.)
|
||||
|
||||
See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
|
||||
|
||||
endmenu
|
||||
6
extra/linux-2.6.10/drivers/firmware/Makefile
Normal file
6
extra/linux-2.6.10/drivers/firmware/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
obj-$(CONFIG_EDD) += edd.o
|
||||
obj-$(CONFIG_EFI_VARS) += efivars.o
|
||||
obj-$(CONFIG_EFI_PCDP) += pcdp.o
|
||||
1
extra/linux-2.6.10/drivers/firmware/built-in.o
Normal file
1
extra/linux-2.6.10/drivers/firmware/built-in.o
Normal file
@@ -0,0 +1 @@
|
||||
!<arch>
|
||||
790
extra/linux-2.6.10/drivers/firmware/edd.c
Normal file
790
extra/linux-2.6.10/drivers/firmware/edd.c
Normal file
@@ -0,0 +1,790 @@
|
||||
/*
|
||||
* linux/arch/i386/kernel/edd.c
|
||||
* Copyright (C) 2002, 2003, 2004 Dell Inc.
|
||||
* by Matt Domsch <Matt_Domsch@dell.com>
|
||||
* disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
|
||||
* legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
|
||||
*
|
||||
* BIOS Enhanced Disk Drive Services (EDD)
|
||||
* conformant to T13 Committee www.t13.org
|
||||
* projects 1572D, 1484D, 1386D, 1226DT
|
||||
*
|
||||
* This code takes information provided by BIOS EDD calls
|
||||
* fn41 - Check Extensions Present and
|
||||
* fn48 - Get Device Parametes with EDD extensions
|
||||
* made in setup.S, copied to safe structures in setup.c,
|
||||
* and presents it in sysfs.
|
||||
*
|
||||
* Please see http://linux.dell.com/edd30/results.html for
|
||||
* the list of BIOSs which have been reported to implement EDD.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License v2.0 as published by
|
||||
* the Free Software Foundation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/edd.h>
|
||||
|
||||
#define EDD_VERSION "0.16"
|
||||
#define EDD_DATE "2004-Jun-25"
|
||||
|
||||
MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
|
||||
MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(EDD_VERSION);
|
||||
|
||||
#define left (PAGE_SIZE - (p - buf) - 1)
|
||||
|
||||
struct edd_device {
|
||||
unsigned int index;
|
||||
unsigned int mbr_signature;
|
||||
struct edd_info *info;
|
||||
struct kobject kobj;
|
||||
};
|
||||
|
||||
struct edd_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t(*show) (struct edd_device * edev, char *buf);
|
||||
int (*test) (struct edd_device * edev);
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
static int edd_dev_is_type(struct edd_device *edev, const char *type);
|
||||
static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
|
||||
|
||||
static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
|
||||
|
||||
#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
|
||||
struct edd_attribute edd_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
|
||||
.show = _show, \
|
||||
.test = _test, \
|
||||
};
|
||||
|
||||
static int
|
||||
edd_has_mbr_signature(struct edd_device *edev)
|
||||
{
|
||||
return edev->index < min_t(unsigned char, edd.mbr_signature_nr, EDD_MBR_SIG_MAX);
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_edd_info(struct edd_device *edev)
|
||||
{
|
||||
return edev->index < min_t(unsigned char, edd.edd_info_nr, EDDMAXNR);
|
||||
}
|
||||
|
||||
static inline struct edd_info *
|
||||
edd_dev_get_info(struct edd_device *edev)
|
||||
{
|
||||
return edev->info;
|
||||
}
|
||||
|
||||
static inline void
|
||||
edd_dev_set_info(struct edd_device *edev, int i)
|
||||
{
|
||||
edev->index = i;
|
||||
if (edd_has_mbr_signature(edev))
|
||||
edev->mbr_signature = edd.mbr_signature[i];
|
||||
if (edd_has_edd_info(edev))
|
||||
edev->info = &edd.edd_info[i];
|
||||
}
|
||||
|
||||
#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
|
||||
#define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
|
||||
|
||||
static ssize_t
|
||||
edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
|
||||
{
|
||||
struct edd_device *dev = to_edd_device(kobj);
|
||||
struct edd_attribute *edd_attr = to_edd_attr(attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (edd_attr->show)
|
||||
ret = edd_attr->show(dev, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sysfs_ops edd_attr_ops = {
|
||||
.show = edd_attr_show,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
edd_show_host_bus(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
int i;
|
||||
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (isprint(info->params.host_bus_type[i])) {
|
||||
p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
|
||||
} else {
|
||||
p += scnprintf(p, left, " ");
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
|
||||
p += scnprintf(p, left, "\tbase_address: %x\n",
|
||||
info->params.interface_path.isa.base_address);
|
||||
} else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
|
||||
!strncmp(info->params.host_bus_type, "PCI", 3)) {
|
||||
p += scnprintf(p, left,
|
||||
"\t%02x:%02x.%d channel: %u\n",
|
||||
info->params.interface_path.pci.bus,
|
||||
info->params.interface_path.pci.slot,
|
||||
info->params.interface_path.pci.function,
|
||||
info->params.interface_path.pci.channel);
|
||||
} else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
|
||||
!strncmp(info->params.host_bus_type, "XPRS", 4) ||
|
||||
!strncmp(info->params.host_bus_type, "HTPT", 4)) {
|
||||
p += scnprintf(p, left,
|
||||
"\tTBD: %llx\n",
|
||||
info->params.interface_path.ibnd.reserved);
|
||||
|
||||
} else {
|
||||
p += scnprintf(p, left, "\tunknown: %llx\n",
|
||||
info->params.interface_path.unknown.reserved);
|
||||
}
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_interface(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
int i;
|
||||
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (isprint(info->params.interface_type[i])) {
|
||||
p += scnprintf(p, left, "%c", info->params.interface_type[i]);
|
||||
} else {
|
||||
p += scnprintf(p, left, " ");
|
||||
}
|
||||
}
|
||||
if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
|
||||
p += scnprintf(p, left, "\tdevice: %u lun: %u\n",
|
||||
info->params.device_path.atapi.device,
|
||||
info->params.device_path.atapi.lun);
|
||||
} else if (!strncmp(info->params.interface_type, "ATA", 3)) {
|
||||
p += scnprintf(p, left, "\tdevice: %u\n",
|
||||
info->params.device_path.ata.device);
|
||||
} else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
|
||||
p += scnprintf(p, left, "\tid: %u lun: %llu\n",
|
||||
info->params.device_path.scsi.id,
|
||||
info->params.device_path.scsi.lun);
|
||||
} else if (!strncmp(info->params.interface_type, "USB", 3)) {
|
||||
p += scnprintf(p, left, "\tserial_number: %llx\n",
|
||||
info->params.device_path.usb.serial_number);
|
||||
} else if (!strncmp(info->params.interface_type, "1394", 4)) {
|
||||
p += scnprintf(p, left, "\teui: %llx\n",
|
||||
info->params.device_path.i1394.eui);
|
||||
} else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
|
||||
p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
|
||||
info->params.device_path.fibre.wwid,
|
||||
info->params.device_path.fibre.lun);
|
||||
} else if (!strncmp(info->params.interface_type, "I2O", 3)) {
|
||||
p += scnprintf(p, left, "\tidentity_tag: %llx\n",
|
||||
info->params.device_path.i2o.identity_tag);
|
||||
} else if (!strncmp(info->params.interface_type, "RAID", 4)) {
|
||||
p += scnprintf(p, left, "\tidentity_tag: %x\n",
|
||||
info->params.device_path.raid.array_number);
|
||||
} else if (!strncmp(info->params.interface_type, "SATA", 4)) {
|
||||
p += scnprintf(p, left, "\tdevice: %u\n",
|
||||
info->params.device_path.sata.device);
|
||||
} else {
|
||||
p += scnprintf(p, left, "\tunknown: %llx %llx\n",
|
||||
info->params.device_path.unknown.reserved1,
|
||||
info->params.device_path.unknown.reserved2);
|
||||
}
|
||||
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* edd_show_raw_data() - copies raw data to buffer for userspace to parse
|
||||
*
|
||||
* Returns: number of bytes written, or -EINVAL on failure
|
||||
*/
|
||||
static ssize_t
|
||||
edd_show_raw_data(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
ssize_t len = sizeof (info->params);
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
|
||||
len = info->params.length;
|
||||
|
||||
/* In case of buggy BIOSs */
|
||||
if (len > (sizeof(info->params)))
|
||||
len = sizeof(info->params);
|
||||
|
||||
memcpy(buf, &info->params, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_version(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += scnprintf(p, left, "0x%02x\n", info->version);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_mbr_signature(struct edd_device *edev, char *buf)
|
||||
{
|
||||
char *p = buf;
|
||||
p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_extensions(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
|
||||
p += scnprintf(p, left, "Fixed disk access\n");
|
||||
}
|
||||
if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
|
||||
p += scnprintf(p, left, "Device locking and ejecting\n");
|
||||
}
|
||||
if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
|
||||
p += scnprintf(p, left, "Enhanced Disk Drive support\n");
|
||||
}
|
||||
if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
|
||||
p += scnprintf(p, left, "64-bit extensions\n");
|
||||
}
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_info_flags(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
|
||||
p += scnprintf(p, left, "DMA boundary error transparent\n");
|
||||
if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
|
||||
p += scnprintf(p, left, "geometry valid\n");
|
||||
if (info->params.info_flags & EDD_INFO_REMOVABLE)
|
||||
p += scnprintf(p, left, "removable\n");
|
||||
if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
|
||||
p += scnprintf(p, left, "write verify\n");
|
||||
if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
|
||||
p += scnprintf(p, left, "media change notification\n");
|
||||
if (info->params.info_flags & EDD_INFO_LOCKABLE)
|
||||
p += scnprintf(p, left, "lockable\n");
|
||||
if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
|
||||
p += scnprintf(p, left, "no media present\n");
|
||||
if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
|
||||
p += scnprintf(p, left, "use int13 fn50\n");
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_legacy_max_head(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += snprintf(p, left, "%u\n", info->legacy_max_head);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_default_cylinders(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_default_heads(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += scnprintf(p, left, "%u\n", info->params.num_default_heads);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_default_sectors_per_track(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += scnprintf(p, left, "%u\n", info->params.sectors_per_track);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
edd_show_sectors(struct edd_device *edev, char *buf)
|
||||
{
|
||||
struct edd_info *info;
|
||||
char *p = buf;
|
||||
if (!edev)
|
||||
return -EINVAL;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Some device instances may not have all the above attributes,
|
||||
* or the attribute values may be meaningless (i.e. if
|
||||
* the device is < EDD 3.0, it won't have host_bus and interface
|
||||
* information), so don't bother making files for them. Likewise
|
||||
* if the default_{cylinders,heads,sectors_per_track} values
|
||||
* are zero, the BIOS doesn't provide sane values, don't bother
|
||||
* creating files for them either.
|
||||
*/
|
||||
|
||||
static int
|
||||
edd_has_legacy_max_cylinder(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
return info->legacy_max_cylinder > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_legacy_max_head(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
return info->legacy_max_head > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_legacy_sectors_per_track(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
return info->legacy_sectors_per_track > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_default_cylinders(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
return info->params.num_default_cylinders > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_default_heads(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
return info->params.num_default_heads > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_default_sectors_per_track(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
return info->params.sectors_per_track > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_has_edd30(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info;
|
||||
int i, nonzero_path = 0;
|
||||
char c;
|
||||
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 30; i <= 73; i++) {
|
||||
c = *(((uint8_t *) info) + i + 4);
|
||||
if (c) {
|
||||
nonzero_path++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nonzero_path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, edd_has_edd_info);
|
||||
static EDD_DEVICE_ATTR(version, 0444, edd_show_version, edd_has_edd_info);
|
||||
static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, edd_has_edd_info);
|
||||
static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, edd_has_edd_info);
|
||||
static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, edd_has_edd_info);
|
||||
static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444,
|
||||
edd_show_legacy_max_cylinder,
|
||||
edd_has_legacy_max_cylinder);
|
||||
static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head,
|
||||
edd_has_legacy_max_head);
|
||||
static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444,
|
||||
edd_show_legacy_sectors_per_track,
|
||||
edd_has_legacy_sectors_per_track);
|
||||
static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
|
||||
edd_has_default_cylinders);
|
||||
static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
|
||||
edd_has_default_heads);
|
||||
static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
|
||||
edd_show_default_sectors_per_track,
|
||||
edd_has_default_sectors_per_track);
|
||||
static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
|
||||
static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
|
||||
static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature);
|
||||
|
||||
|
||||
/* These are default attributes that are added for every edd
|
||||
* device discovered. There are none.
|
||||
*/
|
||||
static struct attribute * def_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* These attributes are conditional and only added for some devices. */
|
||||
static struct edd_attribute * edd_attrs[] = {
|
||||
&edd_attr_raw_data,
|
||||
&edd_attr_version,
|
||||
&edd_attr_extensions,
|
||||
&edd_attr_info_flags,
|
||||
&edd_attr_sectors,
|
||||
&edd_attr_legacy_max_cylinder,
|
||||
&edd_attr_legacy_max_head,
|
||||
&edd_attr_legacy_sectors_per_track,
|
||||
&edd_attr_default_cylinders,
|
||||
&edd_attr_default_heads,
|
||||
&edd_attr_default_sectors_per_track,
|
||||
&edd_attr_interface,
|
||||
&edd_attr_host_bus,
|
||||
&edd_attr_mbr_signature,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* edd_release - free edd structure
|
||||
* @kobj: kobject of edd structure
|
||||
*
|
||||
* This is called when the refcount of the edd structure
|
||||
* reaches 0. This should happen right after we unregister,
|
||||
* but just in case, we use the release callback anyway.
|
||||
*/
|
||||
|
||||
static void edd_release(struct kobject * kobj)
|
||||
{
|
||||
struct edd_device * dev = to_edd_device(kobj);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct kobj_type ktype_edd = {
|
||||
.release = edd_release,
|
||||
.sysfs_ops = &edd_attr_ops,
|
||||
.default_attrs = def_attrs,
|
||||
};
|
||||
|
||||
static decl_subsys(edd,&ktype_edd,NULL);
|
||||
|
||||
|
||||
/**
|
||||
* edd_dev_is_type() - is this EDD device a 'type' device?
|
||||
* @edev
|
||||
* @type - a host bus or interface identifier string per the EDD spec
|
||||
*
|
||||
* Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
edd_dev_is_type(struct edd_device *edev, const char *type)
|
||||
{
|
||||
struct edd_info *info;
|
||||
if (!edev)
|
||||
return 0;
|
||||
info = edd_dev_get_info(edev);
|
||||
|
||||
if (type && info) {
|
||||
if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
|
||||
!strncmp(info->params.interface_type, type, strlen(type)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* edd_get_pci_dev() - finds pci_dev that matches edev
|
||||
* @edev - edd_device
|
||||
*
|
||||
* Returns pci_dev if found, or NULL
|
||||
*/
|
||||
static struct pci_dev *
|
||||
edd_get_pci_dev(struct edd_device *edev)
|
||||
{
|
||||
struct edd_info *info = edd_dev_get_info(edev);
|
||||
|
||||
if (edd_dev_is_type(edev, "PCI")) {
|
||||
return pci_find_slot(info->params.interface_path.pci.bus,
|
||||
PCI_DEVFN(info->params.interface_path.pci.slot,
|
||||
info->params.interface_path.pci.
|
||||
function));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
edd_create_symlink_to_pcidev(struct edd_device *edev)
|
||||
{
|
||||
|
||||
struct pci_dev *pci_dev = edd_get_pci_dev(edev);
|
||||
if (!pci_dev)
|
||||
return 1;
|
||||
return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
|
||||
}
|
||||
|
||||
static inline void
|
||||
edd_device_unregister(struct edd_device *edev)
|
||||
{
|
||||
kobject_unregister(&edev->kobj);
|
||||
}
|
||||
|
||||
static void edd_populate_dir(struct edd_device * edev)
|
||||
{
|
||||
struct edd_attribute * attr;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
|
||||
if (!attr->test ||
|
||||
(attr->test && attr->test(edev)))
|
||||
error = sysfs_create_file(&edev->kobj,&attr->attr);
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
edd_create_symlink_to_pcidev(edev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
edd_device_register(struct edd_device *edev, int i)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!edev)
|
||||
return 1;
|
||||
memset(edev, 0, sizeof (*edev));
|
||||
edd_dev_set_info(edev, i);
|
||||
kobject_set_name(&edev->kobj, "int13_dev%02x",
|
||||
0x80 + i);
|
||||
kobj_set_kset_s(edev,edd_subsys);
|
||||
error = kobject_register(&edev->kobj);
|
||||
if (!error)
|
||||
edd_populate_dir(edev);
|
||||
return error;
|
||||
}
|
||||
|
||||
static inline int edd_num_devices(void)
|
||||
{
|
||||
return max_t(unsigned char,
|
||||
min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr),
|
||||
min_t(unsigned char, EDDMAXNR, edd.edd_info_nr));
|
||||
}
|
||||
|
||||
/**
|
||||
* edd_init() - creates sysfs tree of EDD data
|
||||
*/
|
||||
static int __init
|
||||
edd_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
int rc=0;
|
||||
struct edd_device *edev;
|
||||
|
||||
printk(KERN_INFO "BIOS EDD facility v%s %s, %d devices found\n",
|
||||
EDD_VERSION, EDD_DATE, edd_num_devices());
|
||||
|
||||
if (!edd_num_devices()) {
|
||||
printk(KERN_INFO "EDD information not available.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = firmware_register(&edd_subsys);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < edd_num_devices() && !rc; i++) {
|
||||
edev = kmalloc(sizeof (*edev), GFP_KERNEL);
|
||||
if (!edev)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = edd_device_register(edev, i);
|
||||
if (rc) {
|
||||
kfree(edev);
|
||||
break;
|
||||
}
|
||||
edd_devices[i] = edev;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
firmware_unregister(&edd_subsys);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
edd_exit(void)
|
||||
{
|
||||
int i;
|
||||
struct edd_device *edev;
|
||||
|
||||
for (i = 0; i < edd_num_devices(); i++) {
|
||||
if ((edev = edd_devices[i]))
|
||||
edd_device_unregister(edev);
|
||||
}
|
||||
firmware_unregister(&edd_subsys);
|
||||
}
|
||||
|
||||
late_initcall(edd_init);
|
||||
module_exit(edd_exit);
|
||||
755
extra/linux-2.6.10/drivers/firmware/efivars.c
Normal file
755
extra/linux-2.6.10/drivers/firmware/efivars.c
Normal file
@@ -0,0 +1,755 @@
|
||||
/*
|
||||
* EFI Variables - efivars.c
|
||||
*
|
||||
* Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
|
||||
* Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
|
||||
*
|
||||
* This code takes all variables accessible from EFI runtime and
|
||||
* exports them via sysfs
|
||||
*
|
||||
* 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
|
||||
* (at your option) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Changelog:
|
||||
*
|
||||
* 17 May 2004 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* remove check for efi_enabled in exit
|
||||
* add MODULE_VERSION
|
||||
*
|
||||
* 26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* minor bug fixes
|
||||
*
|
||||
* 21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com)
|
||||
* converted driver to export variable information via sysfs
|
||||
* and moved to drivers/firmware directory
|
||||
* bumped revision number to v0.07 to reflect conversion & move
|
||||
*
|
||||
* 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* fix locking per Peter Chubb's findings
|
||||
*
|
||||
* 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
|
||||
*
|
||||
* 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* use list_for_each_safe when deleting vars.
|
||||
* remove ifdef CONFIG_SMP around include <linux/smp.h>
|
||||
* v0.04 release to linux-ia64@linuxia64.org
|
||||
*
|
||||
* 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Moved vars from /proc/efi to /proc/efi/vars, and made
|
||||
* efi.c own the /proc/efi directory.
|
||||
* v0.03 release to linux-ia64@linuxia64.org
|
||||
*
|
||||
* 26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* At the request of Stephane, moved ownership of /proc/efi
|
||||
* to efi.c, and now efivars lives under /proc/efi/vars.
|
||||
*
|
||||
* 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Feedback received from Stephane Eranian incorporated.
|
||||
* efivar_write() checks copy_from_user() return value.
|
||||
* efivar_read/write() returns proper errno.
|
||||
* v0.02 release to linux-ia64@linuxia64.org
|
||||
*
|
||||
* 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
|
||||
* v0.01 release to linux-ia64@linuxia64.org
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h> /* for capable() */
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define EFIVARS_VERSION "0.08"
|
||||
#define EFIVARS_DATE "2004-May-17"
|
||||
|
||||
MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
|
||||
MODULE_DESCRIPTION("sysfs interface to EFI Variables");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(EFIVARS_VERSION);
|
||||
|
||||
/*
|
||||
* efivars_lock protects two things:
|
||||
* 1) efivar_list - adds, removals, reads, writes
|
||||
* 2) efi.[gs]et_variable() calls.
|
||||
* It must not be held when creating sysfs entries or calling kmalloc.
|
||||
* efi.get_next_variable() is only called from efivars_init(),
|
||||
* which is protected by the BKL, so that path is safe.
|
||||
*/
|
||||
static spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED;
|
||||
static LIST_HEAD(efivar_list);
|
||||
|
||||
/*
|
||||
* The maximum size of VariableName + Data = 1024
|
||||
* Therefore, it's reasonable to save that much
|
||||
* space in each part of the structure,
|
||||
* and we use a page for reading/writing.
|
||||
*/
|
||||
|
||||
struct efi_variable {
|
||||
efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
|
||||
efi_guid_t VendorGuid;
|
||||
unsigned long DataSize;
|
||||
__u8 Data[1024];
|
||||
efi_status_t Status;
|
||||
__u32 Attributes;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
struct efivar_entry {
|
||||
struct efi_variable var;
|
||||
struct list_head list;
|
||||
struct kobject kobj;
|
||||
};
|
||||
|
||||
#define get_efivar_entry(n) list_entry(n, struct efivar_entry, list)
|
||||
|
||||
struct efivar_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show) (struct efivar_entry *entry, char *buf);
|
||||
ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
|
||||
};
|
||||
|
||||
|
||||
#define EFI_ATTR(_name, _mode, _show, _store) \
|
||||
struct subsys_attribute efi_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
#define EFIVAR_ATTR(_name, _mode, _show, _store) \
|
||||
struct efivar_attribute efivar_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
|
||||
struct subsys_attribute var_subsys_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
#define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
|
||||
#define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj)
|
||||
|
||||
/*
|
||||
* Prototype for sysfs creation function
|
||||
*/
|
||||
static int
|
||||
efivar_create_sysfs_entry(unsigned long variable_name_size,
|
||||
efi_char16_t *variable_name,
|
||||
efi_guid_t *vendor_guid);
|
||||
|
||||
/* Return the number of unicode characters in data */
|
||||
static unsigned long
|
||||
utf8_strlen(efi_char16_t *data, unsigned long maxlength)
|
||||
{
|
||||
unsigned long length = 0;
|
||||
|
||||
while (*data++ != 0 && length < maxlength)
|
||||
length++;
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of bytes is the length of this string
|
||||
* Note: this is NOT the same as the number of unicode characters
|
||||
*/
|
||||
static inline unsigned long
|
||||
utf8_strsize(efi_char16_t *data, unsigned long maxlength)
|
||||
{
|
||||
return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
get_var_data(struct efi_variable *var)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
spin_lock(&efivars_lock);
|
||||
var->DataSize = 1024;
|
||||
status = efi.get_variable(var->VariableName,
|
||||
&var->VendorGuid,
|
||||
&var->Attributes,
|
||||
&var->DataSize,
|
||||
var->Data);
|
||||
spin_unlock(&efivars_lock);
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
|
||||
status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
efivar_guid_read(struct efivar_entry *entry, char *buf)
|
||||
{
|
||||
struct efi_variable *var = &entry->var;
|
||||
char *str = buf;
|
||||
|
||||
if (!entry || !buf)
|
||||
return 0;
|
||||
|
||||
efi_guid_unparse(&var->VendorGuid, str);
|
||||
str += strlen(str);
|
||||
str += sprintf(str, "\n");
|
||||
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
efivar_attr_read(struct efivar_entry *entry, char *buf)
|
||||
{
|
||||
struct efi_variable *var = &entry->var;
|
||||
char *str = buf;
|
||||
efi_status_t status;
|
||||
|
||||
if (!entry || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
status = get_var_data(var);
|
||||
if (status != EFI_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
if (var->Attributes & 0x1)
|
||||
str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
|
||||
if (var->Attributes & 0x2)
|
||||
str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
|
||||
if (var->Attributes & 0x4)
|
||||
str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
efivar_size_read(struct efivar_entry *entry, char *buf)
|
||||
{
|
||||
struct efi_variable *var = &entry->var;
|
||||
char *str = buf;
|
||||
efi_status_t status;
|
||||
|
||||
if (!entry || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
status = get_var_data(var);
|
||||
if (status != EFI_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
str += sprintf(str, "0x%lx\n", var->DataSize);
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
efivar_data_read(struct efivar_entry *entry, char *buf)
|
||||
{
|
||||
struct efi_variable *var = &entry->var;
|
||||
efi_status_t status;
|
||||
|
||||
if (!entry || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
status = get_var_data(var);
|
||||
if (status != EFI_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
memcpy(buf, var->Data, var->DataSize);
|
||||
return var->DataSize;
|
||||
}
|
||||
/*
|
||||
* We allow each variable to be edited via rewriting the
|
||||
* entire efi variable structure.
|
||||
*/
|
||||
static ssize_t
|
||||
efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
|
||||
{
|
||||
struct efi_variable *new_var, *var = &entry->var;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
|
||||
if (count != sizeof(struct efi_variable))
|
||||
return -EINVAL;
|
||||
|
||||
new_var = (struct efi_variable *)buf;
|
||||
/*
|
||||
* If only updating the variable data, then the name
|
||||
* and guid should remain the same
|
||||
*/
|
||||
if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
|
||||
efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
|
||||
printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
|
||||
printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock(&efivars_lock);
|
||||
status = efi.set_variable(new_var->VariableName,
|
||||
&new_var->VendorGuid,
|
||||
new_var->Attributes,
|
||||
new_var->DataSize,
|
||||
new_var->Data);
|
||||
|
||||
spin_unlock(&efivars_lock);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||||
status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(&entry->var, new_var, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
efivar_show_raw(struct efivar_entry *entry, char *buf)
|
||||
{
|
||||
struct efi_variable *var = &entry->var;
|
||||
efi_status_t status;
|
||||
|
||||
if (!entry || !buf)
|
||||
return 0;
|
||||
|
||||
status = get_var_data(var);
|
||||
if (status != EFI_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
memcpy(buf, var, sizeof(*var));
|
||||
return sizeof(*var);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic read/write functions that call the specific functions of
|
||||
* the atttributes...
|
||||
*/
|
||||
static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct efivar_entry *var = to_efivar_entry(kobj);
|
||||
struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
if (efivar_attr->show) {
|
||||
ret = efivar_attr->show(var, buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct efivar_entry *var = to_efivar_entry(kobj);
|
||||
struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
if (efivar_attr->store)
|
||||
ret = efivar_attr->store(var, buf, count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sysfs_ops efivar_attr_ops = {
|
||||
.show = efivar_attr_show,
|
||||
.store = efivar_attr_store,
|
||||
};
|
||||
|
||||
static void efivar_release(struct kobject *kobj)
|
||||
{
|
||||
struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
|
||||
spin_lock(&efivars_lock);
|
||||
list_del(&var->list);
|
||||
spin_unlock(&efivars_lock);
|
||||
kfree(var);
|
||||
}
|
||||
|
||||
static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
|
||||
static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
|
||||
static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
|
||||
static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
|
||||
static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
|
||||
|
||||
static struct attribute *def_attrs[] = {
|
||||
&efivar_attr_guid.attr,
|
||||
&efivar_attr_size.attr,
|
||||
&efivar_attr_attributes.attr,
|
||||
&efivar_attr_data.attr,
|
||||
&efivar_attr_raw_var.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct kobj_type ktype_efivar = {
|
||||
.release = efivar_release,
|
||||
.sysfs_ops = &efivar_attr_ops,
|
||||
.default_attrs = def_attrs,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
dummy(struct subsystem *sub, char *buf)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void
|
||||
efivar_unregister(struct efivar_entry *var)
|
||||
{
|
||||
kobject_unregister(&var->kobj);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
efivar_create(struct subsystem *sub, const char *buf, size_t count)
|
||||
{
|
||||
struct efi_variable *new_var = (struct efi_variable *)buf;
|
||||
struct efivar_entry *search_efivar = NULL;
|
||||
unsigned long strsize1, strsize2;
|
||||
struct list_head *pos, *n;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
int found = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
spin_lock(&efivars_lock);
|
||||
|
||||
/*
|
||||
* Does this variable already exist?
|
||||
*/
|
||||
list_for_each_safe(pos, n, &efivar_list) {
|
||||
search_efivar = get_efivar_entry(pos);
|
||||
strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
|
||||
strsize2 = utf8_strsize(new_var->VariableName, 1024);
|
||||
if (strsize1 == strsize2 &&
|
||||
!memcmp(&(search_efivar->var.VariableName),
|
||||
new_var->VariableName, strsize1) &&
|
||||
!efi_guidcmp(search_efivar->var.VendorGuid,
|
||||
new_var->VendorGuid)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
spin_unlock(&efivars_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* now *really* create the variable via EFI */
|
||||
status = efi.set_variable(new_var->VariableName,
|
||||
&new_var->VendorGuid,
|
||||
new_var->Attributes,
|
||||
new_var->DataSize,
|
||||
new_var->Data);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||||
status);
|
||||
spin_unlock(&efivars_lock);
|
||||
return -EIO;
|
||||
}
|
||||
spin_unlock(&efivars_lock);
|
||||
|
||||
/* Create the entry in sysfs. Locking is not required here */
|
||||
status = efivar_create_sysfs_entry(utf8_strsize(new_var->VariableName,
|
||||
1024), new_var->VariableName, &new_var->VendorGuid);
|
||||
if (status) {
|
||||
printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
efivar_delete(struct subsystem *sub, const char *buf, size_t count)
|
||||
{
|
||||
struct efi_variable *del_var = (struct efi_variable *)buf;
|
||||
struct efivar_entry *search_efivar = NULL;
|
||||
unsigned long strsize1, strsize2;
|
||||
struct list_head *pos, *n;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
int found = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
spin_lock(&efivars_lock);
|
||||
|
||||
/*
|
||||
* Does this variable already exist?
|
||||
*/
|
||||
list_for_each_safe(pos, n, &efivar_list) {
|
||||
search_efivar = get_efivar_entry(pos);
|
||||
strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
|
||||
strsize2 = utf8_strsize(del_var->VariableName, 1024);
|
||||
if (strsize1 == strsize2 &&
|
||||
!memcmp(&(search_efivar->var.VariableName),
|
||||
del_var->VariableName, strsize1) &&
|
||||
!efi_guidcmp(search_efivar->var.VendorGuid,
|
||||
del_var->VendorGuid)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
spin_unlock(&efivars_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* force the Attributes/DataSize to 0 to ensure deletion */
|
||||
del_var->Attributes = 0;
|
||||
del_var->DataSize = 0;
|
||||
|
||||
status = efi.set_variable(del_var->VariableName,
|
||||
&del_var->VendorGuid,
|
||||
del_var->Attributes,
|
||||
del_var->DataSize,
|
||||
del_var->Data);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||||
status);
|
||||
spin_unlock(&efivars_lock);
|
||||
return -EIO;
|
||||
}
|
||||
/* We need to release this lock before unregistering. */
|
||||
spin_unlock(&efivars_lock);
|
||||
|
||||
efivar_unregister(search_efivar);
|
||||
|
||||
/* It's dead Jim.... */
|
||||
return count;
|
||||
}
|
||||
|
||||
static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);
|
||||
static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);
|
||||
|
||||
static struct subsys_attribute *var_subsys_attrs[] = {
|
||||
&var_subsys_attr_new_var,
|
||||
&var_subsys_attr_del_var,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Let's not leave out systab information that snuck into
|
||||
* the efivars driver
|
||||
*/
|
||||
static ssize_t
|
||||
systab_read(struct subsystem *entry, char *buf)
|
||||
{
|
||||
char *str = buf;
|
||||
|
||||
if (!entry || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (efi.mps)
|
||||
str += sprintf(str, "MPS=0x%lx\n", __pa(efi.mps));
|
||||
if (efi.acpi20)
|
||||
str += sprintf(str, "ACPI20=0x%lx\n", __pa(efi.acpi20));
|
||||
if (efi.acpi)
|
||||
str += sprintf(str, "ACPI=0x%lx\n", __pa(efi.acpi));
|
||||
if (efi.smbios)
|
||||
str += sprintf(str, "SMBIOS=0x%lx\n", __pa(efi.smbios));
|
||||
if (efi.hcdp)
|
||||
str += sprintf(str, "HCDP=0x%lx\n", __pa(efi.hcdp));
|
||||
if (efi.boot_info)
|
||||
str += sprintf(str, "BOOTINFO=0x%lx\n", __pa(efi.boot_info));
|
||||
if (efi.uga)
|
||||
str += sprintf(str, "UGA=0x%lx\n", __pa(efi.uga));
|
||||
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
static EFI_ATTR(systab, 0400, systab_read, NULL);
|
||||
|
||||
static struct subsys_attribute *efi_subsys_attrs[] = {
|
||||
&efi_attr_systab,
|
||||
NULL, /* maybe more in the future? */
|
||||
};
|
||||
|
||||
static decl_subsys(vars, &ktype_efivar, NULL);
|
||||
static decl_subsys(efi, NULL, NULL);
|
||||
|
||||
/*
|
||||
* efivar_create_sysfs_entry()
|
||||
* Requires:
|
||||
* variable_name_size = number of bytes required to hold
|
||||
* variable_name (not counting the NULL
|
||||
* character at the end.
|
||||
* efivars_lock is not held on entry or exit.
|
||||
* Returns 1 on failure, 0 on success
|
||||
*/
|
||||
static int
|
||||
efivar_create_sysfs_entry(unsigned long variable_name_size,
|
||||
efi_char16_t *variable_name,
|
||||
efi_guid_t *vendor_guid)
|
||||
{
|
||||
int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
|
||||
char *short_name;
|
||||
struct efivar_entry *new_efivar;
|
||||
|
||||
short_name = kmalloc(short_name_size + 1, GFP_KERNEL);
|
||||
new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL);
|
||||
|
||||
if (!short_name || !new_efivar) {
|
||||
if (short_name) kfree(short_name);
|
||||
if (new_efivar) kfree(new_efivar);
|
||||
return 1;
|
||||
}
|
||||
memset(short_name, 0, short_name_size+1);
|
||||
memset(new_efivar, 0, sizeof(struct efivar_entry));
|
||||
|
||||
memcpy(new_efivar->var.VariableName, variable_name,
|
||||
variable_name_size);
|
||||
memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
|
||||
|
||||
/* Convert Unicode to normal chars (assume top bits are 0),
|
||||
ala UTF-8 */
|
||||
for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
|
||||
short_name[i] = variable_name[i] & 0xFF;
|
||||
}
|
||||
/* This is ugly, but necessary to separate one vendor's
|
||||
private variables from another's. */
|
||||
|
||||
*(short_name + strlen(short_name)) = '-';
|
||||
efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
|
||||
|
||||
kobject_set_name(&new_efivar->kobj, "%s", short_name);
|
||||
kobj_set_kset_s(new_efivar, vars_subsys);
|
||||
kobject_register(&new_efivar->kobj);
|
||||
|
||||
kfree(short_name); short_name = NULL;
|
||||
|
||||
spin_lock(&efivars_lock);
|
||||
list_add(&new_efivar->list, &efivar_list);
|
||||
spin_unlock(&efivars_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* For now we register the efi subsystem with the firmware subsystem
|
||||
* and the vars subsystem with the efi subsystem. In the future, it
|
||||
* might make sense to split off the efi subsystem into its own
|
||||
* driver, but for now only efivars will register with it, so just
|
||||
* include it here.
|
||||
*/
|
||||
|
||||
static int __init
|
||||
efivars_init(void)
|
||||
{
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
efi_guid_t vendor_guid;
|
||||
efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
|
||||
struct subsys_attribute *attr;
|
||||
unsigned long variable_name_size = 1024;
|
||||
int i, rc = 0, error = 0;
|
||||
|
||||
if (!efi_enabled)
|
||||
return -ENODEV;
|
||||
|
||||
printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
|
||||
EFIVARS_DATE);
|
||||
|
||||
/*
|
||||
* For now we'll register the efi subsys within this driver
|
||||
*/
|
||||
|
||||
rc = firmware_register(&efi_subsys);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
kset_set_kset_s(&vars_subsys, efi_subsys);
|
||||
subsystem_register(&vars_subsys);
|
||||
|
||||
/*
|
||||
* Per EFI spec, the maximum storage allocated for both
|
||||
* the variable name and variable data is 1024 bytes.
|
||||
*/
|
||||
|
||||
memset(variable_name, 0, 1024);
|
||||
|
||||
do {
|
||||
variable_name_size = 1024;
|
||||
|
||||
status = efi.get_next_variable(&variable_name_size,
|
||||
variable_name,
|
||||
&vendor_guid);
|
||||
switch (status) {
|
||||
case EFI_SUCCESS:
|
||||
efivar_create_sysfs_entry(variable_name_size,
|
||||
variable_name,
|
||||
&vendor_guid);
|
||||
break;
|
||||
case EFI_NOT_FOUND:
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
|
||||
status);
|
||||
status = EFI_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
} while (status != EFI_NOT_FOUND);
|
||||
|
||||
/*
|
||||
* Now add attributes to allow creation of new vars
|
||||
* and deletion of existing ones...
|
||||
*/
|
||||
|
||||
for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {
|
||||
if (attr->show && attr->store)
|
||||
error = subsys_create_file(&vars_subsys, attr);
|
||||
}
|
||||
|
||||
/* Don't forget the systab entry */
|
||||
|
||||
for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {
|
||||
if (attr->show)
|
||||
error = subsys_create_file(&efi_subsys, attr);
|
||||
}
|
||||
|
||||
kfree(variable_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
efivars_exit(void)
|
||||
{
|
||||
struct list_head *pos, *n;
|
||||
|
||||
list_for_each_safe(pos, n, &efivar_list)
|
||||
efivar_unregister(get_efivar_entry(pos));
|
||||
|
||||
subsystem_unregister(&vars_subsys);
|
||||
firmware_unregister(&efi_subsys);
|
||||
}
|
||||
|
||||
module_init(efivars_init);
|
||||
module_exit(efivars_exit);
|
||||
|
||||
141
extra/linux-2.6.10/drivers/firmware/pcdp.c
Normal file
141
extra/linux-2.6.10/drivers/firmware/pcdp.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Parse the EFI PCDP table to locate the console device.
|
||||
*
|
||||
* (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P.
|
||||
* Khalid Aziz <khalid.aziz@hp.com>
|
||||
* Alex Williamson <alex.williamson@hp.com>
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/serial.h>
|
||||
#include "pcdp.h"
|
||||
|
||||
static int __init
|
||||
setup_serial_console(struct pcdp_uart *uart)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
int mmio;
|
||||
static char options[64];
|
||||
|
||||
mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
|
||||
snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d",
|
||||
mmio ? "mmio" : "io", uart->addr.address, uart->baud,
|
||||
uart->bits ? uart->bits : 8);
|
||||
|
||||
return early_serial_console_init(options);
|
||||
#else
|
||||
return -ENODEV;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __init
|
||||
setup_vga_console(struct pcdp_vga *vga)
|
||||
{
|
||||
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
|
||||
if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
|
||||
printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
conswitchp = &vga_con;
|
||||
printk(KERN_INFO "PCDP: VGA console\n");
|
||||
return 0;
|
||||
#else
|
||||
return -ENODEV;
|
||||
#endif
|
||||
}
|
||||
|
||||
int __init
|
||||
efi_setup_pcdp_console(char *cmdline)
|
||||
{
|
||||
struct pcdp *pcdp;
|
||||
struct pcdp_uart *uart;
|
||||
struct pcdp_device *dev, *end;
|
||||
int i, serial = 0;
|
||||
|
||||
pcdp = efi.hcdp;
|
||||
if (!pcdp)
|
||||
return -ENODEV;
|
||||
|
||||
printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
|
||||
|
||||
if (strstr(cmdline, "console=hcdp")) {
|
||||
if (pcdp->rev < 3)
|
||||
serial = 1;
|
||||
} else if (strstr(cmdline, "console=")) {
|
||||
printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pcdp->rev < 3 && efi_uart_console_only())
|
||||
serial = 1;
|
||||
|
||||
for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
|
||||
if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
|
||||
if (uart->type == PCDP_CONSOLE_UART) {
|
||||
return setup_serial_console(uart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
|
||||
for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
|
||||
dev < end;
|
||||
dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
|
||||
if (dev->flags & PCDP_PRIMARY_CONSOLE) {
|
||||
if (dev->type == PCDP_CONSOLE_VGA) {
|
||||
return setup_vga_console((struct pcdp_vga *) dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IA64_EARLY_PRINTK_UART
|
||||
unsigned long
|
||||
hcdp_early_uart (void)
|
||||
{
|
||||
efi_system_table_t *systab;
|
||||
efi_config_table_t *config_tables;
|
||||
unsigned long addr = 0;
|
||||
struct pcdp *pcdp = 0;
|
||||
struct pcdp_uart *uart;
|
||||
int i;
|
||||
|
||||
systab = (efi_system_table_t *) ia64_boot_param->efi_systab;
|
||||
if (!systab)
|
||||
return 0;
|
||||
systab = __va(systab);
|
||||
|
||||
config_tables = (efi_config_table_t *) systab->tables;
|
||||
if (!config_tables)
|
||||
return 0;
|
||||
config_tables = __va(config_tables);
|
||||
|
||||
for (i = 0; i < systab->nr_tables; i++) {
|
||||
if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
|
||||
pcdp = (struct pcdp *) config_tables[i].table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pcdp)
|
||||
return 0;
|
||||
pcdp = __va(pcdp);
|
||||
|
||||
for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
|
||||
if (uart->type == PCDP_CONSOLE_UART) {
|
||||
addr = uart->addr.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#endif /* CONFIG_IA64_EARLY_PRINTK_UART */
|
||||
84
extra/linux-2.6.10/drivers/firmware/pcdp.h
Normal file
84
extra/linux-2.6.10/drivers/firmware/pcdp.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Definitions for PCDP-defined console devices
|
||||
*
|
||||
* v1.0a: http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf
|
||||
* v2.0: http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf
|
||||
*
|
||||
* (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P.
|
||||
* Khalid Aziz <khalid.aziz@hp.com>
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define PCDP_CONSOLE 0
|
||||
#define PCDP_DEBUG 1
|
||||
#define PCDP_CONSOLE_OUTPUT 2
|
||||
#define PCDP_CONSOLE_INPUT 3
|
||||
|
||||
#define PCDP_UART (0 << 3)
|
||||
#define PCDP_VGA (1 << 3)
|
||||
#define PCDP_USB (2 << 3)
|
||||
|
||||
/* pcdp_uart.type and pcdp_device.type */
|
||||
#define PCDP_CONSOLE_UART (PCDP_UART | PCDP_CONSOLE)
|
||||
#define PCDP_DEBUG_UART (PCDP_UART | PCDP_DEBUG)
|
||||
#define PCDP_CONSOLE_VGA (PCDP_VGA | PCDP_CONSOLE_OUTPUT)
|
||||
#define PCDP_CONSOLE_USB (PCDP_USB | PCDP_CONSOLE_INPUT)
|
||||
|
||||
/* pcdp_uart.flags */
|
||||
#define PCDP_UART_EDGE_SENSITIVE (1 << 0)
|
||||
#define PCDP_UART_ACTIVE_LOW (1 << 1)
|
||||
#define PCDP_UART_PRIMARY_CONSOLE (1 << 2)
|
||||
#define PCDP_UART_IRQ (1 << 6) /* in pci_func for rev < 3 */
|
||||
#define PCDP_UART_PCI (1 << 7) /* in pci_func for rev < 3 */
|
||||
|
||||
struct pcdp_uart {
|
||||
u8 type;
|
||||
u8 bits;
|
||||
u8 parity;
|
||||
u8 stop_bits;
|
||||
u8 pci_seg;
|
||||
u8 pci_bus;
|
||||
u8 pci_dev;
|
||||
u8 pci_func;
|
||||
u64 baud;
|
||||
struct acpi_generic_address addr;
|
||||
u16 pci_dev_id;
|
||||
u16 pci_vendor_id;
|
||||
u32 gsi;
|
||||
u32 clock_rate;
|
||||
u8 pci_prog_intfc;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct pcdp_vga {
|
||||
u8 count; /* address space descriptors */
|
||||
};
|
||||
|
||||
/* pcdp_device.flags */
|
||||
#define PCDP_PRIMARY_CONSOLE 1
|
||||
|
||||
struct pcdp_device {
|
||||
u8 type;
|
||||
u8 flags;
|
||||
u16 length;
|
||||
u16 efi_index;
|
||||
};
|
||||
|
||||
struct pcdp {
|
||||
u8 signature[4];
|
||||
u32 length;
|
||||
u8 rev; /* PCDP v2.0 is rev 3 */
|
||||
u8 chksum;
|
||||
u8 oemid[6];
|
||||
u8 oem_tabid[8];
|
||||
u32 oem_rev;
|
||||
u8 creator_id[4];
|
||||
u32 creator_rev;
|
||||
u32 num_uarts;
|
||||
struct pcdp_uart uart[0]; /* actual size is num_uarts */
|
||||
/* remainder of table is pcdp_device structures */
|
||||
};
|
||||
Reference in New Issue
Block a user