1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/init.h>
34#include <linux/module.h>
35
36#include <linux/kernel.h>
37#include <linux/pci.h>
38#include <linux/slab.h>
39#include <linux/smp.h>
40#include <linux/smp_lock.h>
41#include "pci_hotplug.h"
42#include "acpiphp.h"
43
44static LIST_HEAD(slot_list);
45
46#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE)
47 #define MY_NAME "acpiphp"
48#else
49 #define MY_NAME THIS_MODULE->name
50#endif
51
52static int debug;
53int acpiphp_debug;
54
55
56static int num_slots;
57
58#define DRIVER_VERSION "0.4"
59#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
60#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
61
62MODULE_AUTHOR(DRIVER_AUTHOR);
63MODULE_DESCRIPTION(DRIVER_DESC);
64MODULE_LICENSE("GPL");
65MODULE_PARM(debug, "i");
66MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
67
68static int enable_slot (struct hotplug_slot *slot);
69static int disable_slot (struct hotplug_slot *slot);
70static int set_attention_status (struct hotplug_slot *slot, u8 value);
71static int hardware_test (struct hotplug_slot *slot, u32 value);
72static int get_power_status (struct hotplug_slot *slot, u8 *value);
73static int get_attention_status (struct hotplug_slot *slot, u8 *value);
74static int get_latch_status (struct hotplug_slot *slot, u8 *value);
75static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
76static int get_address (struct hotplug_slot *slot, u32 *value);
77static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
78static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
79
80static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
81 .owner = THIS_MODULE,
82 .enable_slot = enable_slot,
83 .disable_slot = disable_slot,
84 .set_attention_status = set_attention_status,
85 .hardware_test = hardware_test,
86 .get_power_status = get_power_status,
87 .get_attention_status = get_attention_status,
88 .get_latch_status = get_latch_status,
89 .get_adapter_status = get_adapter_status,
90 .get_address = get_address,
91 .get_max_bus_speed = get_max_bus_speed,
92 .get_cur_bus_speed = get_cur_bus_speed,
93};
94
95
96
97static inline int slot_paranoia_check (struct slot *slot, const char *function)
98{
99 if (!slot) {
100 dbg("%s - slot == NULL\n", function);
101 return -1;
102 }
103 if (slot->magic != SLOT_MAGIC) {
104 dbg("%s - bad magic number for slot\n", function);
105 return -1;
106 }
107 if (!slot->hotplug_slot) {
108 dbg("%s - slot->hotplug_slot == NULL!\n", function);
109 return -1;
110 }
111 return 0;
112}
113
114
115static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
116{
117 struct slot *slot;
118
119 if (!hotplug_slot) {
120 dbg("%s - hotplug_slot == NULL\n", function);
121 return NULL;
122 }
123
124 slot = (struct slot *)hotplug_slot->private;
125 if (slot_paranoia_check(slot, function))
126 return NULL;
127 return slot;
128}
129
130
131
132
133
134
135
136
137
138static int enable_slot (struct hotplug_slot *hotplug_slot)
139{
140 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
141 int retval = 0;
142
143 if (slot == NULL)
144 return -ENODEV;
145
146 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
147
148
149 retval = acpiphp_enable_slot(slot->acpi_slot);
150
151 return retval;
152}
153
154
155
156
157
158
159
160
161
162static int disable_slot (struct hotplug_slot *hotplug_slot)
163{
164 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
165 int retval = 0;
166
167 if (slot == NULL)
168 return -ENODEV;
169
170 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
171
172
173 retval = acpiphp_disable_slot(slot->acpi_slot);
174
175 return retval;
176}
177
178
179
180
181
182
183
184
185
186
187static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
188{
189 int retval = 0;
190
191 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
192
193 switch (status) {
194 case 0:
195
196 hotplug_slot->info->attention_status = 0;
197 break;
198
199 case 1:
200 default:
201
202 hotplug_slot->info->attention_status = 1;
203 break;
204 }
205
206 return retval;
207}
208
209
210
211
212
213
214
215
216static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
217{
218 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
219 int retval = 0;
220
221 if (slot == NULL)
222 return -ENODEV;
223
224 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
225
226 err("No hardware tests are defined for this driver\n");
227 retval = -ENODEV;
228
229 return retval;
230}
231
232
233
234
235
236
237
238
239
240
241
242static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
243{
244 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
245 int retval = 0;
246
247 if (slot == NULL)
248 return -ENODEV;
249
250 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
251
252 *value = acpiphp_get_power_status(slot->acpi_slot);
253
254 return retval;
255}
256
257
258
259
260
261
262
263
264
265static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
266{
267 int retval = 0;
268
269 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
270
271 *value = hotplug_slot->info->attention_status;
272
273 return retval;
274}
275
276
277
278
279
280
281
282
283
284
285
286static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
287{
288 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
289 int retval = 0;
290
291 if (slot == NULL)
292 return -ENODEV;
293
294 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
295
296 *value = acpiphp_get_latch_status(slot->acpi_slot);
297
298 return retval;
299}
300
301
302
303
304
305
306
307
308
309
310
311static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
312{
313 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
314 int retval = 0;
315
316 if (slot == NULL)
317 return -ENODEV;
318
319 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
320
321 *value = acpiphp_get_adapter_status(slot->acpi_slot);
322
323 return retval;
324}
325
326
327
328
329
330
331
332
333static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
334{
335 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
336 int retval = 0;
337
338 if (slot == NULL)
339 return -ENODEV;
340
341 dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
342
343 *value = acpiphp_get_address(slot->acpi_slot);
344
345 return retval;
346}
347
348
349
350static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
351{
352 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
353
354 if (slot == NULL)
355 return -ENODEV;
356
357 *value = PCI_SPEED_UNKNOWN;
358
359 return 0;
360}
361
362
363
364static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
365{
366 struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
367
368 if (slot == NULL)
369 return -ENODEV;
370
371 *value = PCI_SPEED_UNKNOWN;
372
373 return 0;
374}
375
376
377static int init_acpi (void)
378{
379 int retval;
380
381
382 retval = acpiphp_glue_init();
383
384
385 if (!retval) {
386 num_slots = acpiphp_get_num_slots();
387 if (num_slots == 0)
388 retval = -ENODEV;
389 }
390
391 return retval;
392}
393
394
395
396
397
398
399
400static void make_slot_name (struct slot *slot)
401{
402 snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u",
403 slot->acpi_slot->sun);
404}
405
406
407
408
409
410static int init_slots (void)
411{
412 struct slot *slot;
413 int retval = 0;
414 int i;
415
416 for (i = 0; i < num_slots; ++i) {
417 slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
418 if (!slot)
419 return -ENOMEM;
420 memset(slot, 0, sizeof(struct slot));
421
422 slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
423 if (!slot->hotplug_slot) {
424 kfree(slot);
425 return -ENOMEM;
426 }
427 memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
428
429 slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
430 if (!slot->hotplug_slot->info) {
431 kfree(slot->hotplug_slot);
432 kfree(slot);
433 return -ENOMEM;
434 }
435 memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
436
437 slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
438 if (!slot->hotplug_slot->name) {
439 kfree(slot->hotplug_slot->info);
440 kfree(slot->hotplug_slot);
441 kfree(slot);
442 return -ENOMEM;
443 }
444
445 slot->magic = SLOT_MAGIC;
446 slot->number = i;
447
448 slot->hotplug_slot->private = slot;
449 slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
450
451 slot->acpi_slot = get_slot_from_id(i);
452 slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
453 slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
454 slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
455 slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
456
457 make_slot_name(slot);
458
459 retval = pci_hp_register(slot->hotplug_slot);
460 if (retval) {
461 err("pci_hp_register failed with error %d\n", retval);
462 kfree(slot->hotplug_slot->info);
463 kfree(slot->hotplug_slot->name);
464 kfree(slot->hotplug_slot);
465 kfree(slot);
466 return retval;
467 }
468
469
470 list_add(&slot->slot_list, &slot_list);
471 info("Slot [%s] registered\n", slot->hotplug_slot->name);
472 }
473
474 return retval;
475}
476
477
478static void cleanup_slots (void)
479{
480 struct list_head *tmp, *n;
481 struct slot *slot;
482
483 list_for_each_safe (tmp, n, &slot_list) {
484 slot = list_entry(tmp, struct slot, slot_list);
485 list_del(&slot->slot_list);
486 pci_hp_deregister(slot->hotplug_slot);
487 kfree(slot->hotplug_slot->info);
488 kfree(slot->hotplug_slot->name);
489 kfree(slot->hotplug_slot);
490 kfree(slot);
491 }
492
493 return;
494}
495
496
497static int __init acpiphp_init(void)
498{
499 int retval;
500
501 info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
502
503 acpiphp_debug = debug;
504
505
506 retval = init_acpi();
507 if (retval)
508 return retval;
509
510 retval = init_slots();
511 if (retval)
512 return retval;
513
514 return 0;
515}
516
517
518static void __exit acpiphp_exit(void)
519{
520 cleanup_slots();
521
522 acpiphp_glue_exit();
523}
524
525module_init(acpiphp_init);
526module_exit(acpiphp_exit);
527