root/drivers/firmware/edd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. edd_has_mbr_signature
  2. edd_has_edd_info
  3. edd_dev_get_info
  4. edd_dev_set_info
  5. edd_attr_show
  6. edd_show_host_bus
  7. edd_show_interface
  8. edd_show_raw_data
  9. edd_show_version
  10. edd_show_mbr_signature
  11. edd_show_extensions
  12. edd_show_info_flags
  13. edd_show_legacy_max_cylinder
  14. edd_show_legacy_max_head
  15. edd_show_legacy_sectors_per_track
  16. edd_show_default_cylinders
  17. edd_show_default_heads
  18. edd_show_default_sectors_per_track
  19. edd_show_sectors
  20. edd_has_legacy_max_cylinder
  21. edd_has_legacy_max_head
  22. edd_has_legacy_sectors_per_track
  23. edd_has_default_cylinders
  24. edd_has_default_heads
  25. edd_has_default_sectors_per_track
  26. edd_has_edd30
  27. edd_release
  28. edd_dev_is_type
  29. edd_get_pci_dev
  30. edd_create_symlink_to_pcidev
  31. edd_device_unregister
  32. edd_populate_dir
  33. edd_device_register
  34. edd_num_devices
  35. edd_init
  36. edd_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/drivers/firmware/edd.c
   4  *  Copyright (C) 2002, 2003, 2004 Dell Inc.
   5  *  by Matt Domsch <Matt_Domsch@dell.com>
   6  *  disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
   7  *  legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
   8  *
   9  * BIOS Enhanced Disk Drive Services (EDD)
  10  * conformant to T13 Committee www.t13.org
  11  *   projects 1572D, 1484D, 1386D, 1226DT
  12  *
  13  * This code takes information provided by BIOS EDD calls
  14  * fn41 - Check Extensions Present and
  15  * fn48 - Get Device Parameters with EDD extensions
  16  * made in setup.S, copied to safe structures in setup.c,
  17  * and presents it in sysfs.
  18  *
  19  * Please see http://linux.dell.com/edd/results.html for
  20  * the list of BIOSs which have been reported to implement EDD.
  21  */
  22 
  23 #include <linux/module.h>
  24 #include <linux/string.h>
  25 #include <linux/types.h>
  26 #include <linux/init.h>
  27 #include <linux/stat.h>
  28 #include <linux/err.h>
  29 #include <linux/ctype.h>
  30 #include <linux/slab.h>
  31 #include <linux/limits.h>
  32 #include <linux/device.h>
  33 #include <linux/pci.h>
  34 #include <linux/blkdev.h>
  35 #include <linux/edd.h>
  36 
  37 #define EDD_VERSION "0.16"
  38 #define EDD_DATE    "2004-Jun-25"
  39 
  40 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
  41 MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
  42 MODULE_LICENSE("GPL");
  43 MODULE_VERSION(EDD_VERSION);
  44 
  45 #define left (PAGE_SIZE - (p - buf) - 1)
  46 
  47 struct edd_device {
  48         unsigned int index;
  49         unsigned int mbr_signature;
  50         struct edd_info *info;
  51         struct kobject kobj;
  52 };
  53 
  54 struct edd_attribute {
  55         struct attribute attr;
  56         ssize_t(*show) (struct edd_device * edev, char *buf);
  57         int (*test) (struct edd_device * edev);
  58 };
  59 
  60 /* forward declarations */
  61 static int edd_dev_is_type(struct edd_device *edev, const char *type);
  62 static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
  63 
  64 static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
  65 
  66 #define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
  67 struct edd_attribute edd_attr_##_name = {       \
  68         .attr = {.name = __stringify(_name), .mode = _mode },   \
  69         .show   = _show,                                \
  70         .test   = _test,                                \
  71 };
  72 
  73 static int
  74 edd_has_mbr_signature(struct edd_device *edev)
  75 {
  76         return edev->index < min_t(unsigned char, edd.mbr_signature_nr, EDD_MBR_SIG_MAX);
  77 }
  78 
  79 static int
  80 edd_has_edd_info(struct edd_device *edev)
  81 {
  82         return edev->index < min_t(unsigned char, edd.edd_info_nr, EDDMAXNR);
  83 }
  84 
  85 static inline struct edd_info *
  86 edd_dev_get_info(struct edd_device *edev)
  87 {
  88         return edev->info;
  89 }
  90 
  91 static inline void
  92 edd_dev_set_info(struct edd_device *edev, int i)
  93 {
  94         edev->index = i;
  95         if (edd_has_mbr_signature(edev))
  96                 edev->mbr_signature = edd.mbr_signature[i];
  97         if (edd_has_edd_info(edev))
  98                 edev->info = &edd.edd_info[i];
  99 }
 100 
 101 #define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
 102 #define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
 103 
 104 static ssize_t
 105 edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
 106 {
 107         struct edd_device *dev = to_edd_device(kobj);
 108         struct edd_attribute *edd_attr = to_edd_attr(attr);
 109         ssize_t ret = -EIO;
 110 
 111         if (edd_attr->show)
 112                 ret = edd_attr->show(dev, buf);
 113         return ret;
 114 }
 115 
 116 static const struct sysfs_ops edd_attr_ops = {
 117         .show = edd_attr_show,
 118 };
 119 
 120 static ssize_t
 121 edd_show_host_bus(struct edd_device *edev, char *buf)
 122 {
 123         struct edd_info *info;
 124         char *p = buf;
 125         int i;
 126 
 127         if (!edev)
 128                 return -EINVAL;
 129         info = edd_dev_get_info(edev);
 130         if (!info || !buf)
 131                 return -EINVAL;
 132 
 133         for (i = 0; i < 4; i++) {
 134                 if (isprint(info->params.host_bus_type[i])) {
 135                         p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
 136                 } else {
 137                         p += scnprintf(p, left, " ");
 138                 }
 139         }
 140 
 141         if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
 142                 p += scnprintf(p, left, "\tbase_address: %x\n",
 143                              info->params.interface_path.isa.base_address);
 144         } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
 145                    !strncmp(info->params.host_bus_type, "PCI", 3) ||
 146                    !strncmp(info->params.host_bus_type, "XPRS", 4)) {
 147                 p += scnprintf(p, left,
 148                              "\t%02x:%02x.%d  channel: %u\n",
 149                              info->params.interface_path.pci.bus,
 150                              info->params.interface_path.pci.slot,
 151                              info->params.interface_path.pci.function,
 152                              info->params.interface_path.pci.channel);
 153         } else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
 154                    !strncmp(info->params.host_bus_type, "HTPT", 4)) {
 155                 p += scnprintf(p, left,
 156                              "\tTBD: %llx\n",
 157                              info->params.interface_path.ibnd.reserved);
 158 
 159         } else {
 160                 p += scnprintf(p, left, "\tunknown: %llx\n",
 161                              info->params.interface_path.unknown.reserved);
 162         }
 163         return (p - buf);
 164 }
 165 
 166 static ssize_t
 167 edd_show_interface(struct edd_device *edev, char *buf)
 168 {
 169         struct edd_info *info;
 170         char *p = buf;
 171         int i;
 172 
 173         if (!edev)
 174                 return -EINVAL;
 175         info = edd_dev_get_info(edev);
 176         if (!info || !buf)
 177                 return -EINVAL;
 178 
 179         for (i = 0; i < 8; i++) {
 180                 if (isprint(info->params.interface_type[i])) {
 181                         p += scnprintf(p, left, "%c", info->params.interface_type[i]);
 182                 } else {
 183                         p += scnprintf(p, left, " ");
 184                 }
 185         }
 186         if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
 187                 p += scnprintf(p, left, "\tdevice: %u  lun: %u\n",
 188                              info->params.device_path.atapi.device,
 189                              info->params.device_path.atapi.lun);
 190         } else if (!strncmp(info->params.interface_type, "ATA", 3)) {
 191                 p += scnprintf(p, left, "\tdevice: %u\n",
 192                              info->params.device_path.ata.device);
 193         } else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
 194                 p += scnprintf(p, left, "\tid: %u  lun: %llu\n",
 195                              info->params.device_path.scsi.id,
 196                              info->params.device_path.scsi.lun);
 197         } else if (!strncmp(info->params.interface_type, "USB", 3)) {
 198                 p += scnprintf(p, left, "\tserial_number: %llx\n",
 199                              info->params.device_path.usb.serial_number);
 200         } else if (!strncmp(info->params.interface_type, "1394", 4)) {
 201                 p += scnprintf(p, left, "\teui: %llx\n",
 202                              info->params.device_path.i1394.eui);
 203         } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
 204                 p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
 205                              info->params.device_path.fibre.wwid,
 206                              info->params.device_path.fibre.lun);
 207         } else if (!strncmp(info->params.interface_type, "I2O", 3)) {
 208                 p += scnprintf(p, left, "\tidentity_tag: %llx\n",
 209                              info->params.device_path.i2o.identity_tag);
 210         } else if (!strncmp(info->params.interface_type, "RAID", 4)) {
 211                 p += scnprintf(p, left, "\tidentity_tag: %x\n",
 212                              info->params.device_path.raid.array_number);
 213         } else if (!strncmp(info->params.interface_type, "SATA", 4)) {
 214                 p += scnprintf(p, left, "\tdevice: %u\n",
 215                              info->params.device_path.sata.device);
 216         } else {
 217                 p += scnprintf(p, left, "\tunknown: %llx %llx\n",
 218                              info->params.device_path.unknown.reserved1,
 219                              info->params.device_path.unknown.reserved2);
 220         }
 221 
 222         return (p - buf);
 223 }
 224 
 225 /**
 226  * edd_show_raw_data() - copies raw data to buffer for userspace to parse
 227  * @edev: target edd_device
 228  * @buf: output buffer
 229  *
 230  * Returns: number of bytes written, or -EINVAL on failure
 231  */
 232 static ssize_t
 233 edd_show_raw_data(struct edd_device *edev, char *buf)
 234 {
 235         struct edd_info *info;
 236         ssize_t len = sizeof (info->params);
 237         if (!edev)
 238                 return -EINVAL;
 239         info = edd_dev_get_info(edev);
 240         if (!info || !buf)
 241                 return -EINVAL;
 242 
 243         if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
 244                 len = info->params.length;
 245 
 246         /* In case of buggy BIOSs */
 247         if (len > (sizeof(info->params)))
 248                 len = sizeof(info->params);
 249 
 250         memcpy(buf, &info->params, len);
 251         return len;
 252 }
 253 
 254 static ssize_t
 255 edd_show_version(struct edd_device *edev, char *buf)
 256 {
 257         struct edd_info *info;
 258         char *p = buf;
 259         if (!edev)
 260                 return -EINVAL;
 261         info = edd_dev_get_info(edev);
 262         if (!info || !buf)
 263                 return -EINVAL;
 264 
 265         p += scnprintf(p, left, "0x%02x\n", info->version);
 266         return (p - buf);
 267 }
 268 
 269 static ssize_t
 270 edd_show_mbr_signature(struct edd_device *edev, char *buf)
 271 {
 272         char *p = buf;
 273         p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature);
 274         return (p - buf);
 275 }
 276 
 277 static ssize_t
 278 edd_show_extensions(struct edd_device *edev, char *buf)
 279 {
 280         struct edd_info *info;
 281         char *p = buf;
 282         if (!edev)
 283                 return -EINVAL;
 284         info = edd_dev_get_info(edev);
 285         if (!info || !buf)
 286                 return -EINVAL;
 287 
 288         if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
 289                 p += scnprintf(p, left, "Fixed disk access\n");
 290         }
 291         if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
 292                 p += scnprintf(p, left, "Device locking and ejecting\n");
 293         }
 294         if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
 295                 p += scnprintf(p, left, "Enhanced Disk Drive support\n");
 296         }
 297         if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
 298                 p += scnprintf(p, left, "64-bit extensions\n");
 299         }
 300         return (p - buf);
 301 }
 302 
 303 static ssize_t
 304 edd_show_info_flags(struct edd_device *edev, char *buf)
 305 {
 306         struct edd_info *info;
 307         char *p = buf;
 308         if (!edev)
 309                 return -EINVAL;
 310         info = edd_dev_get_info(edev);
 311         if (!info || !buf)
 312                 return -EINVAL;
 313 
 314         if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
 315                 p += scnprintf(p, left, "DMA boundary error transparent\n");
 316         if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
 317                 p += scnprintf(p, left, "geometry valid\n");
 318         if (info->params.info_flags & EDD_INFO_REMOVABLE)
 319                 p += scnprintf(p, left, "removable\n");
 320         if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
 321                 p += scnprintf(p, left, "write verify\n");
 322         if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
 323                 p += scnprintf(p, left, "media change notification\n");
 324         if (info->params.info_flags & EDD_INFO_LOCKABLE)
 325                 p += scnprintf(p, left, "lockable\n");
 326         if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
 327                 p += scnprintf(p, left, "no media present\n");
 328         if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
 329                 p += scnprintf(p, left, "use int13 fn50\n");
 330         return (p - buf);
 331 }
 332 
 333 static ssize_t
 334 edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
 335 {
 336         struct edd_info *info;
 337         char *p = buf;
 338         if (!edev)
 339                 return -EINVAL;
 340         info = edd_dev_get_info(edev);
 341         if (!info || !buf)
 342                 return -EINVAL;
 343 
 344         p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
 345         return (p - buf);
 346 }
 347 
 348 static ssize_t
 349 edd_show_legacy_max_head(struct edd_device *edev, char *buf)
 350 {
 351         struct edd_info *info;
 352         char *p = buf;
 353         if (!edev)
 354                 return -EINVAL;
 355         info = edd_dev_get_info(edev);
 356         if (!info || !buf)
 357                 return -EINVAL;
 358 
 359         p += snprintf(p, left, "%u\n", info->legacy_max_head);
 360         return (p - buf);
 361 }
 362 
 363 static ssize_t
 364 edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
 365 {
 366         struct edd_info *info;
 367         char *p = buf;
 368         if (!edev)
 369                 return -EINVAL;
 370         info = edd_dev_get_info(edev);
 371         if (!info || !buf)
 372                 return -EINVAL;
 373 
 374         p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
 375         return (p - buf);
 376 }
 377 
 378 static ssize_t
 379 edd_show_default_cylinders(struct edd_device *edev, char *buf)
 380 {
 381         struct edd_info *info;
 382         char *p = buf;
 383         if (!edev)
 384                 return -EINVAL;
 385         info = edd_dev_get_info(edev);
 386         if (!info || !buf)
 387                 return -EINVAL;
 388 
 389         p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders);
 390         return (p - buf);
 391 }
 392 
 393 static ssize_t
 394 edd_show_default_heads(struct edd_device *edev, char *buf)
 395 {
 396         struct edd_info *info;
 397         char *p = buf;
 398         if (!edev)
 399                 return -EINVAL;
 400         info = edd_dev_get_info(edev);
 401         if (!info || !buf)
 402                 return -EINVAL;
 403 
 404         p += scnprintf(p, left, "%u\n", info->params.num_default_heads);
 405         return (p - buf);
 406 }
 407 
 408 static ssize_t
 409 edd_show_default_sectors_per_track(struct edd_device *edev, char *buf)
 410 {
 411         struct edd_info *info;
 412         char *p = buf;
 413         if (!edev)
 414                 return -EINVAL;
 415         info = edd_dev_get_info(edev);
 416         if (!info || !buf)
 417                 return -EINVAL;
 418 
 419         p += scnprintf(p, left, "%u\n", info->params.sectors_per_track);
 420         return (p - buf);
 421 }
 422 
 423 static ssize_t
 424 edd_show_sectors(struct edd_device *edev, char *buf)
 425 {
 426         struct edd_info *info;
 427         char *p = buf;
 428         if (!edev)
 429                 return -EINVAL;
 430         info = edd_dev_get_info(edev);
 431         if (!info || !buf)
 432                 return -EINVAL;
 433 
 434         p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors);
 435         return (p - buf);
 436 }
 437 
 438 
 439 /*
 440  * Some device instances may not have all the above attributes,
 441  * or the attribute values may be meaningless (i.e. if
 442  * the device is < EDD 3.0, it won't have host_bus and interface
 443  * information), so don't bother making files for them.  Likewise
 444  * if the default_{cylinders,heads,sectors_per_track} values
 445  * are zero, the BIOS doesn't provide sane values, don't bother
 446  * creating files for them either.
 447  */
 448 
 449 static int
 450 edd_has_legacy_max_cylinder(struct edd_device *edev)
 451 {
 452         struct edd_info *info;
 453         if (!edev)
 454                 return 0;
 455         info = edd_dev_get_info(edev);
 456         if (!info)
 457                 return 0;
 458         return info->legacy_max_cylinder > 0;
 459 }
 460 
 461 static int
 462 edd_has_legacy_max_head(struct edd_device *edev)
 463 {
 464         struct edd_info *info;
 465         if (!edev)
 466                 return 0;
 467         info = edd_dev_get_info(edev);
 468         if (!info)
 469                 return 0;
 470         return info->legacy_max_head > 0;
 471 }
 472 
 473 static int
 474 edd_has_legacy_sectors_per_track(struct edd_device *edev)
 475 {
 476         struct edd_info *info;
 477         if (!edev)
 478                 return 0;
 479         info = edd_dev_get_info(edev);
 480         if (!info)
 481                 return 0;
 482         return info->legacy_sectors_per_track > 0;
 483 }
 484 
 485 static int
 486 edd_has_default_cylinders(struct edd_device *edev)
 487 {
 488         struct edd_info *info;
 489         if (!edev)
 490                 return 0;
 491         info = edd_dev_get_info(edev);
 492         if (!info)
 493                 return 0;
 494         return info->params.num_default_cylinders > 0;
 495 }
 496 
 497 static int
 498 edd_has_default_heads(struct edd_device *edev)
 499 {
 500         struct edd_info *info;
 501         if (!edev)
 502                 return 0;
 503         info = edd_dev_get_info(edev);
 504         if (!info)
 505                 return 0;
 506         return info->params.num_default_heads > 0;
 507 }
 508 
 509 static int
 510 edd_has_default_sectors_per_track(struct edd_device *edev)
 511 {
 512         struct edd_info *info;
 513         if (!edev)
 514                 return 0;
 515         info = edd_dev_get_info(edev);
 516         if (!info)
 517                 return 0;
 518         return info->params.sectors_per_track > 0;
 519 }
 520 
 521 static int
 522 edd_has_edd30(struct edd_device *edev)
 523 {
 524         struct edd_info *info;
 525         int i;
 526         u8 csum = 0;
 527 
 528         if (!edev)
 529                 return 0;
 530         info = edd_dev_get_info(edev);
 531         if (!info)
 532                 return 0;
 533 
 534         if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
 535                 return 0;
 536         }
 537 
 538 
 539         /* We support only T13 spec */
 540         if (info->params.device_path_info_length != 44)
 541                 return 0;
 542 
 543         for (i = 30; i < info->params.device_path_info_length + 30; i++)
 544                 csum += *(((u8 *)&info->params) + i);
 545 
 546         if (csum)
 547                 return 0;
 548 
 549         return 1;
 550 }
 551 
 552 
 553 static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, edd_has_edd_info);
 554 static EDD_DEVICE_ATTR(version, 0444, edd_show_version, edd_has_edd_info);
 555 static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, edd_has_edd_info);
 556 static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, edd_has_edd_info);
 557 static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, edd_has_edd_info);
 558 static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444,
 559                        edd_show_legacy_max_cylinder,
 560                        edd_has_legacy_max_cylinder);
 561 static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head,
 562                        edd_has_legacy_max_head);
 563 static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444,
 564                        edd_show_legacy_sectors_per_track,
 565                        edd_has_legacy_sectors_per_track);
 566 static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
 567                        edd_has_default_cylinders);
 568 static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
 569                        edd_has_default_heads);
 570 static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
 571                        edd_show_default_sectors_per_track,
 572                        edd_has_default_sectors_per_track);
 573 static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
 574 static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
 575 static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature);
 576 
 577 
 578 /* These are default attributes that are added for every edd
 579  * device discovered.  There are none.
 580  */
 581 static struct attribute * def_attrs[] = {
 582         NULL,
 583 };
 584 
 585 /* These attributes are conditional and only added for some devices. */
 586 static struct edd_attribute * edd_attrs[] = {
 587         &edd_attr_raw_data,
 588         &edd_attr_version,
 589         &edd_attr_extensions,
 590         &edd_attr_info_flags,
 591         &edd_attr_sectors,
 592         &edd_attr_legacy_max_cylinder,
 593         &edd_attr_legacy_max_head,
 594         &edd_attr_legacy_sectors_per_track,
 595         &edd_attr_default_cylinders,
 596         &edd_attr_default_heads,
 597         &edd_attr_default_sectors_per_track,
 598         &edd_attr_interface,
 599         &edd_attr_host_bus,
 600         &edd_attr_mbr_signature,
 601         NULL,
 602 };
 603 
 604 /**
 605  *      edd_release - free edd structure
 606  *      @kobj:  kobject of edd structure
 607  *
 608  *      This is called when the refcount of the edd structure
 609  *      reaches 0. This should happen right after we unregister,
 610  *      but just in case, we use the release callback anyway.
 611  */
 612 
 613 static void edd_release(struct kobject * kobj)
 614 {
 615         struct edd_device * dev = to_edd_device(kobj);
 616         kfree(dev);
 617 }
 618 
 619 static struct kobj_type edd_ktype = {
 620         .release        = edd_release,
 621         .sysfs_ops      = &edd_attr_ops,
 622         .default_attrs  = def_attrs,
 623 };
 624 
 625 static struct kset *edd_kset;
 626 
 627 
 628 /**
 629  * edd_dev_is_type() - is this EDD device a 'type' device?
 630  * @edev: target edd_device
 631  * @type: a host bus or interface identifier string per the EDD spec
 632  *
 633  * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
 634  */
 635 static int
 636 edd_dev_is_type(struct edd_device *edev, const char *type)
 637 {
 638         struct edd_info *info;
 639         if (!edev)
 640                 return 0;
 641         info = edd_dev_get_info(edev);
 642 
 643         if (type && info) {
 644                 if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
 645                     !strncmp(info->params.interface_type, type, strlen(type)))
 646                         return 1;
 647         }
 648         return 0;
 649 }
 650 
 651 /**
 652  * edd_get_pci_dev() - finds pci_dev that matches edev
 653  * @edev: edd_device
 654  *
 655  * Returns pci_dev if found, or NULL
 656  */
 657 static struct pci_dev *
 658 edd_get_pci_dev(struct edd_device *edev)
 659 {
 660         struct edd_info *info = edd_dev_get_info(edev);
 661 
 662         if (edd_dev_is_type(edev, "PCI") || edd_dev_is_type(edev, "XPRS")) {
 663                 return pci_get_domain_bus_and_slot(0,
 664                                 info->params.interface_path.pci.bus,
 665                                 PCI_DEVFN(info->params.interface_path.pci.slot,
 666                                 info->params.interface_path.pci.function));
 667         }
 668         return NULL;
 669 }
 670 
 671 static int
 672 edd_create_symlink_to_pcidev(struct edd_device *edev)
 673 {
 674 
 675         struct pci_dev *pci_dev = edd_get_pci_dev(edev);
 676         int ret;
 677         if (!pci_dev)
 678                 return 1;
 679         ret = sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
 680         pci_dev_put(pci_dev);
 681         return ret;
 682 }
 683 
 684 static inline void
 685 edd_device_unregister(struct edd_device *edev)
 686 {
 687         kobject_put(&edev->kobj);
 688 }
 689 
 690 static void edd_populate_dir(struct edd_device * edev)
 691 {
 692         struct edd_attribute * attr;
 693         int error = 0;
 694         int i;
 695 
 696         for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
 697                 if (!attr->test ||
 698                     (attr->test && attr->test(edev)))
 699                         error = sysfs_create_file(&edev->kobj,&attr->attr);
 700         }
 701 
 702         if (!error) {
 703                 edd_create_symlink_to_pcidev(edev);
 704         }
 705 }
 706 
 707 static int
 708 edd_device_register(struct edd_device *edev, int i)
 709 {
 710         int error;
 711 
 712         if (!edev)
 713                 return 1;
 714         edd_dev_set_info(edev, i);
 715         edev->kobj.kset = edd_kset;
 716         error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL,
 717                                      "int13_dev%02x", 0x80 + i);
 718         if (!error) {
 719                 edd_populate_dir(edev);
 720                 kobject_uevent(&edev->kobj, KOBJ_ADD);
 721         }
 722         return error;
 723 }
 724 
 725 static inline int edd_num_devices(void)
 726 {
 727         return max_t(unsigned char,
 728                      min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr),
 729                      min_t(unsigned char, EDDMAXNR, edd.edd_info_nr));
 730 }
 731 
 732 /**
 733  * edd_init() - creates sysfs tree of EDD data
 734  */
 735 static int __init
 736 edd_init(void)
 737 {
 738         int i;
 739         int rc=0;
 740         struct edd_device *edev;
 741 
 742         if (!edd_num_devices())
 743                 return -ENODEV;
 744 
 745         printk(KERN_INFO "BIOS EDD facility v%s %s, %d devices found\n",
 746                EDD_VERSION, EDD_DATE, edd_num_devices());
 747 
 748         edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
 749         if (!edd_kset)
 750                 return -ENOMEM;
 751 
 752         for (i = 0; i < edd_num_devices(); i++) {
 753                 edev = kzalloc(sizeof (*edev), GFP_KERNEL);
 754                 if (!edev) {
 755                         rc = -ENOMEM;
 756                         goto out;
 757                 }
 758 
 759                 rc = edd_device_register(edev, i);
 760                 if (rc) {
 761                         kfree(edev);
 762                         goto out;
 763                 }
 764                 edd_devices[i] = edev;
 765         }
 766 
 767         return 0;
 768 
 769 out:
 770         while (--i >= 0)
 771                 edd_device_unregister(edd_devices[i]);
 772         kset_unregister(edd_kset);
 773         return rc;
 774 }
 775 
 776 static void __exit
 777 edd_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         kset_unregister(edd_kset);
 787 }
 788 
 789 late_initcall(edd_init);
 790 module_exit(edd_exit);

/* [<][>][^][v][top][bottom][index][help] */