linux/drivers/firmware/edd.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/firmware/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 Parameters 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/edd/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 },   \
  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 = -EIO;
 119
 120        if (edd_attr->show)
 121                ret = edd_attr->show(dev, buf);
 122        return ret;
 123}
 124
 125static const 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                   !strncmp(info->params.host_bus_type, "XPRS", 4)) {
 156                p += scnprintf(p, left,
 157                             "\t%02x:%02x.%d  channel: %u\n",
 158                             info->params.interface_path.pci.bus,
 159                             info->params.interface_path.pci.slot,
 160                             info->params.interface_path.pci.function,
 161                             info->params.interface_path.pci.channel);
 162        } else if (!strncmp(info->params.host_bus_type, "IBND", 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 * @edev: target edd_device
 237 * @buf: output buffer
 238 *
 239 * Returns: number of bytes written, or -EINVAL on failure
 240 */
 241static ssize_t
 242edd_show_raw_data(struct edd_device *edev, char *buf)
 243{
 244        struct edd_info *info;
 245        ssize_t len = sizeof (info->params);
 246        if (!edev)
 247                return -EINVAL;
 248        info = edd_dev_get_info(edev);
 249        if (!info || !buf)
 250                return -EINVAL;
 251
 252        if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
 253                len = info->params.length;
 254
 255        /* In case of buggy BIOSs */
 256        if (len > (sizeof(info->params)))
 257                len = sizeof(info->params);
 258
 259        memcpy(buf, &info->params, len);
 260        return len;
 261}
 262
 263static ssize_t
 264edd_show_version(struct edd_device *edev, char *buf)
 265{
 266        struct edd_info *info;
 267        char *p = buf;
 268        if (!edev)
 269                return -EINVAL;
 270        info = edd_dev_get_info(edev);
 271        if (!info || !buf)
 272                return -EINVAL;
 273
 274        p += scnprintf(p, left, "0x%02x\n", info->version);
 275        return (p - buf);
 276}
 277
 278static ssize_t
 279edd_show_mbr_signature(struct edd_device *edev, char *buf)
 280{
 281        char *p = buf;
 282        p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature);
 283        return (p - buf);
 284}
 285
 286static ssize_t
 287edd_show_extensions(struct edd_device *edev, char *buf)
 288{
 289        struct edd_info *info;
 290        char *p = buf;
 291        if (!edev)
 292                return -EINVAL;
 293        info = edd_dev_get_info(edev);
 294        if (!info || !buf)
 295                return -EINVAL;
 296
 297        if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
 298                p += scnprintf(p, left, "Fixed disk access\n");
 299        }
 300        if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
 301                p += scnprintf(p, left, "Device locking and ejecting\n");
 302        }
 303        if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
 304                p += scnprintf(p, left, "Enhanced Disk Drive support\n");
 305        }
 306        if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
 307                p += scnprintf(p, left, "64-bit extensions\n");
 308        }
 309        return (p - buf);
 310}
 311
 312static ssize_t
 313edd_show_info_flags(struct edd_device *edev, char *buf)
 314{
 315        struct edd_info *info;
 316        char *p = buf;
 317        if (!edev)
 318                return -EINVAL;
 319        info = edd_dev_get_info(edev);
 320        if (!info || !buf)
 321                return -EINVAL;
 322
 323        if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
 324                p += scnprintf(p, left, "DMA boundary error transparent\n");
 325        if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
 326                p += scnprintf(p, left, "geometry valid\n");
 327        if (info->params.info_flags & EDD_INFO_REMOVABLE)
 328                p += scnprintf(p, left, "removable\n");
 329        if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
 330                p += scnprintf(p, left, "write verify\n");
 331        if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
 332                p += scnprintf(p, left, "media change notification\n");
 333        if (info->params.info_flags & EDD_INFO_LOCKABLE)
 334                p += scnprintf(p, left, "lockable\n");
 335        if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
 336                p += scnprintf(p, left, "no media present\n");
 337        if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
 338                p += scnprintf(p, left, "use int13 fn50\n");
 339        return (p - buf);
 340}
 341
 342static ssize_t
 343edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
 344{
 345        struct edd_info *info;
 346        char *p = buf;
 347        if (!edev)
 348                return -EINVAL;
 349        info = edd_dev_get_info(edev);
 350        if (!info || !buf)
 351                return -EINVAL;
 352
 353        p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
 354        return (p - buf);
 355}
 356
 357static ssize_t
 358edd_show_legacy_max_head(struct edd_device *edev, char *buf)
 359{
 360        struct edd_info *info;
 361        char *p = buf;
 362        if (!edev)
 363                return -EINVAL;
 364        info = edd_dev_get_info(edev);
 365        if (!info || !buf)
 366                return -EINVAL;
 367
 368        p += snprintf(p, left, "%u\n", info->legacy_max_head);
 369        return (p - buf);
 370}
 371
 372static ssize_t
 373edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
 374{
 375        struct edd_info *info;
 376        char *p = buf;
 377        if (!edev)
 378                return -EINVAL;
 379        info = edd_dev_get_info(edev);
 380        if (!info || !buf)
 381                return -EINVAL;
 382
 383        p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
 384        return (p - buf);
 385}
 386
 387static ssize_t
 388edd_show_default_cylinders(struct edd_device *edev, char *buf)
 389{
 390        struct edd_info *info;
 391        char *p = buf;
 392        if (!edev)
 393                return -EINVAL;
 394        info = edd_dev_get_info(edev);
 395        if (!info || !buf)
 396                return -EINVAL;
 397
 398        p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders);
 399        return (p - buf);
 400}
 401
 402static ssize_t
 403edd_show_default_heads(struct edd_device *edev, char *buf)
 404{
 405        struct edd_info *info;
 406        char *p = buf;
 407        if (!edev)
 408                return -EINVAL;
 409        info = edd_dev_get_info(edev);
 410        if (!info || !buf)
 411                return -EINVAL;
 412
 413        p += scnprintf(p, left, "%u\n", info->params.num_default_heads);
 414        return (p - buf);
 415}
 416
 417static ssize_t
 418edd_show_default_sectors_per_track(struct edd_device *edev, char *buf)
 419{
 420        struct edd_info *info;
 421        char *p = buf;
 422        if (!edev)
 423                return -EINVAL;
 424        info = edd_dev_get_info(edev);
 425        if (!info || !buf)
 426                return -EINVAL;
 427
 428        p += scnprintf(p, left, "%u\n", info->params.sectors_per_track);
 429        return (p - buf);
 430}
 431
 432static ssize_t
 433edd_show_sectors(struct edd_device *edev, char *buf)
 434{
 435        struct edd_info *info;
 436        char *p = buf;
 437        if (!edev)
 438                return -EINVAL;
 439        info = edd_dev_get_info(edev);
 440        if (!info || !buf)
 441                return -EINVAL;
 442
 443        p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors);
 444        return (p - buf);
 445}
 446
 447
 448/*
 449 * Some device instances may not have all the above attributes,
 450 * or the attribute values may be meaningless (i.e. if
 451 * the device is < EDD 3.0, it won't have host_bus and interface
 452 * information), so don't bother making files for them.  Likewise
 453 * if the default_{cylinders,heads,sectors_per_track} values
 454 * are zero, the BIOS doesn't provide sane values, don't bother
 455 * creating files for them either.
 456 */
 457
 458static int
 459edd_has_legacy_max_cylinder(struct edd_device *edev)
 460{
 461        struct edd_info *info;
 462        if (!edev)
 463                return 0;
 464        info = edd_dev_get_info(edev);
 465        if (!info)
 466                return 0;
 467        return info->legacy_max_cylinder > 0;
 468}
 469
 470static int
 471edd_has_legacy_max_head(struct edd_device *edev)
 472{
 473        struct edd_info *info;
 474        if (!edev)
 475                return 0;
 476        info = edd_dev_get_info(edev);
 477        if (!info)
 478                return 0;
 479        return info->legacy_max_head > 0;
 480}
 481
 482static int
 483edd_has_legacy_sectors_per_track(struct edd_device *edev)
 484{
 485        struct edd_info *info;
 486        if (!edev)
 487                return 0;
 488        info = edd_dev_get_info(edev);
 489        if (!info)
 490                return 0;
 491        return info->legacy_sectors_per_track > 0;
 492}
 493
 494static int
 495edd_has_default_cylinders(struct edd_device *edev)
 496{
 497        struct edd_info *info;
 498        if (!edev)
 499                return 0;
 500        info = edd_dev_get_info(edev);
 501        if (!info)
 502                return 0;
 503        return info->params.num_default_cylinders > 0;
 504}
 505
 506static int
 507edd_has_default_heads(struct edd_device *edev)
 508{
 509        struct edd_info *info;
 510        if (!edev)
 511                return 0;
 512        info = edd_dev_get_info(edev);
 513        if (!info)
 514                return 0;
 515        return info->params.num_default_heads > 0;
 516}
 517
 518static int
 519edd_has_default_sectors_per_track(struct edd_device *edev)
 520{
 521        struct edd_info *info;
 522        if (!edev)
 523                return 0;
 524        info = edd_dev_get_info(edev);
 525        if (!info)
 526                return 0;
 527        return info->params.sectors_per_track > 0;
 528}
 529
 530static int
 531edd_has_edd30(struct edd_device *edev)
 532{
 533        struct edd_info *info;
 534        int i;
 535        u8 csum = 0;
 536
 537        if (!edev)
 538                return 0;
 539        info = edd_dev_get_info(edev);
 540        if (!info)
 541                return 0;
 542
 543        if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
 544                return 0;
 545        }
 546
 547
 548        /* We support only T13 spec */
 549        if (info->params.device_path_info_length != 44)
 550                return 0;
 551
 552        for (i = 30; i < info->params.device_path_info_length + 30; i++)
 553                csum += *(((u8 *)&info->params) + i);
 554
 555        if (csum)
 556                return 0;
 557
 558        return 1;
 559}
 560
 561
 562static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, edd_has_edd_info);
 563static EDD_DEVICE_ATTR(version, 0444, edd_show_version, edd_has_edd_info);
 564static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, edd_has_edd_info);
 565static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, edd_has_edd_info);
 566static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, edd_has_edd_info);
 567static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444,
 568                       edd_show_legacy_max_cylinder,
 569                       edd_has_legacy_max_cylinder);
 570static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head,
 571                       edd_has_legacy_max_head);
 572static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444,
 573                       edd_show_legacy_sectors_per_track,
 574                       edd_has_legacy_sectors_per_track);
 575static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
 576                       edd_has_default_cylinders);
 577static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
 578                       edd_has_default_heads);
 579static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
 580                       edd_show_default_sectors_per_track,
 581                       edd_has_default_sectors_per_track);
 582static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
 583static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
 584static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature);
 585
 586
 587/* These are default attributes that are added for every edd
 588 * device discovered.  There are none.
 589 */
 590static struct attribute * def_attrs[] = {
 591        NULL,
 592};
 593
 594/* These attributes are conditional and only added for some devices. */
 595static struct edd_attribute * edd_attrs[] = {
 596        &edd_attr_raw_data,
 597        &edd_attr_version,
 598        &edd_attr_extensions,
 599        &edd_attr_info_flags,
 600        &edd_attr_sectors,
 601        &edd_attr_legacy_max_cylinder,
 602        &edd_attr_legacy_max_head,
 603        &edd_attr_legacy_sectors_per_track,
 604        &edd_attr_default_cylinders,
 605        &edd_attr_default_heads,
 606        &edd_attr_default_sectors_per_track,
 607        &edd_attr_interface,
 608        &edd_attr_host_bus,
 609        &edd_attr_mbr_signature,
 610        NULL,
 611};
 612
 613/**
 614 *      edd_release - free edd structure
 615 *      @kobj:  kobject of edd structure
 616 *
 617 *      This is called when the refcount of the edd structure
 618 *      reaches 0. This should happen right after we unregister,
 619 *      but just in case, we use the release callback anyway.
 620 */
 621
 622static void edd_release(struct kobject * kobj)
 623{
 624        struct edd_device * dev = to_edd_device(kobj);
 625        kfree(dev);
 626}
 627
 628static struct kobj_type edd_ktype = {
 629        .release        = edd_release,
 630        .sysfs_ops      = &edd_attr_ops,
 631        .default_attrs  = def_attrs,
 632};
 633
 634static struct kset *edd_kset;
 635
 636
 637/**
 638 * edd_dev_is_type() - is this EDD device a 'type' device?
 639 * @edev: target edd_device
 640 * @type: a host bus or interface identifier string per the EDD spec
 641 *
 642 * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
 643 */
 644static int
 645edd_dev_is_type(struct edd_device *edev, const char *type)
 646{
 647        struct edd_info *info;
 648        if (!edev)
 649                return 0;
 650        info = edd_dev_get_info(edev);
 651
 652        if (type && info) {
 653                if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
 654                    !strncmp(info->params.interface_type, type, strlen(type)))
 655                        return 1;
 656        }
 657        return 0;
 658}
 659
 660/**
 661 * edd_get_pci_dev() - finds pci_dev that matches edev
 662 * @edev: edd_device
 663 *
 664 * Returns pci_dev if found, or NULL
 665 */
 666static struct pci_dev *
 667edd_get_pci_dev(struct edd_device *edev)
 668{
 669        struct edd_info *info = edd_dev_get_info(edev);
 670
 671        if (edd_dev_is_type(edev, "PCI") || edd_dev_is_type(edev, "XPRS")) {
 672                return pci_get_bus_and_slot(info->params.interface_path.pci.bus,
 673                                     PCI_DEVFN(info->params.interface_path.pci.slot,
 674                                               info->params.interface_path.pci.
 675                                               function));
 676        }
 677        return NULL;
 678}
 679
 680static int
 681edd_create_symlink_to_pcidev(struct edd_device *edev)
 682{
 683
 684        struct pci_dev *pci_dev = edd_get_pci_dev(edev);
 685        int ret;
 686        if (!pci_dev)
 687                return 1;
 688        ret = sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
 689        pci_dev_put(pci_dev);
 690        return ret;
 691}
 692
 693static inline void
 694edd_device_unregister(struct edd_device *edev)
 695{
 696        kobject_put(&edev->kobj);
 697}
 698
 699static void edd_populate_dir(struct edd_device * edev)
 700{
 701        struct edd_attribute * attr;
 702        int error = 0;
 703        int i;
 704
 705        for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
 706                if (!attr->test ||
 707                    (attr->test && attr->test(edev)))
 708                        error = sysfs_create_file(&edev->kobj,&attr->attr);
 709        }
 710
 711        if (!error) {
 712                edd_create_symlink_to_pcidev(edev);
 713        }
 714}
 715
 716static int
 717edd_device_register(struct edd_device *edev, int i)
 718{
 719        int error;
 720
 721        if (!edev)
 722                return 1;
 723        edd_dev_set_info(edev, i);
 724        edev->kobj.kset = edd_kset;
 725        error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL,
 726                                     "int13_dev%02x", 0x80 + i);
 727        if (!error) {
 728                edd_populate_dir(edev);
 729                kobject_uevent(&edev->kobj, KOBJ_ADD);
 730        }
 731        return error;
 732}
 733
 734static inline int edd_num_devices(void)
 735{
 736        return max_t(unsigned char,
 737                     min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr),
 738                     min_t(unsigned char, EDDMAXNR, edd.edd_info_nr));
 739}
 740
 741/**
 742 * edd_init() - creates sysfs tree of EDD data
 743 */
 744static int __init
 745edd_init(void)
 746{
 747        int i;
 748        int rc=0;
 749        struct edd_device *edev;
 750
 751        printk(KERN_INFO "BIOS EDD facility v%s %s, %d devices found\n",
 752               EDD_VERSION, EDD_DATE, edd_num_devices());
 753
 754        if (!edd_num_devices()) {
 755                printk(KERN_INFO "EDD information not available.\n");
 756                return -ENODEV;
 757        }
 758
 759        edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
 760        if (!edd_kset)
 761                return -ENOMEM;
 762
 763        for (i = 0; i < edd_num_devices(); i++) {
 764                edev = kzalloc(sizeof (*edev), GFP_KERNEL);
 765                if (!edev) {
 766                        rc = -ENOMEM;
 767                        goto out;
 768                }
 769
 770                rc = edd_device_register(edev, i);
 771                if (rc) {
 772                        kfree(edev);
 773                        goto out;
 774                }
 775                edd_devices[i] = edev;
 776        }
 777
 778        return 0;
 779
 780out:
 781        while (--i >= 0)
 782                edd_device_unregister(edd_devices[i]);
 783        kset_unregister(edd_kset);
 784        return rc;
 785}
 786
 787static void __exit
 788edd_exit(void)
 789{
 790        int i;
 791        struct edd_device *edev;
 792
 793        for (i = 0; i < edd_num_devices(); i++) {
 794                if ((edev = edd_devices[i]))
 795                        edd_device_unregister(edev);
 796        }
 797        kset_unregister(edd_kset);
 798}
 799
 800late_initcall(edd_init);
 801module_exit(edd_exit);
 802
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.