aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig61
-rw-r--r--drivers/firmware/Makefile6
-rw-r--r--drivers/firmware/edd.c790
-rw-r--r--drivers/firmware/efivars.c781
-rw-r--r--drivers/firmware/pcdp.c100
-rw-r--r--drivers/firmware/pcdp.h84
6 files changed, 1822 insertions, 0 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
new file mode 100644
index 000000000000..5b29c3b2a331
--- /dev/null
+++ b/drivers/firmware/Kconfig
@@ -0,0 +1,61 @@
1#
2# For a description of the syntax of this configuration file,
3# see Documentation/kbuild/kconfig-language.txt.
4#
5
6menu "Firmware Drivers"
7
8config EDD
9 tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
10 depends on EXPERIMENTAL
11 depends on !IA64
12 help
13 Say Y or M here if you want to enable BIOS Enhanced Disk Drive
14 Services real mode BIOS calls to determine which disk
15 BIOS tries boot from. This information is then exported via sysfs.
16
17 This option is experimental and is known to fail to boot on some
18 obscure configurations. Most disk controller BIOS vendors do
19 not yet implement this feature.
20
21config EFI_VARS
22 tristate "EFI Variable Support via sysfs"
23 depends on EFI
24 default n
25 help
26 If you say Y here, you are able to get EFI (Extensible Firmware
27 Interface) variable information via sysfs. You may read,
28 write, create, and destroy EFI variables through this interface.
29
30 Note that using this driver in concert with efibootmgr requires
31 at least test release version 0.5.0-test3 or later, which is
32 available from Matt Domsch's website located at:
33 <http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz>
34
35 Subsequent efibootmgr releases may be found at:
36 <http://linux.dell.com/efibootmgr>
37
38config EFI_PCDP
39 bool "Console device selection via EFI PCDP or HCDP table"
40 depends on ACPI && EFI && IA64
41 default y if IA64
42 help
43 If your firmware supplies the PCDP table, and you want to
44 automatically use the primary console device it describes
45 as the Linux console, say Y here.
46
47 If your firmware supplies the HCDP table, and you want to
48 use the first serial port it describes as the Linux console,
49 say Y here. If your EFI ConOut path contains only a UART
50 device, it will become the console automatically. Otherwise,
51 you must specify the "console=hcdp" kernel boot argument.
52
53 Neither the PCDP nor the HCDP affects naming of serial devices,
54 so a serial console may be /dev/ttyS0, /dev/ttyS1, etc, depending
55 on how the driver discovers devices.
56
57 You must also enable the appropriate drivers (serial, VGA, etc.)
58
59 See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
60
61endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
new file mode 100644
index 000000000000..90fd0b26db8b
--- /dev/null
+++ b/drivers/firmware/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for the linux kernel.
3#
4obj-$(CONFIG_EDD) += edd.o
5obj-$(CONFIG_EFI_VARS) += efivars.o
6obj-$(CONFIG_EFI_PCDP) += pcdp.o
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
new file mode 100644
index 000000000000..33b669e6f977
--- /dev/null
+++ b/drivers/firmware/edd.c
@@ -0,0 +1,790 @@
1/*
2 * linux/arch/i386/kernel/edd.c
3 * Copyright (C) 2002, 2003, 2004 Dell Inc.
4 * by Matt Domsch <Matt_Domsch@dell.com>
5 * disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
6 * legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
7 *
8 * BIOS Enhanced Disk Drive Services (EDD)
9 * conformant to T13 Committee www.t13.org
10 * projects 1572D, 1484D, 1386D, 1226DT
11 *
12 * This code takes information provided by BIOS EDD calls
13 * fn41 - Check Extensions Present and
14 * fn48 - Get Device Parametes with EDD extensions
15 * made in setup.S, copied to safe structures in setup.c,
16 * and presents it in sysfs.
17 *
18 * Please see http://linux.dell.com/edd30/results.html for
19 * the list of BIOSs which have been reported to implement EDD.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License v2.0 as published by
23 * the Free Software Foundation
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 */
31
32#include <linux/module.h>
33#include <linux/string.h>
34#include <linux/types.h>
35#include <linux/init.h>
36#include <linux/stat.h>
37#include <linux/err.h>
38#include <linux/ctype.h>
39#include <linux/slab.h>
40#include <linux/limits.h>
41#include <linux/device.h>
42#include <linux/pci.h>
43#include <linux/blkdev.h>
44#include <linux/edd.h>
45
46#define EDD_VERSION "0.16"
47#define EDD_DATE "2004-Jun-25"
48
49MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
50MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
51MODULE_LICENSE("GPL");
52MODULE_VERSION(EDD_VERSION);
53
54#define left (PAGE_SIZE - (p - buf) - 1)
55
56struct edd_device {
57 unsigned int index;
58 unsigned int mbr_signature;
59 struct edd_info *info;
60 struct kobject kobj;
61};
62
63struct edd_attribute {
64 struct attribute attr;
65 ssize_t(*show) (struct edd_device * edev, char *buf);
66 int (*test) (struct edd_device * edev);
67};
68
69/* forward declarations */
70static int edd_dev_is_type(struct edd_device *edev, const char *type);
71static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
72
73static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
74
75#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
76struct edd_attribute edd_attr_##_name = { \
77 .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
78 .show = _show, \
79 .test = _test, \
80};
81
82static int
83edd_has_mbr_signature(struct edd_device *edev)
84{
85 return edev->index < min_t(unsigned char, edd.mbr_signature_nr, EDD_MBR_SIG_MAX);
86}
87
88static int
89edd_has_edd_info(struct edd_device *edev)
90{
91 return edev->index < min_t(unsigned char, edd.edd_info_nr, EDDMAXNR);
92}
93
94static inline struct edd_info *
95edd_dev_get_info(struct edd_device *edev)
96{
97 return edev->info;
98}
99
100static inline void
101edd_dev_set_info(struct edd_device *edev, int i)
102{
103 edev->index = i;
104 if (edd_has_mbr_signature(edev))
105 edev->mbr_signature = edd.mbr_signature[i];
106 if (edd_has_edd_info(edev))
107 edev->info = &edd.edd_info[i];
108}
109
110#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
111#define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
112
113static ssize_t
114edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
115{
116 struct edd_device *dev = to_edd_device(kobj);
117 struct edd_attribute *edd_attr = to_edd_attr(attr);
118 ssize_t ret = 0;
119
120 if (edd_attr->show)
121 ret = edd_attr->show(dev, buf);
122 return ret;
123}
124
125static struct sysfs_ops edd_attr_ops = {
126 .show = edd_attr_show,
127};
128
129static ssize_t
130edd_show_host_bus(struct edd_device *edev, char *buf)
131{
132 struct edd_info *info;
133 char *p = buf;
134 int i;
135
136 if (!edev)
137 return -EINVAL;
138 info = edd_dev_get_info(edev);
139 if (!info || !buf)
140 return -EINVAL;
141
142 for (i = 0; i < 4; i++) {
143 if (isprint(info->params.host_bus_type[i])) {
144 p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
145 } else {
146 p += scnprintf(p, left, " ");
147 }
148 }
149
150 if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
151 p += scnprintf(p, left, "\tbase_address: %x\n",
152 info->params.interface_path.isa.base_address);
153 } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
154 !strncmp(info->params.host_bus_type, "PCI", 3)) {
155 p += scnprintf(p, left,
156 "\t%02x:%02x.%d channel: %u\n",
157 info->params.interface_path.pci.bus,
158 info->params.interface_path.pci.slot,
159 info->params.interface_path.pci.function,
160 info->params.interface_path.pci.channel);
161 } else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
162 !strncmp(info->params.host_bus_type, "XPRS", 4) ||
163 !strncmp(info->params.host_bus_type, "HTPT", 4)) {
164 p += scnprintf(p, left,
165 "\tTBD: %llx\n",
166 info->params.interface_path.ibnd.reserved);
167
168 } else {
169 p += scnprintf(p, left, "\tunknown: %llx\n",
170 info->params.interface_path.unknown.reserved);
171 }
172 return (p - buf);
173}
174
175static ssize_t
176edd_show_interface(struct edd_device *edev, char *buf)
177{
178 struct edd_info *info;
179 char *p = buf;
180 int i;
181
182 if (!edev)
183 return -EINVAL;
184 info = edd_dev_get_info(edev);
185 if (!info || !buf)
186 return -EINVAL;
187
188 for (i = 0; i < 8; i++) {
189 if (isprint(info->params.interface_type[i])) {
190 p += scnprintf(p, left, "%c", info->params.interface_type[i]);
191 } else {
192 p += scnprintf(p, left, " ");
193 }
194 }
195 if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
196 p += scnprintf(p, left, "\tdevice: %u lun: %u\n",
197 info->params.device_path.atapi.device,
198 info->params.device_path.atapi.lun);
199 } else if (!strncmp(info->params.interface_type, "ATA", 3)) {
200 p += scnprintf(p, left, "\tdevice: %u\n",
201 info->params.device_path.ata.device);
202 } else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
203 p += scnprintf(p, left, "\tid: %u lun: %llu\n",
204 info->params.device_path.scsi.id,
205 info->params.device_path.scsi.lun);
206 } else if (!strncmp(info->params.interface_type, "USB", 3)) {
207 p += scnprintf(p, left, "\tserial_number: %llx\n",
208 info->params.device_path.usb.serial_number);
209 } else if (!strncmp(info->params.interface_type, "1394", 4)) {
210 p += scnprintf(p, left, "\teui: %llx\n",
211 info->params.device_path.i1394.eui);
212 } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
213 p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
214 info->params.device_path.fibre.wwid,
215 info->params.device_path.fibre.lun);
216 } else if (!strncmp(info->params.interface_type, "I2O", 3)) {
217 p += scnprintf(p, left, "\tidentity_tag: %llx\n",
218 info->params.device_path.i2o.identity_tag);
219 } else if (!strncmp(info->params.interface_type, "RAID", 4)) {
220 p += scnprintf(p, left, "\tidentity_tag: %x\n",
221 info->params.device_path.raid.array_number);
222 } else if (!strncmp(info->params.interface_type, "SATA", 4)) {
223 p += scnprintf(p, left, "\tdevice: %u\n",
224 info->params.device_path.sata.device);
225 } else {
226 p += scnprintf(p, left, "\tunknown: %llx %llx\n",
227 info->params.device_path.unknown.reserved1,
228 info->params.device_path.unknown.reserved2);
229 }
230
231 return (p - buf);
232}
233
234/**
235 * edd_show_raw_data() - copies raw data to buffer for userspace to parse
236 *
237 * Returns: number of bytes written, or -EINVAL on failure
238 */
239static ssize_t
240edd_show_raw_data(struct edd_device *edev, char *buf)
241{
242 struct edd_info *info;
243 ssize_t len = sizeof (info->params);
244 if (!edev)
245 return -EINVAL;
246 info = edd_dev_get_info(edev);
247 if (!info || !buf)
248 return -EINVAL;
249
250 if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
251 len = info->params.length;
252
253 /* In case of buggy BIOSs */
254 if (len > (sizeof(info->params)))
255 len = sizeof(info->params);
256
257 memcpy(buf, &info->params, len);
258 return len;
259}
260
261static ssize_t
262edd_show_version(struct edd_device *edev, char *buf)
263{
264 struct edd_info *info;
265 char *p = buf;
266 if (!edev)
267 return -EINVAL;
268 info = edd_dev_get_info(edev);
269 if (!info || !buf)
270 return -EINVAL;
271
272 p += scnprintf(p, left, "0x%02x\n", info->version);
273 return (p - buf);
274}
275
276static ssize_t
277edd_show_mbr_signature(struct edd_device *edev, char *buf)
278{
279 char *p = buf;
280 p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature);
281 return (p - buf);
282}
283
284static ssize_t
285edd_show_extensions(struct edd_device *edev, char *buf)
286{
287 struct edd_info *info;
288 char *p = buf;
289 if (!edev)
290 return -EINVAL;
291 info = edd_dev_get_info(edev);
292 if (!info || !buf)
293 return -EINVAL;
294
295 if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
296 p += scnprintf(p, left, "Fixed disk access\n");
297 }
298 if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
299 p += scnprintf(p, left, "Device locking and ejecting\n");
300 }
301 if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
302 p += scnprintf(p, left, "Enhanced Disk Drive support\n");
303 }
304 if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
305 p += scnprintf(p, left, "64-bit extensions\n");
306 }
307 return (p - buf);
308}
309
310static ssize_t
311edd_show_info_flags(struct edd_device *edev, char *buf)
312{
313 struct edd_info *info;
314 char *p = buf;
315 if (!edev)
316 return -EINVAL;
317 info = edd_dev_get_info(edev);
318 if (!info || !buf)
319 return -EINVAL;
320
321 if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
322 p += scnprintf(p, left, "DMA boundary error transparent\n");
323 if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
324 p += scnprintf(p, left, "geometry valid\n");
325 if (info->params.info_flags & EDD_INFO_REMOVABLE)
326 p += scnprintf(p, left, "removable\n");
327 if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
328 p += scnprintf(p, left, "write verify\n");
329 if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
330 p += scnprintf(p, left, "media change notification\n");
331 if (info->params.info_flags & EDD_INFO_LOCKABLE)
332 p += scnprintf(p, left, "lockable\n");
333 if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
334 p += scnprintf(p, left, "no media present\n");
335 if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
336 p += scnprintf(p, left, "use int13 fn50\n");
337 return (p - buf);
338}
339
340static ssize_t
341edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
342{
343 struct edd_info *info;
344 char *p = buf;
345 if (!edev)
346 return -EINVAL;
347 info = edd_dev_get_info(edev);
348 if (!info || !buf)
349 return -EINVAL;
350
351 p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
352 return (p - buf);
353}
354
355static ssize_t
356edd_show_legacy_max_head(struct edd_device *edev, char *buf)
357{
358 struct edd_info *info;
359 char *p = buf;
360 if (!edev)
361 return -EINVAL;
362 info = edd_dev_get_info(edev);
363 if (!info || !buf)
364 return -EINVAL;
365
366 p += snprintf(p, left, "%u\n", info->legacy_max_head);
367 return (p - buf);
368}
369
370static ssize_t
371edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
372{
373 struct edd_info *info;
374 char *p = buf;
375 if (!edev)
376 return -EINVAL;
377 info = edd_dev_get_info(edev);
378 if (!info || !buf)
379 return -EINVAL;
380
381 p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
382 return (p - buf);
383}
384
385static ssize_t
386edd_show_default_cylinders(struct edd_device *edev, char *buf)
387{
388 struct edd_info *info;
389 char *p = buf;
390 if (!edev)
391 return -EINVAL;
392 info = edd_dev_get_info(edev);
393 if (!info || !buf)
394 return -EINVAL;
395
396 p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders);
397 return (p - buf);
398}
399
400static ssize_t
401edd_show_default_heads(struct edd_device *edev, char *buf)
402{
403 struct edd_info *info;
404 char *p = buf;
405 if (!edev)
406 return -EINVAL;
407 info = edd_dev_get_info(edev);
408 if (!info || !buf)
409 return -EINVAL;
410
411 p += scnprintf(p, left, "%u\n", info->params.num_default_heads);
412 return (p - buf);
413}
414
415static ssize_t
416edd_show_default_sectors_per_track(struct edd_device *edev, char *buf)
417{
418 struct edd_info *info;
419 char *p = buf;
420 if (!edev)
421 return -EINVAL;
422 info = edd_dev_get_info(edev);
423 if (!info || !buf)
424 return -EINVAL;
425
426 p += scnprintf(p, left, "%u\n", info->params.sectors_per_track);
427 return (p - buf);
428}
429
430static ssize_t
431edd_show_sectors(struct edd_device *edev, char *buf)
432{
433 struct edd_info *info;
434 char *p = buf;
435 if (!edev)
436 return -EINVAL;
437 info = edd_dev_get_info(edev);
438 if (!info || !buf)
439 return -EINVAL;
440
441 p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors);
442 return (p - buf);
443}
444
445
446/*
447 * Some device instances may not have all the above attributes,
448 * or the attribute values may be meaningless (i.e. if
449 * the device is < EDD 3.0, it won't have host_bus and interface
450 * information), so don't bother making files for them. Likewise
451 * if the default_{cylinders,heads,sectors_per_track} values
452 * are zero, the BIOS doesn't provide sane values, don't bother
453 * creating files for them either.
454 */
455
456static int
457edd_has_legacy_max_cylinder(struct edd_device *edev)
458{
459 struct edd_info *info;
460 if (!edev)
461 return 0;
462 info = edd_dev_get_info(edev);
463 if (!info)
464 return 0;
465 return info->legacy_max_cylinder > 0;
466}
467
468static int
469edd_has_legacy_max_head(struct edd_device *edev)
470{
471 struct edd_info *info;
472 if (!edev)
473 return 0;
474 info = edd_dev_get_info(edev);
475 if (!info)
476 return 0;
477 return info->legacy_max_head > 0;
478}
479
480static int
481edd_has_legacy_sectors_per_track(struct edd_device *edev)
482{
483 struct edd_info *info;
484 if (!edev)
485 return 0;
486 info = edd_dev_get_info(edev);
487 if (!info)
488 return 0;
489 return info->legacy_sectors_per_track > 0;
490}
491
492static int
493edd_has_default_cylinders(struct edd_device *edev)
494{
495 struct edd_info *info;
496 if (!edev)
497 return 0;
498 info = edd_dev_get_info(edev);
499 if (!info)
500 return 0;
501 return info->params.num_default_cylinders > 0;
502}
503
504static int
505edd_has_default_heads(struct edd_device *edev)
506{
507 struct edd_info *info;
508 if (!edev)
509 return 0;
510 info = edd_dev_get_info(edev);
511 if (!info)
512 return 0;
513 return info->params.num_default_heads > 0;
514}
515
516static int
517edd_has_default_sectors_per_track(struct edd_device *edev)
518{
519 struct edd_info *info;
520 if (!edev)
521 return 0;
522 info = edd_dev_get_info(edev);
523 if (!info)
524 return 0;
525 return info->params.sectors_per_track > 0;
526}
527
528static int
529edd_has_edd30(struct edd_device *edev)
530{
531 struct edd_info *info;
532 int i, nonzero_path = 0;
533 char c;
534
535 if (!edev)
536 return 0;
537 info = edd_dev_get_info(edev);
538 if (!info)
539 return 0;
540
541 if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
542 return 0;
543 }
544
545 for (i = 30; i <= 73; i++) {
546 c = *(((uint8_t *) info) + i + 4);
547 if (c) {
548 nonzero_path++;
549 break;
550 }
551 }
552 if (!nonzero_path) {
553 return 0;
554 }
555
556 return 1;
557}
558
559
560static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, edd_has_edd_info);
561static EDD_DEVICE_ATTR(version, 0444, edd_show_version, edd_has_edd_info);
562static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, edd_has_edd_info);
563static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, edd_has_edd_info);
564static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, edd_has_edd_info);
565static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444,
566 edd_show_legacy_max_cylinder,
567 edd_has_legacy_max_cylinder);
568static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head,
569 edd_has_legacy_max_head);
570static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444,
571 edd_show_legacy_sectors_per_track,
572 edd_has_legacy_sectors_per_track);
573static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
574 edd_has_default_cylinders);
575static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
576 edd_has_default_heads);
577static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
578 edd_show_default_sectors_per_track,
579 edd_has_default_sectors_per_track);
580static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
581static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
582static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature);
583
584
585/* These are default attributes that are added for every edd
586 * device discovered. There are none.
587 */
588static struct attribute * def_attrs[] = {
589 NULL,
590};
591
592/* These attributes are conditional and only added for some devices. */
593static struct edd_attribute * edd_attrs[] = {
594 &edd_attr_raw_data,
595 &edd_attr_version,
596 &edd_attr_extensions,
597 &edd_attr_info_flags,
598 &edd_attr_sectors,
599 &edd_attr_legacy_max_cylinder,
600 &edd_attr_legacy_max_head,
601 &edd_attr_legacy_sectors_per_track,
602 &edd_attr_default_cylinders,
603 &edd_attr_default_heads,
604 &edd_attr_default_sectors_per_track,
605 &edd_attr_interface,
606 &edd_attr_host_bus,
607 &edd_attr_mbr_signature,
608 NULL,
609};
610
611/**
612 * edd_release - free edd structure
613 * @kobj: kobject of edd structure
614 *
615 * This is called when the refcount of the edd structure
616 * reaches 0. This should happen right after we unregister,
617 * but just in case, we use the release callback anyway.
618 */
619
620static void edd_release(struct kobject * kobj)
621{
622 struct edd_device * dev = to_edd_device(kobj);
623 kfree(dev);
624}
625
626static struct kobj_type ktype_edd = {
627 .release = edd_release,
628 .sysfs_ops = &edd_attr_ops,
629 .default_attrs = def_attrs,
630};
631
632static decl_subsys(edd,&ktype_edd,NULL);
633
634
635/**
636 * edd_dev_is_type() - is this EDD device a 'type' device?
637 * @edev
638 * @type - a host bus or interface identifier string per the EDD spec
639 *
640 * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
641 */
642static int
643edd_dev_is_type(struct edd_device *edev, const char *type)
644{
645 struct edd_info *info;
646 if (!edev)
647 return 0;
648 info = edd_dev_get_info(edev);
649
650 if (type && info) {
651 if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
652 !strncmp(info->params.interface_type, type, strlen(type)))
653 return 1;
654 }
655 return 0;
656}
657
658/**
659 * edd_get_pci_dev() - finds pci_dev that matches edev
660 * @edev - edd_device
661 *
662 * Returns pci_dev if found, or NULL
663 */
664static struct pci_dev *
665edd_get_pci_dev(struct edd_device *edev)
666{
667 struct edd_info *info = edd_dev_get_info(edev);
668
669 if (edd_dev_is_type(edev, "PCI")) {
670 return pci_find_slot(info->params.interface_path.pci.bus,
671 PCI_DEVFN(info->params.interface_path.pci.slot,
672 info->params.interface_path.pci.
673 function));
674 }
675 return NULL;
676}
677
678static int
679edd_create_symlink_to_pcidev(struct edd_device *edev)
680{
681
682 struct pci_dev *pci_dev = edd_get_pci_dev(edev);
683 if (!pci_dev)
684 return 1;
685 return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
686}
687
688static inline void
689edd_device_unregister(struct edd_device *edev)
690{
691 kobject_unregister(&edev->kobj);
692}
693
694static void edd_populate_dir(struct edd_device * edev)
695{
696 struct edd_attribute * attr;
697 int error = 0;
698 int i;
699
700 for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
701 if (!attr->test ||
702 (attr->test && attr->test(edev)))
703 error = sysfs_create_file(&edev->kobj,&attr->attr);
704 }
705
706 if (!error) {
707 edd_create_symlink_to_pcidev(edev);
708 }
709}
710
711static int
712edd_device_register(struct edd_device *edev, int i)
713{
714 int error;
715
716 if (!edev)
717 return 1;
718 memset(edev, 0, sizeof (*edev));
719 edd_dev_set_info(edev, i);
720 kobject_set_name(&edev->kobj, "int13_dev%02x",
721 0x80 + i);
722 kobj_set_kset_s(edev,edd_subsys);
723 error = kobject_register(&edev->kobj);
724 if (!error)
725 edd_populate_dir(edev);
726 return error;
727}
728
729static inline int edd_num_devices(void)
730{
731 return max_t(unsigned char,
732 min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr),
733 min_t(unsigned char, EDDMAXNR, edd.edd_info_nr));
734}
735
736/**
737 * edd_init() - creates sysfs tree of EDD data
738 */
739static int __init
740edd_init(void)
741{
742 unsigned int i;
743 int rc=0;
744 struct edd_device *edev;
745
746 printk(KERN_INFO "BIOS EDD facility v%s %s, %d devices found\n",
747 EDD_VERSION, EDD_DATE, edd_num_devices());
748
749 if (!edd_num_devices()) {
750 printk(KERN_INFO "EDD information not available.\n");
751 return 1;
752 }
753
754 rc = firmware_register(&edd_subsys);
755 if (rc)
756 return rc;
757
758 for (i = 0; i < edd_num_devices() && !rc; i++) {
759 edev = kmalloc(sizeof (*edev), GFP_KERNEL);
760 if (!edev)
761 return -ENOMEM;
762
763 rc = edd_device_register(edev, i);
764 if (rc) {
765 kfree(edev);
766 break;
767 }
768 edd_devices[i] = edev;
769 }
770
771 if (rc)
772 firmware_unregister(&edd_subsys);
773 return rc;
774}
775
776static void __exit
777edd_exit(void)
778{
779 int i;
780 struct edd_device *edev;
781
782 for (i = 0; i < edd_num_devices(); i++) {
783 if ((edev = edd_devices[i]))
784 edd_device_unregister(edev);
785 }
786 firmware_unregister(&edd_subsys);
787}
788
789late_initcall(edd_init);
790module_exit(edd_exit);
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
new file mode 100644
index 000000000000..0287ff65963b
--- /dev/null
+++ b/drivers/firmware/efivars.c
@@ -0,0 +1,781 @@
1/*
2 * EFI Variables - efivars.c
3 *
4 * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
5 * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
6 *
7 * This code takes all variables accessible from EFI runtime and
8 * exports them via sysfs
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Changelog:
25 *
26 * 17 May 2004 - Matt Domsch <Matt_Domsch@dell.com>
27 * remove check for efi_enabled in exit
28 * add MODULE_VERSION
29 *
30 * 26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com>
31 * minor bug fixes
32 *
33 * 21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com)
34 * converted driver to export variable information via sysfs
35 * and moved to drivers/firmware directory
36 * bumped revision number to v0.07 to reflect conversion & move
37 *
38 * 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
39 * fix locking per Peter Chubb's findings
40 *
41 * 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
42 * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
43 *
44 * 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
45 * use list_for_each_safe when deleting vars.
46 * remove ifdef CONFIG_SMP around include <linux/smp.h>
47 * v0.04 release to linux-ia64@linuxia64.org
48 *
49 * 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
50 * Moved vars from /proc/efi to /proc/efi/vars, and made
51 * efi.c own the /proc/efi directory.
52 * v0.03 release to linux-ia64@linuxia64.org
53 *
54 * 26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
55 * At the request of Stephane, moved ownership of /proc/efi
56 * to efi.c, and now efivars lives under /proc/efi/vars.
57 *
58 * 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
59 * Feedback received from Stephane Eranian incorporated.
60 * efivar_write() checks copy_from_user() return value.
61 * efivar_read/write() returns proper errno.
62 * v0.02 release to linux-ia64@linuxia64.org
63 *
64 * 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
65 * v0.01 release to linux-ia64@linuxia64.org
66 */
67
68#include <linux/config.h>
69#include <linux/types.h>
70#include <linux/errno.h>
71#include <linux/init.h>
72#include <linux/sched.h> /* for capable() */
73#include <linux/mm.h>
74#include <linux/module.h>
75#include <linux/string.h>
76#include <linux/smp.h>
77#include <linux/efi.h>
78#include <linux/sysfs.h>
79#include <linux/kobject.h>
80#include <linux/device.h>
81
82#include <asm/uaccess.h>
83
84#define EFIVARS_VERSION "0.08"
85#define EFIVARS_DATE "2004-May-17"
86
87MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
88MODULE_DESCRIPTION("sysfs interface to EFI Variables");
89MODULE_LICENSE("GPL");
90MODULE_VERSION(EFIVARS_VERSION);
91
92/*
93 * efivars_lock protects two things:
94 * 1) efivar_list - adds, removals, reads, writes
95 * 2) efi.[gs]et_variable() calls.
96 * It must not be held when creating sysfs entries or calling kmalloc.
97 * efi.get_next_variable() is only called from efivars_init(),
98 * which is protected by the BKL, so that path is safe.
99 */
100static DEFINE_SPINLOCK(efivars_lock);
101static LIST_HEAD(efivar_list);
102
103/*
104 * The maximum size of VariableName + Data = 1024
105 * Therefore, it's reasonable to save that much
106 * space in each part of the structure,
107 * and we use a page for reading/writing.
108 */
109
110struct efi_variable {
111 efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
112 efi_guid_t VendorGuid;
113 unsigned long DataSize;
114 __u8 Data[1024];
115 efi_status_t Status;
116 __u32 Attributes;
117} __attribute__((packed));
118
119
120struct efivar_entry {
121 struct efi_variable var;
122 struct list_head list;
123 struct kobject kobj;
124};
125
126#define get_efivar_entry(n) list_entry(n, struct efivar_entry, list)
127
128struct efivar_attribute {
129 struct attribute attr;
130 ssize_t (*show) (struct efivar_entry *entry, char *buf);
131 ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
132};
133
134
135#define EFI_ATTR(_name, _mode, _show, _store) \
136struct subsys_attribute efi_attr_##_name = { \
137 .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
138 .show = _show, \
139 .store = _store, \
140};
141
142#define EFIVAR_ATTR(_name, _mode, _show, _store) \
143struct efivar_attribute efivar_attr_##_name = { \
144 .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
145 .show = _show, \
146 .store = _store, \
147};
148
149#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
150struct subsys_attribute var_subsys_attr_##_name = { \
151 .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
152 .show = _show, \
153 .store = _store, \
154};
155
156#define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
157#define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj)
158
159/*
160 * Prototype for sysfs creation function
161 */
162static int
163efivar_create_sysfs_entry(unsigned long variable_name_size,
164 efi_char16_t *variable_name,
165 efi_guid_t *vendor_guid);
166
167/* Return the number of unicode characters in data */
168static unsigned long
169utf8_strlen(efi_char16_t *data, unsigned long maxlength)
170{
171 unsigned long length = 0;
172
173 while (*data++ != 0 && length < maxlength)
174 length++;
175 return length;
176}
177
178/*
179 * Return the number of bytes is the length of this string
180 * Note: this is NOT the same as the number of unicode characters
181 */
182static inline unsigned long
183utf8_strsize(efi_char16_t *data, unsigned long maxlength)
184{
185 return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
186}
187
188static efi_status_t
189get_var_data(struct efi_variable *var)
190{
191 efi_status_t status;
192
193 spin_lock(&efivars_lock);
194 var->DataSize = 1024;
195 status = efi.get_variable(var->VariableName,
196 &var->VendorGuid,
197 &var->Attributes,
198 &var->DataSize,
199 var->Data);
200 spin_unlock(&efivars_lock);
201 if (status != EFI_SUCCESS) {
202 printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
203 status);
204 }
205 return status;
206}
207
208static ssize_t
209efivar_guid_read(struct efivar_entry *entry, char *buf)
210{
211 struct efi_variable *var = &entry->var;
212 char *str = buf;
213
214 if (!entry || !buf)
215 return 0;
216
217 efi_guid_unparse(&var->VendorGuid, str);
218 str += strlen(str);
219 str += sprintf(str, "\n");
220
221 return str - buf;
222}
223
224static ssize_t
225efivar_attr_read(struct efivar_entry *entry, char *buf)
226{
227 struct efi_variable *var = &entry->var;
228 char *str = buf;
229 efi_status_t status;
230
231 if (!entry || !buf)
232 return -EINVAL;
233
234 status = get_var_data(var);
235 if (status != EFI_SUCCESS)
236 return -EIO;
237
238 if (var->Attributes & 0x1)
239 str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
240 if (var->Attributes & 0x2)
241 str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
242 if (var->Attributes & 0x4)
243 str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
244 return str - buf;
245}
246
247static ssize_t
248efivar_size_read(struct efivar_entry *entry, char *buf)
249{
250 struct efi_variable *var = &entry->var;
251 char *str = buf;
252 efi_status_t status;
253
254 if (!entry || !buf)
255 return -EINVAL;
256
257 status = get_var_data(var);
258 if (status != EFI_SUCCESS)
259 return -EIO;
260
261 str += sprintf(str, "0x%lx\n", var->DataSize);
262 return str - buf;
263}
264
265static ssize_t
266efivar_data_read(struct efivar_entry *entry, char *buf)
267{
268 struct efi_variable *var = &entry->var;
269 efi_status_t status;
270
271 if (!entry || !buf)
272 return -EINVAL;
273
274 status = get_var_data(var);
275 if (status != EFI_SUCCESS)
276 return -EIO;
277
278 memcpy(buf, var->Data, var->DataSize);
279 return var->DataSize;
280}
281/*
282 * We allow each variable to be edited via rewriting the
283 * entire efi variable structure.
284 */
285static ssize_t
286efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
287{
288 struct efi_variable *new_var, *var = &entry->var;
289 efi_status_t status = EFI_NOT_FOUND;
290
291 if (count != sizeof(struct efi_variable))
292 return -EINVAL;
293
294 new_var = (struct efi_variable *)buf;
295 /*
296 * If only updating the variable data, then the name
297 * and guid should remain the same
298 */
299 if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
300 efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
301 printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
302 return -EINVAL;
303 }
304
305 if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
306 printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
307 return -EINVAL;
308 }
309
310 spin_lock(&efivars_lock);
311 status = efi.set_variable(new_var->VariableName,
312 &new_var->VendorGuid,
313 new_var->Attributes,
314 new_var->DataSize,
315 new_var->Data);
316
317 spin_unlock(&efivars_lock);
318
319 if (status != EFI_SUCCESS) {
320 printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
321 status);
322 return -EIO;
323 }
324
325 memcpy(&entry->var, new_var, count);
326 return count;
327}
328
329static ssize_t
330efivar_show_raw(struct efivar_entry *entry, char *buf)
331{
332 struct efi_variable *var = &entry->var;
333 efi_status_t status;
334
335 if (!entry || !buf)
336 return 0;
337
338 status = get_var_data(var);
339 if (status != EFI_SUCCESS)
340 return -EIO;
341
342 memcpy(buf, var, sizeof(*var));
343 return sizeof(*var);
344}
345
346/*
347 * Generic read/write functions that call the specific functions of
348 * the atttributes...
349 */
350static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
351 char *buf)
352{
353 struct efivar_entry *var = to_efivar_entry(kobj);
354 struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
355 ssize_t ret = 0;
356
357 if (!capable(CAP_SYS_ADMIN))
358 return -EACCES;
359
360 if (efivar_attr->show) {
361 ret = efivar_attr->show(var, buf);
362 }
363 return ret;
364}
365
366static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
367 const char *buf, size_t count)
368{
369 struct efivar_entry *var = to_efivar_entry(kobj);
370 struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
371 ssize_t ret = 0;
372
373 if (!capable(CAP_SYS_ADMIN))
374 return -EACCES;
375
376 if (efivar_attr->store)
377 ret = efivar_attr->store(var, buf, count);
378
379 return ret;
380}
381
382static struct sysfs_ops efivar_attr_ops = {
383 .show = efivar_attr_show,
384 .store = efivar_attr_store,
385};
386
387static void efivar_release(struct kobject *kobj)
388{
389 struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
390 spin_lock(&efivars_lock);
391 list_del(&var->list);
392 spin_unlock(&efivars_lock);
393 kfree(var);
394}
395
396static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
397static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
398static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
399static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
400static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
401
402static struct attribute *def_attrs[] = {
403 &efivar_attr_guid.attr,
404 &efivar_attr_size.attr,
405 &efivar_attr_attributes.attr,
406 &efivar_attr_data.attr,
407 &efivar_attr_raw_var.attr,
408 NULL,
409};
410
411static struct kobj_type ktype_efivar = {
412 .release = efivar_release,
413 .sysfs_ops = &efivar_attr_ops,
414 .default_attrs = def_attrs,
415};
416
417static ssize_t
418dummy(struct subsystem *sub, char *buf)
419{
420 return -ENODEV;
421}
422
423static inline void
424efivar_unregister(struct efivar_entry *var)
425{
426 kobject_unregister(&var->kobj);
427}
428
429
430static ssize_t
431efivar_create(struct subsystem *sub, const char *buf, size_t count)
432{
433 struct efi_variable *new_var = (struct efi_variable *)buf;
434 struct efivar_entry *search_efivar = NULL;
435 unsigned long strsize1, strsize2;
436 struct list_head *pos, *n;
437 efi_status_t status = EFI_NOT_FOUND;
438 int found = 0;
439
440 if (!capable(CAP_SYS_ADMIN))
441 return -EACCES;
442
443 spin_lock(&efivars_lock);
444
445 /*
446 * Does this variable already exist?
447 */
448 list_for_each_safe(pos, n, &efivar_list) {
449 search_efivar = get_efivar_entry(pos);
450 strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
451 strsize2 = utf8_strsize(new_var->VariableName, 1024);
452 if (strsize1 == strsize2 &&
453 !memcmp(&(search_efivar->var.VariableName),
454 new_var->VariableName, strsize1) &&
455 !efi_guidcmp(search_efivar->var.VendorGuid,
456 new_var->VendorGuid)) {
457 found = 1;
458 break;
459 }
460 }
461 if (found) {
462 spin_unlock(&efivars_lock);
463 return -EINVAL;
464 }
465
466 /* now *really* create the variable via EFI */
467 status = efi.set_variable(new_var->VariableName,
468 &new_var->VendorGuid,
469 new_var->Attributes,
470 new_var->DataSize,
471 new_var->Data);
472
473 if (status != EFI_SUCCESS) {
474 printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
475 status);
476 spin_unlock(&efivars_lock);
477 return -EIO;
478 }
479 spin_unlock(&efivars_lock);
480
481 /* Create the entry in sysfs. Locking is not required here */
482 status = efivar_create_sysfs_entry(utf8_strsize(new_var->VariableName,
483 1024), new_var->VariableName, &new_var->VendorGuid);
484 if (status) {
485 printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.\n");
486 }
487 return count;
488}
489
490static ssize_t
491efivar_delete(struct subsystem *sub, const char *buf, size_t count)
492{
493 struct efi_variable *del_var = (struct efi_variable *)buf;
494 struct efivar_entry *search_efivar = NULL;
495 unsigned long strsize1, strsize2;
496 struct list_head *pos, *n;
497 efi_status_t status = EFI_NOT_FOUND;
498 int found = 0;
499
500 if (!capable(CAP_SYS_ADMIN))
501 return -EACCES;
502
503 spin_lock(&efivars_lock);
504
505 /*
506 * Does this variable already exist?
507 */
508 list_for_each_safe(pos, n, &efivar_list) {
509 search_efivar = get_efivar_entry(pos);
510 strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
511 strsize2 = utf8_strsize(del_var->VariableName, 1024);
512 if (strsize1 == strsize2 &&
513 !memcmp(&(search_efivar->var.VariableName),
514 del_var->VariableName, strsize1) &&
515 !efi_guidcmp(search_efivar->var.VendorGuid,
516 del_var->VendorGuid)) {
517 found = 1;
518 break;
519 }
520 }
521 if (!found) {
522 spin_unlock(&efivars_lock);
523 return -EINVAL;
524 }
525 /* force the Attributes/DataSize to 0 to ensure deletion */
526 del_var->Attributes = 0;
527 del_var->DataSize = 0;
528
529 status = efi.set_variable(del_var->VariableName,
530 &del_var->VendorGuid,
531 del_var->Attributes,
532 del_var->DataSize,
533 del_var->Data);
534
535 if (status != EFI_SUCCESS) {
536 printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
537 status);
538 spin_unlock(&efivars_lock);
539 return -EIO;
540 }
541 /* We need to release this lock before unregistering. */
542 spin_unlock(&efivars_lock);
543
544 efivar_unregister(search_efivar);
545
546 /* It's dead Jim.... */
547 return count;
548}
549
550static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);
551static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);
552
553static struct subsys_attribute *var_subsys_attrs[] = {
554 &var_subsys_attr_new_var,
555 &var_subsys_attr_del_var,
556 NULL,
557};
558
559/*
560 * Let's not leave out systab information that snuck into
561 * the efivars driver
562 */
563static ssize_t
564systab_read(struct subsystem *entry, char *buf)
565{
566 char *str = buf;
567
568 if (!entry || !buf)
569 return -EINVAL;
570
571 if (efi.mps)
572 str += sprintf(str, "MPS=0x%lx\n", __pa(efi.mps));
573 if (efi.acpi20)
574 str += sprintf(str, "ACPI20=0x%lx\n", __pa(efi.acpi20));
575 if (efi.acpi)
576 str += sprintf(str, "ACPI=0x%lx\n", __pa(efi.acpi));
577 if (efi.smbios)
578 str += sprintf(str, "SMBIOS=0x%lx\n", __pa(efi.smbios));
579 if (efi.hcdp)
580 str += sprintf(str, "HCDP=0x%lx\n", __pa(efi.hcdp));
581 if (efi.boot_info)
582 str += sprintf(str, "BOOTINFO=0x%lx\n", __pa(efi.boot_info));
583 if (efi.uga)
584 str += sprintf(str, "UGA=0x%lx\n", __pa(efi.uga));
585
586 return str - buf;
587}
588
589static EFI_ATTR(systab, 0400, systab_read, NULL);
590
591static struct subsys_attribute *efi_subsys_attrs[] = {
592 &efi_attr_systab,
593 NULL, /* maybe more in the future? */
594};
595
596static decl_subsys(vars, &ktype_efivar, NULL);
597static decl_subsys(efi, NULL, NULL);
598
599/*
600 * efivar_create_sysfs_entry()
601 * Requires:
602 * variable_name_size = number of bytes required to hold
603 * variable_name (not counting the NULL
604 * character at the end.
605 * efivars_lock is not held on entry or exit.
606 * Returns 1 on failure, 0 on success
607 */
608static int
609efivar_create_sysfs_entry(unsigned long variable_name_size,
610 efi_char16_t *variable_name,
611 efi_guid_t *vendor_guid)
612{
613 int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
614 char *short_name;
615 struct efivar_entry *new_efivar;
616
617 short_name = kmalloc(short_name_size + 1, GFP_KERNEL);
618 new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL);
619
620 if (!short_name || !new_efivar) {
621 if (short_name) kfree(short_name);
622 if (new_efivar) kfree(new_efivar);
623 return 1;
624 }
625 memset(short_name, 0, short_name_size+1);
626 memset(new_efivar, 0, sizeof(struct efivar_entry));
627
628 memcpy(new_efivar->var.VariableName, variable_name,
629 variable_name_size);
630 memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
631
632 /* Convert Unicode to normal chars (assume top bits are 0),
633 ala UTF-8 */
634 for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
635 short_name[i] = variable_name[i] & 0xFF;
636 }
637 /* This is ugly, but necessary to separate one vendor's
638 private variables from another's. */
639
640 *(short_name + strlen(short_name)) = '-';
641 efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
642
643 kobject_set_name(&new_efivar->kobj, "%s", short_name);
644 kobj_set_kset_s(new_efivar, vars_subsys);
645 kobject_register(&new_efivar->kobj);
646
647 kfree(short_name); short_name = NULL;
648
649 spin_lock(&efivars_lock);
650 list_add(&new_efivar->list, &efivar_list);
651 spin_unlock(&efivars_lock);
652
653 return 0;
654}
655/*
656 * For now we register the efi subsystem with the firmware subsystem
657 * and the vars subsystem with the efi subsystem. In the future, it
658 * might make sense to split off the efi subsystem into its own
659 * driver, but for now only efivars will register with it, so just
660 * include it here.
661 */
662
663static int __init
664efivars_init(void)
665{
666 efi_status_t status = EFI_NOT_FOUND;
667 efi_guid_t vendor_guid;
668 efi_char16_t *variable_name;
669 struct subsys_attribute *attr;
670 unsigned long variable_name_size = 1024;
671 int i, error = 0;
672
673 if (!efi_enabled)
674 return -ENODEV;
675
676 variable_name = kmalloc(variable_name_size, GFP_KERNEL);
677 if (!variable_name) {
678 printk(KERN_ERR "efivars: Memory allocation failed.\n");
679 return -ENOMEM;
680 }
681
682 memset(variable_name, 0, variable_name_size);
683
684 printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
685 EFIVARS_DATE);
686
687 /*
688 * For now we'll register the efi subsys within this driver
689 */
690
691 error = firmware_register(&efi_subsys);
692
693 if (error) {
694 printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error);
695 goto out_free;
696 }
697
698 kset_set_kset_s(&vars_subsys, efi_subsys);
699
700 error = subsystem_register(&vars_subsys);
701
702 if (error) {
703 printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error);
704 goto out_firmware_unregister;
705 }
706
707 /*
708 * Per EFI spec, the maximum storage allocated for both
709 * the variable name and variable data is 1024 bytes.
710 */
711
712 do {
713 variable_name_size = 1024;
714
715 status = efi.get_next_variable(&variable_name_size,
716 variable_name,
717 &vendor_guid);
718 switch (status) {
719 case EFI_SUCCESS:
720 efivar_create_sysfs_entry(variable_name_size,
721 variable_name,
722 &vendor_guid);
723 break;
724 case EFI_NOT_FOUND:
725 break;
726 default:
727 printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
728 status);
729 status = EFI_NOT_FOUND;
730 break;
731 }
732 } while (status != EFI_NOT_FOUND);
733
734 /*
735 * Now add attributes to allow creation of new vars
736 * and deletion of existing ones...
737 */
738
739 for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {
740 if (attr->show && attr->store)
741 error = subsys_create_file(&vars_subsys, attr);
742 }
743
744 /* Don't forget the systab entry */
745
746 for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {
747 if (attr->show)
748 error = subsys_create_file(&efi_subsys, attr);
749 }
750
751 if (error)
752 printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error);
753 else
754 goto out_free;
755
756 subsystem_unregister(&vars_subsys);
757
758out_firmware_unregister:
759 firmware_unregister(&efi_subsys);
760
761out_free:
762 kfree(variable_name);
763
764 return error;
765}
766
767static void __exit
768efivars_exit(void)
769{
770 struct list_head *pos, *n;
771
772 list_for_each_safe(pos, n, &efivar_list)
773 efivar_unregister(get_efivar_entry(pos));
774
775 subsystem_unregister(&vars_subsys);
776 firmware_unregister(&efi_subsys);
777}
778
779module_init(efivars_init);
780module_exit(efivars_exit);
781
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
new file mode 100644
index 000000000000..6d5df6c2efa2
--- /dev/null
+++ b/drivers/firmware/pcdp.c
@@ -0,0 +1,100 @@
1/*
2 * Parse the EFI PCDP table to locate the console device.
3 *
4 * (c) Copyright 2002, 2003, 2004 Hewlett-Packard Development Company, L.P.
5 * Khalid Aziz <khalid.aziz@hp.com>
6 * Alex Williamson <alex.williamson@hp.com>
7 * Bjorn Helgaas <bjorn.helgaas@hp.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/acpi.h>
15#include <linux/console.h>
16#include <linux/efi.h>
17#include <linux/serial.h>
18#include "pcdp.h"
19
20static int __init
21setup_serial_console(struct pcdp_uart *uart)
22{
23#ifdef CONFIG_SERIAL_8250_CONSOLE
24 int mmio;
25 static char options[64];
26
27 mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
28 snprintf(options, sizeof(options), "console=uart,%s,0x%lx,%lun%d",
29 mmio ? "mmio" : "io", uart->addr.address, uart->baud,
30 uart->bits ? uart->bits : 8);
31
32 return early_serial_console_init(options);
33#else
34 return -ENODEV;
35#endif
36}
37
38static int __init
39setup_vga_console(struct pcdp_vga *vga)
40{
41#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
42 if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
43 printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
44 return -ENODEV;
45 }
46
47 conswitchp = &vga_con;
48 printk(KERN_INFO "PCDP: VGA console\n");
49 return 0;
50#else
51 return -ENODEV;
52#endif
53}
54
55int __init
56efi_setup_pcdp_console(char *cmdline)
57{
58 struct pcdp *pcdp;
59 struct pcdp_uart *uart;
60 struct pcdp_device *dev, *end;
61 int i, serial = 0;
62
63 pcdp = efi.hcdp;
64 if (!pcdp)
65 return -ENODEV;
66
67 printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, __pa(pcdp));
68
69 if (strstr(cmdline, "console=hcdp")) {
70 if (pcdp->rev < 3)
71 serial = 1;
72 } else if (strstr(cmdline, "console=")) {
73 printk(KERN_INFO "Explicit \"console=\"; ignoring PCDP\n");
74 return -ENODEV;
75 }
76
77 if (pcdp->rev < 3 && efi_uart_console_only())
78 serial = 1;
79
80 for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
81 if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
82 if (uart->type == PCDP_CONSOLE_UART) {
83 return setup_serial_console(uart);
84 }
85 }
86 }
87
88 end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
89 for (dev = (struct pcdp_device *) (pcdp->uart + pcdp->num_uarts);
90 dev < end;
91 dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
92 if (dev->flags & PCDP_PRIMARY_CONSOLE) {
93 if (dev->type == PCDP_CONSOLE_VGA) {
94 return setup_vga_console((struct pcdp_vga *) dev);
95 }
96 }
97 }
98
99 return -ENODEV;
100}
diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h
new file mode 100644
index 000000000000..863bb6f768c3
--- /dev/null
+++ b/drivers/firmware/pcdp.h
@@ -0,0 +1,84 @@
1/*
2 * Definitions for PCDP-defined console devices
3 *
4 * v1.0a: http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf
5 * v2.0: http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf
6 *
7 * (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P.
8 * Khalid Aziz <khalid.aziz@hp.com>
9 * Bjorn Helgaas <bjorn.helgaas@hp.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#define PCDP_CONSOLE 0
17#define PCDP_DEBUG 1
18#define PCDP_CONSOLE_OUTPUT 2
19#define PCDP_CONSOLE_INPUT 3
20
21#define PCDP_UART (0 << 3)
22#define PCDP_VGA (1 << 3)
23#define PCDP_USB (2 << 3)
24
25/* pcdp_uart.type and pcdp_device.type */
26#define PCDP_CONSOLE_UART (PCDP_UART | PCDP_CONSOLE)
27#define PCDP_DEBUG_UART (PCDP_UART | PCDP_DEBUG)
28#define PCDP_CONSOLE_VGA (PCDP_VGA | PCDP_CONSOLE_OUTPUT)
29#define PCDP_CONSOLE_USB (PCDP_USB | PCDP_CONSOLE_INPUT)
30
31/* pcdp_uart.flags */
32#define PCDP_UART_EDGE_SENSITIVE (1 << 0)
33#define PCDP_UART_ACTIVE_LOW (1 << 1)
34#define PCDP_UART_PRIMARY_CONSOLE (1 << 2)
35#define PCDP_UART_IRQ (1 << 6) /* in pci_func for rev < 3 */
36#define PCDP_UART_PCI (1 << 7) /* in pci_func for rev < 3 */
37
38struct pcdp_uart {
39 u8 type;
40 u8 bits;
41 u8 parity;
42 u8 stop_bits;
43 u8 pci_seg;
44 u8 pci_bus;
45 u8 pci_dev;
46 u8 pci_func;
47 u64 baud;
48 struct acpi_generic_address addr;
49 u16 pci_dev_id;
50 u16 pci_vendor_id;
51 u32 gsi;
52 u32 clock_rate;
53 u8 pci_prog_intfc;
54 u8 flags;
55};
56
57struct pcdp_vga {
58 u8 count; /* address space descriptors */
59};
60
61/* pcdp_device.flags */
62#define PCDP_PRIMARY_CONSOLE 1
63
64struct pcdp_device {
65 u8 type;
66 u8 flags;
67 u16 length;
68 u16 efi_index;
69};
70
71struct pcdp {
72 u8 signature[4];
73 u32 length;
74 u8 rev; /* PCDP v2.0 is rev 3 */
75 u8 chksum;
76 u8 oemid[6];
77 u8 oem_tabid[8];
78 u32 oem_rev;
79 u8 creator_id[4];
80 u32 creator_rev;
81 u32 num_uarts;
82 struct pcdp_uart uart[0]; /* actual size is num_uarts */
83 /* remainder of table is pcdp_device structures */
84};