xref: /linux/drivers/pci/hotplug/pci_hotplug_core.c (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
1 /*
2  * PCI HotPlug Controller Core
3  *
4  * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
5  * Copyright (C) 2001-2002 IBM Corp.
6  *
7  * All rights reserved.
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 as published by
11  * the Free Software Foundation; either version 2 of the License, or (at
12  * your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
17  * NON INFRINGEMENT.  See the GNU General Public License for more
18  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * Send feedback to <kristen.c.accardi@intel.com>
25  *
26  */
27 
28 #include <linux/module.h>
29 #include <linux/moduleparam.h>
30 #include <linux/kernel.h>
31 #include <linux/types.h>
32 #include <linux/list.h>
33 #include <linux/kobject.h>
34 #include <linux/sysfs.h>
35 #include <linux/pagemap.h>
36 #include <linux/slab.h>
37 #include <linux/smp_lock.h>
38 #include <linux/init.h>
39 #include <linux/mount.h>
40 #include <linux/namei.h>
41 #include <linux/pci.h>
42 #include <linux/pci_hotplug.h>
43 #include <asm/uaccess.h>
44 
45 #define MY_NAME	"pci_hotplug"
46 
47 #define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
48 #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
49 #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
50 #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
51 
52 
53 /* local variables */
54 static int debug;
55 
56 #define DRIVER_VERSION	"0.5"
57 #define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>"
58 #define DRIVER_DESC	"PCI Hot Plug PCI Core"
59 
60 
61 //////////////////////////////////////////////////////////////////
62 
63 static LIST_HEAD(pci_hotplug_slot_list);
64 
65 struct subsystem pci_hotplug_slots_subsys;
66 
67 static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
68 		struct attribute *attr, char *buf)
69 {
70 	struct hotplug_slot *slot = to_hotplug_slot(kobj);
71 	struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
72 	return attribute->show ? attribute->show(slot, buf) : -EIO;
73 }
74 
75 static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
76 		struct attribute *attr, const char *buf, size_t len)
77 {
78 	struct hotplug_slot *slot = to_hotplug_slot(kobj);
79 	struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
80 	return attribute->store ? attribute->store(slot, buf, len) : -EIO;
81 }
82 
83 static struct sysfs_ops hotplug_slot_sysfs_ops = {
84 	.show = hotplug_slot_attr_show,
85 	.store = hotplug_slot_attr_store,
86 };
87 
88 static void hotplug_slot_release(struct kobject *kobj)
89 {
90 	struct hotplug_slot *slot = to_hotplug_slot(kobj);
91 	if (slot->release)
92 		slot->release(slot);
93 }
94 
95 static struct kobj_type hotplug_slot_ktype = {
96 	.sysfs_ops = &hotplug_slot_sysfs_ops,
97 	.release = &hotplug_slot_release,
98 };
99 
100 decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
101 
102 /* these strings match up with the values in pci_bus_speed */
103 static char *pci_bus_speed_strings[] = {
104 	"33 MHz PCI",		/* 0x00 */
105 	"66 MHz PCI",		/* 0x01 */
106 	"66 MHz PCIX", 		/* 0x02 */
107 	"100 MHz PCIX",		/* 0x03 */
108 	"133 MHz PCIX",		/* 0x04 */
109 	NULL,			/* 0x05 */
110 	NULL,			/* 0x06 */
111 	NULL,			/* 0x07 */
112 	NULL,			/* 0x08 */
113 	"66 MHz PCIX 266",	/* 0x09 */
114 	"100 MHz PCIX 266",	/* 0x0a */
115 	"133 MHz PCIX 266",	/* 0x0b */
116 	NULL,			/* 0x0c */
117 	NULL,			/* 0x0d */
118 	NULL,			/* 0x0e */
119 	NULL,			/* 0x0f */
120 	NULL,			/* 0x10 */
121 	"66 MHz PCIX 533",	/* 0x11 */
122 	"100 MHz PCIX 533",	/* 0x12 */
123 	"133 MHz PCIX 533",	/* 0x13 */
124 	"25 GBps PCI-E",	/* 0x14 */
125 };
126 
127 #ifdef CONFIG_HOTPLUG_PCI_CPCI
128 extern int cpci_hotplug_init(int debug);
129 extern void cpci_hotplug_exit(void);
130 #else
131 static inline int cpci_hotplug_init(int debug) { return 0; }
132 static inline void cpci_hotplug_exit(void) { }
133 #endif
134 
135 /* Weee, fun with macros... */
136 #define GET_STATUS(name,type)	\
137 static int get_##name (struct hotplug_slot *slot, type *value)		\
138 {									\
139 	struct hotplug_slot_ops *ops = slot->ops;			\
140 	int retval = 0;							\
141 	if (try_module_get(ops->owner)) {				\
142 		if (ops->get_##name)					\
143 			retval = ops->get_##name (slot, value);		\
144 		else							\
145 			*value = slot->info->name;			\
146 		module_put(ops->owner);					\
147 	}								\
148 	return retval;							\
149 }
150 
151 GET_STATUS(power_status, u8)
152 GET_STATUS(attention_status, u8)
153 GET_STATUS(latch_status, u8)
154 GET_STATUS(adapter_status, u8)
155 GET_STATUS(address, u32)
156 GET_STATUS(max_bus_speed, enum pci_bus_speed)
157 GET_STATUS(cur_bus_speed, enum pci_bus_speed)
158 
159 static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
160 {
161 	int retval;
162 	u8 value;
163 
164 	retval = get_power_status (slot, &value);
165 	if (retval)
166 		goto exit;
167 	retval = sprintf (buf, "%d\n", value);
168 exit:
169 	return retval;
170 }
171 
172 static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
173 		size_t count)
174 {
175 	unsigned long lpower;
176 	u8 power;
177 	int retval = 0;
178 
179 	lpower = simple_strtoul (buf, NULL, 10);
180 	power = (u8)(lpower & 0xff);
181 	dbg ("power = %d\n", power);
182 
183 	if (!try_module_get(slot->ops->owner)) {
184 		retval = -ENODEV;
185 		goto exit;
186 	}
187 	switch (power) {
188 		case 0:
189 			if (slot->ops->disable_slot)
190 				retval = slot->ops->disable_slot(slot);
191 			break;
192 
193 		case 1:
194 			if (slot->ops->enable_slot)
195 				retval = slot->ops->enable_slot(slot);
196 			break;
197 
198 		default:
199 			err ("Illegal value specified for power\n");
200 			retval = -EINVAL;
201 	}
202 	module_put(slot->ops->owner);
203 
204 exit:
205 	if (retval)
206 		return retval;
207 	return count;
208 }
209 
210 static struct hotplug_slot_attribute hotplug_slot_attr_power = {
211 	.attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
212 	.show = power_read_file,
213 	.store = power_write_file
214 };
215 
216 static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
217 {
218 	int retval;
219 	u8 value;
220 
221 	retval = get_attention_status (slot, &value);
222 	if (retval)
223 		goto exit;
224 	retval = sprintf (buf, "%d\n", value);
225 
226 exit:
227 	return retval;
228 }
229 
230 static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
231 		size_t count)
232 {
233 	unsigned long lattention;
234 	u8 attention;
235 	int retval = 0;
236 
237 	lattention = simple_strtoul (buf, NULL, 10);
238 	attention = (u8)(lattention & 0xff);
239 	dbg (" - attention = %d\n", attention);
240 
241 	if (!try_module_get(slot->ops->owner)) {
242 		retval = -ENODEV;
243 		goto exit;
244 	}
245 	if (slot->ops->set_attention_status)
246 		retval = slot->ops->set_attention_status(slot, attention);
247 	module_put(slot->ops->owner);
248 
249 exit:
250 	if (retval)
251 		return retval;
252 	return count;
253 }
254 
255 static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
256 	.attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
257 	.show = attention_read_file,
258 	.store = attention_write_file
259 };
260 
261 static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
262 {
263 	int retval;
264 	u8 value;
265 
266 	retval = get_latch_status (slot, &value);
267 	if (retval)
268 		goto exit;
269 	retval = sprintf (buf, "%d\n", value);
270 
271 exit:
272 	return retval;
273 }
274 
275 static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
276 	.attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
277 	.show = latch_read_file,
278 };
279 
280 static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
281 {
282 	int retval;
283 	u8 value;
284 
285 	retval = get_adapter_status (slot, &value);
286 	if (retval)
287 		goto exit;
288 	retval = sprintf (buf, "%d\n", value);
289 
290 exit:
291 	return retval;
292 }
293 
294 static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
295 	.attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
296 	.show = presence_read_file,
297 };
298 
299 static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
300 {
301 	int retval;
302 	u32 address;
303 
304 	retval = get_address (slot, &address);
305 	if (retval)
306 		goto exit;
307 	retval = sprintf (buf, "%04x:%02x:%02x\n",
308 			  (address >> 16) & 0xffff,
309 			  (address >> 8) & 0xff,
310 			  address & 0xff);
311 
312 exit:
313 	return retval;
314 }
315 
316 static struct hotplug_slot_attribute hotplug_slot_attr_address = {
317 	.attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
318 	.show = address_read_file,
319 };
320 
321 static char *unknown_speed = "Unknown bus speed";
322 
323 static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
324 {
325 	char *speed_string;
326 	int retval;
327 	enum pci_bus_speed value;
328 
329 	retval = get_max_bus_speed (slot, &value);
330 	if (retval)
331 		goto exit;
332 
333 	if (value == PCI_SPEED_UNKNOWN)
334 		speed_string = unknown_speed;
335 	else
336 		speed_string = pci_bus_speed_strings[value];
337 
338 	retval = sprintf (buf, "%s\n", speed_string);
339 
340 exit:
341 	return retval;
342 }
343 
344 static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
345 	.attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
346 	.show = max_bus_speed_read_file,
347 };
348 
349 static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
350 {
351 	char *speed_string;
352 	int retval;
353 	enum pci_bus_speed value;
354 
355 	retval = get_cur_bus_speed (slot, &value);
356 	if (retval)
357 		goto exit;
358 
359 	if (value == PCI_SPEED_UNKNOWN)
360 		speed_string = unknown_speed;
361 	else
362 		speed_string = pci_bus_speed_strings[value];
363 
364 	retval = sprintf (buf, "%s\n", speed_string);
365 
366 exit:
367 	return retval;
368 }
369 
370 static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
371 	.attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
372 	.show = cur_bus_speed_read_file,
373 };
374 
375 static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
376 		size_t count)
377 {
378 	unsigned long ltest;
379 	u32 test;
380 	int retval = 0;
381 
382 	ltest = simple_strtoul (buf, NULL, 10);
383 	test = (u32)(ltest & 0xffffffff);
384 	dbg ("test = %d\n", test);
385 
386 	if (!try_module_get(slot->ops->owner)) {
387 		retval = -ENODEV;
388 		goto exit;
389 	}
390 	if (slot->ops->hardware_test)
391 		retval = slot->ops->hardware_test(slot, test);
392 	module_put(slot->ops->owner);
393 
394 exit:
395 	if (retval)
396 		return retval;
397 	return count;
398 }
399 
400 static struct hotplug_slot_attribute hotplug_slot_attr_test = {
401 	.attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
402 	.store = test_write_file
403 };
404 
405 static int has_power_file (struct hotplug_slot *slot)
406 {
407 	if ((!slot) || (!slot->ops))
408 		return -ENODEV;
409 	if ((slot->ops->enable_slot) ||
410 	    (slot->ops->disable_slot) ||
411 	    (slot->ops->get_power_status))
412 		return 0;
413 	return -ENOENT;
414 }
415 
416 static int has_attention_file (struct hotplug_slot *slot)
417 {
418 	if ((!slot) || (!slot->ops))
419 		return -ENODEV;
420 	if ((slot->ops->set_attention_status) ||
421 	    (slot->ops->get_attention_status))
422 		return 0;
423 	return -ENOENT;
424 }
425 
426 static int has_latch_file (struct hotplug_slot *slot)
427 {
428 	if ((!slot) || (!slot->ops))
429 		return -ENODEV;
430 	if (slot->ops->get_latch_status)
431 		return 0;
432 	return -ENOENT;
433 }
434 
435 static int has_adapter_file (struct hotplug_slot *slot)
436 {
437 	if ((!slot) || (!slot->ops))
438 		return -ENODEV;
439 	if (slot->ops->get_adapter_status)
440 		return 0;
441 	return -ENOENT;
442 }
443 
444 static int has_address_file (struct hotplug_slot *slot)
445 {
446 	if ((!slot) || (!slot->ops))
447 		return -ENODEV;
448 	if (slot->ops->get_address)
449 		return 0;
450 	return -ENOENT;
451 }
452 
453 static int has_max_bus_speed_file (struct hotplug_slot *slot)
454 {
455 	if ((!slot) || (!slot->ops))
456 		return -ENODEV;
457 	if (slot->ops->get_max_bus_speed)
458 		return 0;
459 	return -ENOENT;
460 }
461 
462 static int has_cur_bus_speed_file (struct hotplug_slot *slot)
463 {
464 	if ((!slot) || (!slot->ops))
465 		return -ENODEV;
466 	if (slot->ops->get_cur_bus_speed)
467 		return 0;
468 	return -ENOENT;
469 }
470 
471 static int has_test_file (struct hotplug_slot *slot)
472 {
473 	if ((!slot) || (!slot->ops))
474 		return -ENODEV;
475 	if (slot->ops->hardware_test)
476 		return 0;
477 	return -ENOENT;
478 }
479 
480 static int fs_add_slot (struct hotplug_slot *slot)
481 {
482 	int retval = 0;
483 
484 	if (has_power_file(slot) == 0) {
485 		retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
486 		if (retval)
487 			goto exit_power;
488 	}
489 
490 	if (has_attention_file(slot) == 0) {
491 		retval = sysfs_create_file(&slot->kobj,
492 					   &hotplug_slot_attr_attention.attr);
493 		if (retval)
494 			goto exit_attention;
495 	}
496 
497 	if (has_latch_file(slot) == 0) {
498 		retval = sysfs_create_file(&slot->kobj,
499 					   &hotplug_slot_attr_latch.attr);
500 		if (retval)
501 			goto exit_latch;
502 	}
503 
504 	if (has_adapter_file(slot) == 0) {
505 		retval = sysfs_create_file(&slot->kobj,
506 					   &hotplug_slot_attr_presence.attr);
507 		if (retval)
508 			goto exit_adapter;
509 	}
510 
511 	if (has_address_file(slot) == 0) {
512 		retval = sysfs_create_file(&slot->kobj,
513 					   &hotplug_slot_attr_address.attr);
514 		if (retval)
515 			goto exit_address;
516 	}
517 
518 	if (has_max_bus_speed_file(slot) == 0) {
519 		retval = sysfs_create_file(&slot->kobj,
520 					   &hotplug_slot_attr_max_bus_speed.attr);
521 		if (retval)
522 			goto exit_max_speed;
523 	}
524 
525 	if (has_cur_bus_speed_file(slot) == 0) {
526 		retval = sysfs_create_file(&slot->kobj,
527 					   &hotplug_slot_attr_cur_bus_speed.attr);
528 		if (retval)
529 			goto exit_cur_speed;
530 	}
531 
532 	if (has_test_file(slot) == 0) {
533 		retval = sysfs_create_file(&slot->kobj,
534 					   &hotplug_slot_attr_test.attr);
535 		if (retval)
536 			goto exit_test;
537 	}
538 
539 	goto exit;
540 
541 exit_test:
542 	if (has_cur_bus_speed_file(slot) == 0)
543 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
544 
545 exit_cur_speed:
546 	if (has_max_bus_speed_file(slot) == 0)
547 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
548 
549 exit_max_speed:
550 	if (has_address_file(slot) == 0)
551 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
552 
553 exit_address:
554 	if (has_adapter_file(slot) == 0)
555 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
556 
557 exit_adapter:
558 	if (has_latch_file(slot) == 0)
559 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
560 
561 exit_latch:
562 	if (has_attention_file(slot) == 0)
563 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
564 
565 exit_attention:
566 	if (has_power_file(slot) == 0)
567 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
568 exit_power:
569 exit:
570 	return retval;
571 }
572 
573 static void fs_remove_slot (struct hotplug_slot *slot)
574 {
575 	if (has_power_file(slot) == 0)
576 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
577 
578 	if (has_attention_file(slot) == 0)
579 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
580 
581 	if (has_latch_file(slot) == 0)
582 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
583 
584 	if (has_adapter_file(slot) == 0)
585 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
586 
587 	if (has_address_file(slot) == 0)
588 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
589 
590 	if (has_max_bus_speed_file(slot) == 0)
591 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
592 
593 	if (has_cur_bus_speed_file(slot) == 0)
594 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
595 
596 	if (has_test_file(slot) == 0)
597 		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
598 }
599 
600 static struct hotplug_slot *get_slot_from_name (const char *name)
601 {
602 	struct hotplug_slot *slot;
603 	struct list_head *tmp;
604 
605 	list_for_each (tmp, &pci_hotplug_slot_list) {
606 		slot = list_entry (tmp, struct hotplug_slot, slot_list);
607 		if (strcmp(slot->name, name) == 0)
608 			return slot;
609 	}
610 	return NULL;
611 }
612 
613 /**
614  * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
615  * @slot: pointer to the &struct hotplug_slot to register
616  *
617  * Registers a hotplug slot with the pci hotplug subsystem, which will allow
618  * userspace interaction to the slot.
619  *
620  * Returns 0 if successful, anything else for an error.
621  */
622 int pci_hp_register (struct hotplug_slot *slot)
623 {
624 	int result;
625 
626 	if (slot == NULL)
627 		return -ENODEV;
628 	if ((slot->info == NULL) || (slot->ops == NULL))
629 		return -EINVAL;
630 	if (slot->release == NULL) {
631 		dbg("Why are you trying to register a hotplug slot"
632 		    "without a proper release function?\n");
633 		return -EINVAL;
634 	}
635 
636 	kobject_set_name(&slot->kobj, "%s", slot->name);
637 	kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
638 
639 	/* this can fail if we have already registered a slot with the same name */
640 	if (kobject_register(&slot->kobj)) {
641 		err("Unable to register kobject");
642 		return -EINVAL;
643 	}
644 
645 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
646 
647 	result = fs_add_slot (slot);
648 	dbg ("Added slot %s to the list\n", slot->name);
649 	return result;
650 }
651 
652 /**
653  * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
654  * @slot: pointer to the &struct hotplug_slot to deregister
655  *
656  * The @slot must have been registered with the pci hotplug subsystem
657  * previously with a call to pci_hp_register().
658  *
659  * Returns 0 if successful, anything else for an error.
660  */
661 int pci_hp_deregister (struct hotplug_slot *slot)
662 {
663 	struct hotplug_slot *temp;
664 
665 	if (slot == NULL)
666 		return -ENODEV;
667 
668 	temp = get_slot_from_name (slot->name);
669 	if (temp != slot) {
670 		return -ENODEV;
671 	}
672 	list_del (&slot->slot_list);
673 
674 	fs_remove_slot (slot);
675 	dbg ("Removed slot %s from the list\n", slot->name);
676 	kobject_unregister(&slot->kobj);
677 	return 0;
678 }
679 
680 /**
681  * pci_hp_change_slot_info - changes the slot's information structure in the core
682  * @slot: pointer to the slot whose info has changed
683  * @info: pointer to the info copy into the slot's info structure
684  *
685  * @slot must have been registered with the pci
686  * hotplug subsystem previously with a call to pci_hp_register().
687  *
688  * Returns 0 if successful, anything else for an error.
689  */
690 int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
691 					 struct hotplug_slot_info *info)
692 {
693 	int retval;
694 
695 	if ((slot == NULL) || (info == NULL))
696 		return -ENODEV;
697 
698 	/*
699 	* check all fields in the info structure, and update timestamps
700 	* for the files referring to the fields that have now changed.
701 	*/
702 	if ((has_power_file(slot) == 0) &&
703 	    (slot->info->power_status != info->power_status)) {
704 		retval = sysfs_update_file(&slot->kobj,
705 					   &hotplug_slot_attr_power.attr);
706 		if (retval)
707 			return retval;
708 	}
709 
710 	if ((has_attention_file(slot) == 0) &&
711 	    (slot->info->attention_status != info->attention_status)) {
712 		retval = sysfs_update_file(&slot->kobj,
713 					   &hotplug_slot_attr_attention.attr);
714 		if (retval)
715 			return retval;
716 	}
717 
718 	if ((has_latch_file(slot) == 0) &&
719 	    (slot->info->latch_status != info->latch_status)) {
720 		retval = sysfs_update_file(&slot->kobj,
721 					   &hotplug_slot_attr_latch.attr);
722 		if (retval)
723 			return retval;
724 	}
725 
726 	if ((has_adapter_file(slot) == 0) &&
727 	    (slot->info->adapter_status != info->adapter_status)) {
728 		retval = sysfs_update_file(&slot->kobj,
729 					   &hotplug_slot_attr_presence.attr);
730 		if (retval)
731 			return retval;
732 	}
733 
734 	if ((has_address_file(slot) == 0) &&
735 	    (slot->info->address != info->address)) {
736 		retval = sysfs_update_file(&slot->kobj,
737 					   &hotplug_slot_attr_address.attr);
738 		if (retval)
739 			return retval;
740 	}
741 
742 	if ((has_max_bus_speed_file(slot) == 0) &&
743 	    (slot->info->max_bus_speed != info->max_bus_speed)) {
744 		retval = sysfs_update_file(&slot->kobj,
745 					   &hotplug_slot_attr_max_bus_speed.attr);
746 		if (retval)
747 			return retval;
748 	}
749 
750 	if ((has_cur_bus_speed_file(slot) == 0) &&
751 	    (slot->info->cur_bus_speed != info->cur_bus_speed)) {
752 		retval = sysfs_update_file(&slot->kobj,
753 					   &hotplug_slot_attr_cur_bus_speed.attr);
754 		if (retval)
755 			return retval;
756 	}
757 
758 	memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
759 
760 	return 0;
761 }
762 
763 static int __init pci_hotplug_init (void)
764 {
765 	int result;
766 
767 	kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
768 	result = subsystem_register(&pci_hotplug_slots_subsys);
769 	if (result) {
770 		err("Register subsys with error %d\n", result);
771 		goto exit;
772 	}
773 	result = cpci_hotplug_init(debug);
774 	if (result) {
775 		err ("cpci_hotplug_init with error %d\n", result);
776 		goto err_subsys;
777 	}
778 
779 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
780 	goto exit;
781 
782 err_subsys:
783 	subsystem_unregister(&pci_hotplug_slots_subsys);
784 exit:
785 	return result;
786 }
787 
788 static void __exit pci_hotplug_exit (void)
789 {
790 	cpci_hotplug_exit();
791 	subsystem_unregister(&pci_hotplug_slots_subsys);
792 }
793 
794 module_init(pci_hotplug_init);
795 module_exit(pci_hotplug_exit);
796 
797 MODULE_AUTHOR(DRIVER_AUTHOR);
798 MODULE_DESCRIPTION(DRIVER_DESC);
799 MODULE_LICENSE("GPL");
800 module_param(debug, bool, 0644);
801 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
802 
803 EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
804 EXPORT_SYMBOL_GPL(pci_hp_register);
805 EXPORT_SYMBOL_GPL(pci_hp_deregister);
806 EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
807