Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
acpiphp_core.c
Go to the documentation of this file.
1 /*
2  * ACPI PCI Hot Plug Controller Driver
3  *
4  * Copyright (C) 1995,2001 Compaq Computer Corporation
5  * Copyright (C) 2001 Greg Kroah-Hartman ([email protected])
6  * Copyright (C) 2001 IBM Corp.
7  * Copyright (C) 2002 Hiroshi Aono ([email protected])
8  * Copyright (C) 2002,2003 Takayoshi Kochi ([email protected])
9  * Copyright (C) 2002,2003 NEC Corporation
10  * Copyright (C) 2003-2005 Matthew Wilcox ([email protected])
11  * Copyright (C) 2003-2005 Hewlett Packard
12  *
13  * All rights reserved.
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or (at
18  * your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
23  * NON INFRINGEMENT. See the GNU General Public License for more
24  * details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  *
30  * Send feedback to <[email protected]>
31  *
32  */
33 
34 #include <linux/init.h>
35 #include <linux/module.h>
36 #include <linux/moduleparam.h>
37 
38 #include <linux/kernel.h>
39 #include <linux/pci.h>
40 #include <linux/pci_hotplug.h>
41 #include <linux/slab.h>
42 #include <linux/smp.h>
43 #include "acpiphp.h"
44 
45 #define MY_NAME "acpiphp"
46 
47 /* name size which is used for entries in pcihpfs */
48 #define SLOT_NAME_SIZE 21 /* {_SUN} */
49 
51 
52 /* local variables */
53 static int num_slots;
54 static struct acpiphp_attention_info *attention_info;
55 
56 #define DRIVER_VERSION "0.5"
57 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[email protected]>, Takayoshi Kochi <[email protected]>, Matthew Wilcox <[email protected]>"
58 #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
59 
62 MODULE_LICENSE("GPL");
63 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
65 
66 /* export the attention callback registration methods */
69 
70 static int enable_slot (struct hotplug_slot *slot);
71 static int disable_slot (struct hotplug_slot *slot);
72 static int set_attention_status (struct hotplug_slot *slot, u8 value);
73 static int get_power_status (struct hotplug_slot *slot, u8 *value);
74 static int get_attention_status (struct hotplug_slot *slot, u8 *value);
75 static int get_latch_status (struct hotplug_slot *slot, u8 *value);
76 static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
77 
78 static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
79  .enable_slot = enable_slot,
80  .disable_slot = disable_slot,
81  .set_attention_status = set_attention_status,
82  .get_power_status = get_power_status,
83  .get_attention_status = get_attention_status,
84  .get_latch_status = get_latch_status,
85  .get_adapter_status = get_adapter_status,
86 };
87 
97 {
98  int retval = -EINVAL;
99 
100  if (info && info->owner && info->set_attn &&
101  info->get_attn && !attention_info) {
102  retval = 0;
103  attention_info = info;
104  }
105  return retval;
106 }
107 
108 
118 {
119  int retval = -EINVAL;
120 
121  if (info && attention_info == info) {
122  attention_info = NULL;
123  retval = 0;
124  }
125  return retval;
126 }
127 
128 
135 static int enable_slot(struct hotplug_slot *hotplug_slot)
136 {
137  struct slot *slot = hotplug_slot->private;
138 
139  dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
140 
141  /* enable the specified slot */
142  return acpiphp_enable_slot(slot->acpi_slot);
143 }
144 
145 
152 static int disable_slot(struct hotplug_slot *hotplug_slot)
153 {
154  struct slot *slot = hotplug_slot->private;
155  int retval;
156 
157  dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
158 
159  /* disable the specified slot */
160  retval = acpiphp_disable_slot(slot->acpi_slot);
161  if (!retval)
162  retval = acpiphp_eject_slot(slot->acpi_slot);
163  return retval;
164 }
165 
166 
176  static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
177  {
178  int retval = -ENODEV;
179 
180  dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
181 
182  if (attention_info && try_module_get(attention_info->owner)) {
183  retval = attention_info->set_attn(hotplug_slot, status);
184  module_put(attention_info->owner);
185  } else
186  attention_info = NULL;
187  return retval;
188  }
189 
190 
199 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
200 {
201  struct slot *slot = hotplug_slot->private;
202 
203  dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
204 
205  *value = acpiphp_get_power_status(slot->acpi_slot);
206 
207  return 0;
208 }
209 
210 
221 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
222 {
223  int retval = -EINVAL;
224 
225  dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
226 
227  if (attention_info && try_module_get(attention_info->owner)) {
228  retval = attention_info->get_attn(hotplug_slot, value);
229  module_put(attention_info->owner);
230  } else
231  attention_info = NULL;
232  return retval;
233 }
234 
235 
244 static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
245 {
246  struct slot *slot = hotplug_slot->private;
247 
248  dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
249 
250  *value = acpiphp_get_latch_status(slot->acpi_slot);
251 
252  return 0;
253 }
254 
255 
264 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
265 {
266  struct slot *slot = hotplug_slot->private;
267 
268  dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
269 
270  *value = acpiphp_get_adapter_status(slot->acpi_slot);
271 
272  return 0;
273 }
274 
275 static int __init init_acpi(void)
276 {
277  int retval;
278 
279  /* initialize internal data structure etc. */
280  retval = acpiphp_glue_init();
281 
282  /* read initial number of slots */
283  if (!retval) {
285  if (num_slots == 0) {
287  retval = -ENODEV;
288  }
289  }
290 
291  return retval;
292 }
293 
298 static void release_slot(struct hotplug_slot *hotplug_slot)
299 {
300  struct slot *slot = hotplug_slot->private;
301 
302  dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
303 
304  kfree(slot->hotplug_slot);
305  kfree(slot);
306 }
307 
308 /* callback routine to initialize 'struct slot' for each slot */
310 {
311  struct slot *slot;
312  int retval = -ENOMEM;
313  char name[SLOT_NAME_SIZE];
314 
315  slot = kzalloc(sizeof(*slot), GFP_KERNEL);
316  if (!slot)
317  goto error;
318 
319  slot->hotplug_slot = kzalloc(sizeof(*slot->hotplug_slot), GFP_KERNEL);
320  if (!slot->hotplug_slot)
321  goto error_slot;
322 
323  slot->hotplug_slot->info = &slot->info;
324 
325  slot->hotplug_slot->private = slot;
326  slot->hotplug_slot->release = &release_slot;
327  slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
328 
329  slot->acpi_slot = acpiphp_slot;
330  slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
331  slot->hotplug_slot->info->attention_status = 0;
332  slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
333  slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
334 
335  acpiphp_slot->slot = slot;
336  snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
337 
338  retval = pci_hp_register(slot->hotplug_slot,
339  acpiphp_slot->bridge->pci_bus,
340  acpiphp_slot->device,
341  name);
342  if (retval == -EBUSY)
343  goto error_hpslot;
344  if (retval) {
345  err("pci_hp_register failed with error %d\n", retval);
346  goto error_hpslot;
347  }
348 
349  info("Slot [%s] registered\n", slot_name(slot));
350 
351  return 0;
352 error_hpslot:
353  kfree(slot->hotplug_slot);
354 error_slot:
355  kfree(slot);
356 error:
357  return retval;
358 }
359 
360 
362 {
363  struct slot *slot = acpiphp_slot->slot;
364  int retval = 0;
365 
366  info("Slot [%s] unregistered\n", slot_name(slot));
367 
368  retval = pci_hp_deregister(slot->hotplug_slot);
369  if (retval)
370  err("pci_hp_deregister failed with error %d\n", retval);
371 }
372 
373 
374 static int __init acpiphp_init(void)
375 {
376  info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
377 
378  if (acpi_pci_disabled)
379  return 0;
380 
381  /* read all the ACPI info from the system */
382  return init_acpi();
383 }
384 
385 
386 static void __exit acpiphp_exit(void)
387 {
388  if (acpi_pci_disabled)
389  return;
390 
391  /* deallocate internal data structures etc. */
393 }
394 
395 module_init(acpiphp_init);
396 module_exit(acpiphp_exit);