This source file includes following definitions.
- GET_STATUS
- power_write_file
- attention_read_file
- attention_write_file
- latch_read_file
- presence_read_file
- test_write_file
- has_power_file
- has_attention_file
- has_latch_file
- has_adapter_file
- has_test_file
- fs_add_slot
- fs_remove_slot
- get_slot_from_name
- __pci_hp_register
- __pci_hp_initialize
- pci_hp_add
- pci_hp_deregister
- pci_hp_del
- pci_hp_destroy
- pci_hotplug_init
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 #include <linux/module.h>       
  18 #include <linux/moduleparam.h>
  19 #include <linux/kernel.h>
  20 #include <linux/types.h>
  21 #include <linux/list.h>
  22 #include <linux/kobject.h>
  23 #include <linux/sysfs.h>
  24 #include <linux/pagemap.h>
  25 #include <linux/init.h>
  26 #include <linux/mount.h>
  27 #include <linux/namei.h>
  28 #include <linux/mutex.h>
  29 #include <linux/pci.h>
  30 #include <linux/pci_hotplug.h>
  31 #include <linux/uaccess.h>
  32 #include "../pci.h"
  33 #include "cpci_hotplug.h"
  34 
  35 #define MY_NAME "pci_hotplug"
  36 
  37 #define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt, MY_NAME, __func__, ## arg); } while (0)
  38 #define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME, ## arg)
  39 #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME, ## arg)
  40 #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME, ## arg)
  41 
  42 
  43 static bool debug;
  44 
  45 static LIST_HEAD(pci_hotplug_slot_list);
  46 static DEFINE_MUTEX(pci_hp_mutex);
  47 
  48 
  49 #define GET_STATUS(name, type)  \
  50 static int get_##name(struct hotplug_slot *slot, type *value)           \
  51 {                                                                       \
  52         const struct hotplug_slot_ops *ops = slot->ops;                 \
  53         int retval = 0;                                                 \
  54         if (!try_module_get(slot->owner))                               \
  55                 return -ENODEV;                                         \
  56         if (ops->get_##name)                                            \
  57                 retval = ops->get_##name(slot, value);                  \
  58         module_put(slot->owner);                                        \
  59         return retval;                                                  \
  60 }
  61 
  62 GET_STATUS(power_status, u8)
  63 GET_STATUS(attention_status, u8)
  64 GET_STATUS(latch_status, u8)
  65 GET_STATUS(adapter_status, u8)
  66 
  67 static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf)
  68 {
  69         int retval;
  70         u8 value;
  71 
  72         retval = get_power_status(pci_slot->hotplug, &value);
  73         if (retval)
  74                 return retval;
  75 
  76         return sprintf(buf, "%d\n", value);
  77 }
  78 
  79 static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
  80                                 size_t count)
  81 {
  82         struct hotplug_slot *slot = pci_slot->hotplug;
  83         unsigned long lpower;
  84         u8 power;
  85         int retval = 0;
  86 
  87         lpower = simple_strtoul(buf, NULL, 10);
  88         power = (u8)(lpower & 0xff);
  89         dbg("power = %d\n", power);
  90 
  91         if (!try_module_get(slot->owner)) {
  92                 retval = -ENODEV;
  93                 goto exit;
  94         }
  95         switch (power) {
  96         case 0:
  97                 if (slot->ops->disable_slot)
  98                         retval = slot->ops->disable_slot(slot);
  99                 break;
 100 
 101         case 1:
 102                 if (slot->ops->enable_slot)
 103                         retval = slot->ops->enable_slot(slot);
 104                 break;
 105 
 106         default:
 107                 err("Illegal value specified for power\n");
 108                 retval = -EINVAL;
 109         }
 110         module_put(slot->owner);
 111 
 112 exit:
 113         if (retval)
 114                 return retval;
 115         return count;
 116 }
 117 
 118 static struct pci_slot_attribute hotplug_slot_attr_power = {
 119         .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
 120         .show = power_read_file,
 121         .store = power_write_file
 122 };
 123 
 124 static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
 125 {
 126         int retval;
 127         u8 value;
 128 
 129         retval = get_attention_status(pci_slot->hotplug, &value);
 130         if (retval)
 131                 return retval;
 132 
 133         return sprintf(buf, "%d\n", value);
 134 }
 135 
 136 static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
 137                                     size_t count)
 138 {
 139         struct hotplug_slot *slot = pci_slot->hotplug;
 140         const struct hotplug_slot_ops *ops = slot->ops;
 141         unsigned long lattention;
 142         u8 attention;
 143         int retval = 0;
 144 
 145         lattention = simple_strtoul(buf, NULL, 10);
 146         attention = (u8)(lattention & 0xff);
 147         dbg(" - attention = %d\n", attention);
 148 
 149         if (!try_module_get(slot->owner)) {
 150                 retval = -ENODEV;
 151                 goto exit;
 152         }
 153         if (ops->set_attention_status)
 154                 retval = ops->set_attention_status(slot, attention);
 155         module_put(slot->owner);
 156 
 157 exit:
 158         if (retval)
 159                 return retval;
 160         return count;
 161 }
 162 
 163 static struct pci_slot_attribute hotplug_slot_attr_attention = {
 164         .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
 165         .show = attention_read_file,
 166         .store = attention_write_file
 167 };
 168 
 169 static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf)
 170 {
 171         int retval;
 172         u8 value;
 173 
 174         retval = get_latch_status(pci_slot->hotplug, &value);
 175         if (retval)
 176                 return retval;
 177 
 178         return sprintf(buf, "%d\n", value);
 179 }
 180 
 181 static struct pci_slot_attribute hotplug_slot_attr_latch = {
 182         .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
 183         .show = latch_read_file,
 184 };
 185 
 186 static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf)
 187 {
 188         int retval;
 189         u8 value;
 190 
 191         retval = get_adapter_status(pci_slot->hotplug, &value);
 192         if (retval)
 193                 return retval;
 194 
 195         return sprintf(buf, "%d\n", value);
 196 }
 197 
 198 static struct pci_slot_attribute hotplug_slot_attr_presence = {
 199         .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
 200         .show = presence_read_file,
 201 };
 202 
 203 static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
 204                                size_t count)
 205 {
 206         struct hotplug_slot *slot = pci_slot->hotplug;
 207         unsigned long ltest;
 208         u32 test;
 209         int retval = 0;
 210 
 211         ltest = simple_strtoul(buf, NULL, 10);
 212         test = (u32)(ltest & 0xffffffff);
 213         dbg("test = %d\n", test);
 214 
 215         if (!try_module_get(slot->owner)) {
 216                 retval = -ENODEV;
 217                 goto exit;
 218         }
 219         if (slot->ops->hardware_test)
 220                 retval = slot->ops->hardware_test(slot, test);
 221         module_put(slot->owner);
 222 
 223 exit:
 224         if (retval)
 225                 return retval;
 226         return count;
 227 }
 228 
 229 static struct pci_slot_attribute hotplug_slot_attr_test = {
 230         .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
 231         .store = test_write_file
 232 };
 233 
 234 static bool has_power_file(struct pci_slot *pci_slot)
 235 {
 236         struct hotplug_slot *slot = pci_slot->hotplug;
 237 
 238         if ((!slot) || (!slot->ops))
 239                 return false;
 240         if ((slot->ops->enable_slot) ||
 241             (slot->ops->disable_slot) ||
 242             (slot->ops->get_power_status))
 243                 return true;
 244         return false;
 245 }
 246 
 247 static bool has_attention_file(struct pci_slot *pci_slot)
 248 {
 249         struct hotplug_slot *slot = pci_slot->hotplug;
 250 
 251         if ((!slot) || (!slot->ops))
 252                 return false;
 253         if ((slot->ops->set_attention_status) ||
 254             (slot->ops->get_attention_status))
 255                 return true;
 256         return false;
 257 }
 258 
 259 static bool has_latch_file(struct pci_slot *pci_slot)
 260 {
 261         struct hotplug_slot *slot = pci_slot->hotplug;
 262 
 263         if ((!slot) || (!slot->ops))
 264                 return false;
 265         if (slot->ops->get_latch_status)
 266                 return true;
 267         return false;
 268 }
 269 
 270 static bool has_adapter_file(struct pci_slot *pci_slot)
 271 {
 272         struct hotplug_slot *slot = pci_slot->hotplug;
 273 
 274         if ((!slot) || (!slot->ops))
 275                 return false;
 276         if (slot->ops->get_adapter_status)
 277                 return true;
 278         return false;
 279 }
 280 
 281 static bool has_test_file(struct pci_slot *pci_slot)
 282 {
 283         struct hotplug_slot *slot = pci_slot->hotplug;
 284 
 285         if ((!slot) || (!slot->ops))
 286                 return false;
 287         if (slot->ops->hardware_test)
 288                 return true;
 289         return false;
 290 }
 291 
 292 static int fs_add_slot(struct pci_slot *pci_slot)
 293 {
 294         int retval = 0;
 295 
 296         
 297         pci_hp_create_module_link(pci_slot);
 298 
 299         if (has_power_file(pci_slot)) {
 300                 retval = sysfs_create_file(&pci_slot->kobj,
 301                                            &hotplug_slot_attr_power.attr);
 302                 if (retval)
 303                         goto exit_power;
 304         }
 305 
 306         if (has_attention_file(pci_slot)) {
 307                 retval = sysfs_create_file(&pci_slot->kobj,
 308                                            &hotplug_slot_attr_attention.attr);
 309                 if (retval)
 310                         goto exit_attention;
 311         }
 312 
 313         if (has_latch_file(pci_slot)) {
 314                 retval = sysfs_create_file(&pci_slot->kobj,
 315                                            &hotplug_slot_attr_latch.attr);
 316                 if (retval)
 317                         goto exit_latch;
 318         }
 319 
 320         if (has_adapter_file(pci_slot)) {
 321                 retval = sysfs_create_file(&pci_slot->kobj,
 322                                            &hotplug_slot_attr_presence.attr);
 323                 if (retval)
 324                         goto exit_adapter;
 325         }
 326 
 327         if (has_test_file(pci_slot)) {
 328                 retval = sysfs_create_file(&pci_slot->kobj,
 329                                            &hotplug_slot_attr_test.attr);
 330                 if (retval)
 331                         goto exit_test;
 332         }
 333 
 334         goto exit;
 335 
 336 exit_test:
 337         if (has_adapter_file(pci_slot))
 338                 sysfs_remove_file(&pci_slot->kobj,
 339                                   &hotplug_slot_attr_presence.attr);
 340 exit_adapter:
 341         if (has_latch_file(pci_slot))
 342                 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr);
 343 exit_latch:
 344         if (has_attention_file(pci_slot))
 345                 sysfs_remove_file(&pci_slot->kobj,
 346                                   &hotplug_slot_attr_attention.attr);
 347 exit_attention:
 348         if (has_power_file(pci_slot))
 349                 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr);
 350 exit_power:
 351         pci_hp_remove_module_link(pci_slot);
 352 exit:
 353         return retval;
 354 }
 355 
 356 static void fs_remove_slot(struct pci_slot *pci_slot)
 357 {
 358         if (has_power_file(pci_slot))
 359                 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr);
 360 
 361         if (has_attention_file(pci_slot))
 362                 sysfs_remove_file(&pci_slot->kobj,
 363                                   &hotplug_slot_attr_attention.attr);
 364 
 365         if (has_latch_file(pci_slot))
 366                 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr);
 367 
 368         if (has_adapter_file(pci_slot))
 369                 sysfs_remove_file(&pci_slot->kobj,
 370                                   &hotplug_slot_attr_presence.attr);
 371 
 372         if (has_test_file(pci_slot))
 373                 sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_test.attr);
 374 
 375         pci_hp_remove_module_link(pci_slot);
 376 }
 377 
 378 static struct hotplug_slot *get_slot_from_name(const char *name)
 379 {
 380         struct hotplug_slot *slot;
 381 
 382         list_for_each_entry(slot, &pci_hotplug_slot_list, slot_list) {
 383                 if (strcmp(hotplug_slot_name(slot), name) == 0)
 384                         return slot;
 385         }
 386         return NULL;
 387 }
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 
 396 
 397 
 398 
 399 
 400 
 401 
 402 
 403 
 404 int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus,
 405                       int devnr, const char *name,
 406                       struct module *owner, const char *mod_name)
 407 {
 408         int result;
 409 
 410         result = __pci_hp_initialize(slot, bus, devnr, name, owner, mod_name);
 411         if (result)
 412                 return result;
 413 
 414         result = pci_hp_add(slot);
 415         if (result)
 416                 pci_hp_destroy(slot);
 417 
 418         return result;
 419 }
 420 EXPORT_SYMBOL_GPL(__pci_hp_register);
 421 
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 
 432 
 433 
 434 
 435 
 436 
 437 
 438 int __pci_hp_initialize(struct hotplug_slot *slot, struct pci_bus *bus,
 439                         int devnr, const char *name, struct module *owner,
 440                         const char *mod_name)
 441 {
 442         struct pci_slot *pci_slot;
 443 
 444         if (slot == NULL)
 445                 return -ENODEV;
 446         if (slot->ops == NULL)
 447                 return -EINVAL;
 448 
 449         slot->owner = owner;
 450         slot->mod_name = mod_name;
 451 
 452         
 453 
 454 
 455 
 456 
 457         pci_slot = pci_create_slot(bus, devnr, name, slot);
 458         if (IS_ERR(pci_slot))
 459                 return PTR_ERR(pci_slot);
 460 
 461         slot->pci_slot = pci_slot;
 462         pci_slot->hotplug = slot;
 463         return 0;
 464 }
 465 EXPORT_SYMBOL_GPL(__pci_hp_initialize);
 466 
 467 
 468 
 469 
 470 
 471 
 472 
 473 
 474 
 475 
 476 
 477 int pci_hp_add(struct hotplug_slot *slot)
 478 {
 479         struct pci_slot *pci_slot = slot->pci_slot;
 480         int result;
 481 
 482         result = fs_add_slot(pci_slot);
 483         if (result)
 484                 return result;
 485 
 486         kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
 487         mutex_lock(&pci_hp_mutex);
 488         list_add(&slot->slot_list, &pci_hotplug_slot_list);
 489         mutex_unlock(&pci_hp_mutex);
 490         dbg("Added slot %s to the list\n", hotplug_slot_name(slot));
 491         return 0;
 492 }
 493 EXPORT_SYMBOL_GPL(pci_hp_add);
 494 
 495 
 496 
 497 
 498 
 499 
 500 
 501 
 502 
 503 
 504 void pci_hp_deregister(struct hotplug_slot *slot)
 505 {
 506         pci_hp_del(slot);
 507         pci_hp_destroy(slot);
 508 }
 509 EXPORT_SYMBOL_GPL(pci_hp_deregister);
 510 
 511 
 512 
 513 
 514 
 515 
 516 
 517 
 518 
 519 void pci_hp_del(struct hotplug_slot *slot)
 520 {
 521         struct hotplug_slot *temp;
 522 
 523         if (WARN_ON(!slot))
 524                 return;
 525 
 526         mutex_lock(&pci_hp_mutex);
 527         temp = get_slot_from_name(hotplug_slot_name(slot));
 528         if (WARN_ON(temp != slot)) {
 529                 mutex_unlock(&pci_hp_mutex);
 530                 return;
 531         }
 532 
 533         list_del(&slot->slot_list);
 534         mutex_unlock(&pci_hp_mutex);
 535         dbg("Removed slot %s from the list\n", hotplug_slot_name(slot));
 536         fs_remove_slot(slot->pci_slot);
 537 }
 538 EXPORT_SYMBOL_GPL(pci_hp_del);
 539 
 540 
 541 
 542 
 543 
 544 
 545 
 546 
 547 
 548 
 549 
 550 
 551 void pci_hp_destroy(struct hotplug_slot *slot)
 552 {
 553         struct pci_slot *pci_slot = slot->pci_slot;
 554 
 555         slot->pci_slot = NULL;
 556         pci_slot->hotplug = NULL;
 557         pci_destroy_slot(pci_slot);
 558 }
 559 EXPORT_SYMBOL_GPL(pci_hp_destroy);
 560 
 561 static int __init pci_hotplug_init(void)
 562 {
 563         int result;
 564 
 565         result = cpci_hotplug_init(debug);
 566         if (result) {
 567                 err("cpci_hotplug_init with error %d\n", result);
 568                 return result;
 569         }
 570 
 571         return result;
 572 }
 573 device_initcall(pci_hotplug_init);
 574 
 575 
 576 
 577 
 578 
 579 module_param(debug, bool, 0644);
 580 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");