diff options
Diffstat (limited to 'drivers/misc/enclosure.c')
| -rw-r--r-- | drivers/misc/enclosure.c | 108 |
1 files changed, 96 insertions, 12 deletions
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 180a5442fd4b..38552a31304a 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c | |||
| @@ -145,8 +145,11 @@ enclosure_register(struct device *dev, const char *name, int components, | |||
| 145 | if (err) | 145 | if (err) |
| 146 | goto err; | 146 | goto err; |
| 147 | 147 | ||
| 148 | for (i = 0; i < components; i++) | 148 | for (i = 0; i < components; i++) { |
| 149 | edev->component[i].number = -1; | 149 | edev->component[i].number = -1; |
| 150 | edev->component[i].slot = -1; | ||
| 151 | edev->component[i].power_status = 1; | ||
| 152 | } | ||
| 150 | 153 | ||
| 151 | mutex_lock(&container_list_lock); | 154 | mutex_lock(&container_list_lock); |
| 152 | list_add_tail(&edev->node, &container_list); | 155 | list_add_tail(&edev->node, &container_list); |
| @@ -273,27 +276,26 @@ enclosure_component_find_by_name(struct enclosure_device *edev, | |||
| 273 | static const struct attribute_group *enclosure_component_groups[]; | 276 | static const struct attribute_group *enclosure_component_groups[]; |
| 274 | 277 | ||
| 275 | /** | 278 | /** |
| 276 | * enclosure_component_register - add a particular component to an enclosure | 279 | * enclosure_component_alloc - prepare a new enclosure component |
| 277 | * @edev: the enclosure to add the component | 280 | * @edev: the enclosure to add the component |
| 278 | * @num: the device number | 281 | * @num: the device number |
| 279 | * @type: the type of component being added | 282 | * @type: the type of component being added |
| 280 | * @name: an optional name to appear in sysfs (leave NULL if none) | 283 | * @name: an optional name to appear in sysfs (leave NULL if none) |
| 281 | * | 284 | * |
| 282 | * Registers the component. The name is optional for enclosures that | 285 | * The name is optional for enclosures that give their components a unique |
| 283 | * give their components a unique name. If not, leave the field NULL | 286 | * name. If not, leave the field NULL and a name will be assigned. |
| 284 | * and a name will be assigned. | ||
| 285 | * | 287 | * |
| 286 | * Returns a pointer to the enclosure component or an error. | 288 | * Returns a pointer to the enclosure component or an error. |
| 287 | */ | 289 | */ |
| 288 | struct enclosure_component * | 290 | struct enclosure_component * |
| 289 | enclosure_component_register(struct enclosure_device *edev, | 291 | enclosure_component_alloc(struct enclosure_device *edev, |
| 290 | unsigned int number, | 292 | unsigned int number, |
| 291 | enum enclosure_component_type type, | 293 | enum enclosure_component_type type, |
| 292 | const char *name) | 294 | const char *name) |
| 293 | { | 295 | { |
| 294 | struct enclosure_component *ecomp; | 296 | struct enclosure_component *ecomp; |
| 295 | struct device *cdev; | 297 | struct device *cdev; |
| 296 | int err, i; | 298 | int i; |
| 297 | char newname[COMPONENT_NAME_SIZE]; | 299 | char newname[COMPONENT_NAME_SIZE]; |
| 298 | 300 | ||
| 299 | if (number >= edev->components) | 301 | if (number >= edev->components) |
| @@ -327,14 +329,30 @@ enclosure_component_register(struct enclosure_device *edev, | |||
| 327 | cdev->release = enclosure_component_release; | 329 | cdev->release = enclosure_component_release; |
| 328 | cdev->groups = enclosure_component_groups; | 330 | cdev->groups = enclosure_component_groups; |
| 329 | 331 | ||
| 332 | return ecomp; | ||
| 333 | } | ||
| 334 | EXPORT_SYMBOL_GPL(enclosure_component_alloc); | ||
| 335 | |||
| 336 | /** | ||
| 337 | * enclosure_component_register - publishes an initialized enclosure component | ||
| 338 | * @ecomp: component to add | ||
| 339 | * | ||
| 340 | * Returns 0 on successful registration, releases the component otherwise | ||
| 341 | */ | ||
| 342 | int enclosure_component_register(struct enclosure_component *ecomp) | ||
| 343 | { | ||
| 344 | struct device *cdev; | ||
| 345 | int err; | ||
| 346 | |||
| 347 | cdev = &ecomp->cdev; | ||
| 330 | err = device_register(cdev); | 348 | err = device_register(cdev); |
| 331 | if (err) { | 349 | if (err) { |
| 332 | ecomp->number = -1; | 350 | ecomp->number = -1; |
| 333 | put_device(cdev); | 351 | put_device(cdev); |
| 334 | return ERR_PTR(err); | 352 | return err; |
| 335 | } | 353 | } |
| 336 | 354 | ||
| 337 | return ecomp; | 355 | return 0; |
| 338 | } | 356 | } |
| 339 | EXPORT_SYMBOL_GPL(enclosure_component_register); | 357 | EXPORT_SYMBOL_GPL(enclosure_component_register); |
| 340 | 358 | ||
| @@ -417,8 +435,21 @@ static ssize_t components_show(struct device *cdev, | |||
| 417 | } | 435 | } |
| 418 | static DEVICE_ATTR_RO(components); | 436 | static DEVICE_ATTR_RO(components); |
| 419 | 437 | ||
| 438 | static ssize_t id_show(struct device *cdev, | ||
| 439 | struct device_attribute *attr, | ||
| 440 | char *buf) | ||
| 441 | { | ||
| 442 | struct enclosure_device *edev = to_enclosure_device(cdev); | ||
| 443 | |||
| 444 | if (edev->cb->show_id) | ||
| 445 | return edev->cb->show_id(edev, buf); | ||
| 446 | return -EINVAL; | ||
| 447 | } | ||
| 448 | static DEVICE_ATTR_RO(id); | ||
| 449 | |||
| 420 | static struct attribute *enclosure_class_attrs[] = { | 450 | static struct attribute *enclosure_class_attrs[] = { |
| 421 | &dev_attr_components.attr, | 451 | &dev_attr_components.attr, |
| 452 | &dev_attr_id.attr, | ||
| 422 | NULL, | 453 | NULL, |
| 423 | }; | 454 | }; |
| 424 | ATTRIBUTE_GROUPS(enclosure_class); | 455 | ATTRIBUTE_GROUPS(enclosure_class); |
| @@ -553,6 +584,40 @@ static ssize_t set_component_locate(struct device *cdev, | |||
| 553 | return count; | 584 | return count; |
| 554 | } | 585 | } |
| 555 | 586 | ||
| 587 | static ssize_t get_component_power_status(struct device *cdev, | ||
| 588 | struct device_attribute *attr, | ||
| 589 | char *buf) | ||
| 590 | { | ||
| 591 | struct enclosure_device *edev = to_enclosure_device(cdev->parent); | ||
| 592 | struct enclosure_component *ecomp = to_enclosure_component(cdev); | ||
| 593 | |||
| 594 | if (edev->cb->get_power_status) | ||
| 595 | edev->cb->get_power_status(edev, ecomp); | ||
| 596 | return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off"); | ||
| 597 | } | ||
| 598 | |||
| 599 | static ssize_t set_component_power_status(struct device *cdev, | ||
| 600 | struct device_attribute *attr, | ||
| 601 | const char *buf, size_t count) | ||
| 602 | { | ||
| 603 | struct enclosure_device *edev = to_enclosure_device(cdev->parent); | ||
| 604 | struct enclosure_component *ecomp = to_enclosure_component(cdev); | ||
| 605 | int val; | ||
| 606 | |||
| 607 | if (strncmp(buf, "on", 2) == 0 && | ||
| 608 | (buf[2] == '\n' || buf[2] == '\0')) | ||
| 609 | val = 1; | ||
| 610 | else if (strncmp(buf, "off", 3) == 0 && | ||
| 611 | (buf[3] == '\n' || buf[3] == '\0')) | ||
| 612 | val = 0; | ||
| 613 | else | ||
| 614 | return -EINVAL; | ||
| 615 | |||
| 616 | if (edev->cb->set_power_status) | ||
| 617 | edev->cb->set_power_status(edev, ecomp, val); | ||
| 618 | return count; | ||
| 619 | } | ||
| 620 | |||
| 556 | static ssize_t get_component_type(struct device *cdev, | 621 | static ssize_t get_component_type(struct device *cdev, |
| 557 | struct device_attribute *attr, char *buf) | 622 | struct device_attribute *attr, char *buf) |
| 558 | { | 623 | { |
| @@ -561,6 +626,20 @@ static ssize_t get_component_type(struct device *cdev, | |||
| 561 | return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); | 626 | return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); |
| 562 | } | 627 | } |
| 563 | 628 | ||
| 629 | static ssize_t get_component_slot(struct device *cdev, | ||
| 630 | struct device_attribute *attr, char *buf) | ||
| 631 | { | ||
| 632 | struct enclosure_component *ecomp = to_enclosure_component(cdev); | ||
| 633 | int slot; | ||
| 634 | |||
| 635 | /* if the enclosure does not override then use 'number' as a stand-in */ | ||
| 636 | if (ecomp->slot >= 0) | ||
| 637 | slot = ecomp->slot; | ||
| 638 | else | ||
| 639 | slot = ecomp->number; | ||
| 640 | |||
| 641 | return snprintf(buf, 40, "%d\n", slot); | ||
| 642 | } | ||
| 564 | 643 | ||
| 565 | static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, | 644 | static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, |
| 566 | set_component_fault); | 645 | set_component_fault); |
| @@ -570,14 +649,19 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active, | |||
| 570 | set_component_active); | 649 | set_component_active); |
| 571 | static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, | 650 | static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, |
| 572 | set_component_locate); | 651 | set_component_locate); |
| 652 | static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status, | ||
| 653 | set_component_power_status); | ||
| 573 | static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL); | 654 | static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL); |
| 655 | static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL); | ||
| 574 | 656 | ||
| 575 | static struct attribute *enclosure_component_attrs[] = { | 657 | static struct attribute *enclosure_component_attrs[] = { |
| 576 | &dev_attr_fault.attr, | 658 | &dev_attr_fault.attr, |
| 577 | &dev_attr_status.attr, | 659 | &dev_attr_status.attr, |
| 578 | &dev_attr_active.attr, | 660 | &dev_attr_active.attr, |
| 579 | &dev_attr_locate.attr, | 661 | &dev_attr_locate.attr, |
| 662 | &dev_attr_power_status.attr, | ||
| 580 | &dev_attr_type.attr, | 663 | &dev_attr_type.attr, |
| 664 | &dev_attr_slot.attr, | ||
| 581 | NULL | 665 | NULL |
| 582 | }; | 666 | }; |
| 583 | ATTRIBUTE_GROUPS(enclosure_component); | 667 | ATTRIBUTE_GROUPS(enclosure_component); |
