acpiphp_core.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * ACPI PCI Hot Plug Controller Driver
  3.  *
  4.  * Copyright (c) 1995,2001 Compaq Computer Corporation
  5.  * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  6.  * Copyright (c) 2001 IBM Corp.
  7.  * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
  8.  * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
  9.  * Copyright (c) 2002 NEC Corporation
  10.  *
  11.  * All rights reserved.
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or (at
  16.  * your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful, but
  19.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  21.  * NON INFRINGEMENT.  See the GNU General Public License for more
  22.  * details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; if not, write to the Free Software
  26.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27.  *
  28.  * Send feedback to <gregkh@us.ibm.com>,
  29.  *                  <h-aono@ap.jp.nec.com>,
  30.  *     <t-kouchi@cq.jp.nec.com>
  31.  *
  32.  */
  33. #include <linux/config.h>
  34. #include <linux/kernel.h>
  35. #include <linux/module.h>
  36. #include <linux/pci.h>
  37. #include <linux/slab.h>
  38. #include <linux/smp.h>
  39. #include <linux/smp_lock.h>
  40. #include <linux/init.h>
  41. #include "pci_hotplug.h"
  42. #include "acpiphp.h"
  43. static LIST_HEAD(slot_list);
  44. #if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE)
  45. #define MY_NAME "acpiphp"
  46. #else
  47. #define MY_NAME THIS_MODULE->name
  48. #endif
  49. /* local variables */
  50. static int debug = 1; /* XXX set to 0 after debug */
  51. static int num_slots;
  52. #define DRIVER_VERSION "0.3"
  53. #define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>"
  54. #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
  55. MODULE_AUTHOR(DRIVER_AUTHOR);
  56. MODULE_DESCRIPTION(DRIVER_DESC);
  57. MODULE_LICENSE("GPL");
  58. MODULE_PARM(debug, "i");
  59. MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
  60. static int enable_slot (struct hotplug_slot *slot);
  61. static int disable_slot (struct hotplug_slot *slot);
  62. static int set_attention_status (struct hotplug_slot *slot, u8 value);
  63. static int hardware_test (struct hotplug_slot *slot, u32 value);
  64. static int get_power_status (struct hotplug_slot *slot, u8 *value);
  65. static int get_attention_status (struct hotplug_slot *slot, u8 *value);
  66. static int get_latch_status (struct hotplug_slot *slot, u8 *value);
  67. static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
  68. static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
  69. owner: THIS_MODULE,
  70. enable_slot: enable_slot,
  71. disable_slot: disable_slot,
  72. set_attention_status: set_attention_status,
  73. hardware_test: hardware_test,
  74. get_power_status: get_power_status,
  75. get_attention_status: get_attention_status,
  76. get_latch_status: get_latch_status,
  77. get_adapter_status: get_adapter_status,
  78. };
  79. /* Inline functions to check the sanity of a pointer that is passed to us */
  80. static inline int slot_paranoia_check (struct slot *slot, const char *function)
  81. {
  82. if (!slot) {
  83. dbg("%s - slot == NULL", function);
  84. return -1;
  85. }
  86. if (slot->magic != SLOT_MAGIC) {
  87. dbg("%s - bad magic number for slot", function);
  88. return -1;
  89. }
  90. if (!slot->hotplug_slot) {
  91. dbg("%s - slot->hotplug_slot == NULL!", function);
  92. return -1;
  93. }
  94. return 0;
  95. }
  96. static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
  97. struct slot *slot;
  98. if (!hotplug_slot) {
  99. dbg("%s - hotplug_slot == NULL", function);
  100. return NULL;
  101. }
  102. slot = (struct slot *)hotplug_slot->private;
  103. if (slot_paranoia_check (slot, function))
  104.                 return NULL;
  105. return slot;
  106. }
  107. /**
  108.  * enable_slot - power on and enable a slot
  109.  * @hotplug_slot: slot to enable
  110.  *
  111.  * Actual tasks are done in acpiphp_enable_slot()
  112.  *
  113.  */
  114. static int enable_slot (struct hotplug_slot *hotplug_slot)
  115. {
  116. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  117. int retval = 0;
  118. if (slot == NULL)
  119. return -ENODEV;
  120. dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  121. /* enable the specified slot */
  122. retval = acpiphp_enable_slot (slot->acpi_slot);
  123. return retval;
  124. }
  125. /**
  126.  * disable_slot - disable and power off a slot
  127.  * @hotplug_slot: slot to disable
  128.  *
  129.  * Actual tasks are done in acpiphp_disable_slot()
  130.  *
  131.  */
  132. static int disable_slot (struct hotplug_slot *hotplug_slot)
  133. {
  134. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  135. int retval = 0;
  136. if (slot == NULL)
  137. return -ENODEV;
  138. dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  139. /* disable the specified slot */
  140. retval = acpiphp_disable_slot (slot->acpi_slot);
  141. return retval;
  142. }
  143. /**
  144.  * set_attention_status - set attention LED
  145.  *
  146.  * TBD:
  147.  * ACPI doesn't have known method to manipulate
  148.  * attention status LED.
  149.  *
  150.  */
  151. static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
  152. {
  153. int retval = 0;
  154. dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  155. switch (status) {
  156. case 0:
  157. /* FIXME turn light off */
  158. hotplug_slot->info->attention_status = 0;
  159. break;
  160. case 1:
  161. default:
  162. /* FIXME turn light on */
  163. hotplug_slot->info->attention_status = 1;
  164. break;
  165. }
  166. return retval;
  167. }
  168. /**
  169.  * hardware_test - hardware test
  170.  *
  171.  * We have nothing to do for now...
  172.  *
  173.  */
  174. static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
  175. {
  176. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  177. int retval = 0;
  178. if (slot == NULL)
  179. return -ENODEV;
  180. dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  181. err ("No hardware tests are defined for this driver");
  182. retval = -ENODEV;
  183. return retval;
  184. }
  185. /**
  186.  * get_power_status - get power status of a slot
  187.  * @hotplug_slot: slot to get status
  188.  * @value: pointer to store status
  189.  *
  190.  * Some platforms may not implement _STA method properly.
  191.  * In that case, the value returned may not be reliable.
  192.  *
  193.  */
  194. static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
  195. {
  196. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  197. int retval = 0;
  198. if (slot == NULL)
  199. return -ENODEV;
  200. dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  201. *value = acpiphp_get_power_status (slot->acpi_slot);
  202. return retval;
  203. }
  204. /**
  205.  * get_attention_status - get attention LED status
  206.  *
  207.  * TBD:
  208.  * ACPI doesn't provide any formal means to access attention LED status.
  209.  *
  210.  */
  211. static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
  212. {
  213. int retval = 0;
  214. dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  215. *value = hotplug_slot->info->attention_status;
  216. return retval;
  217. }
  218. /**
  219.  * get_latch_status - get latch status of a slot
  220.  * @hotplug_slot: slot to get status
  221.  * @value: pointer to store status
  222.  *
  223.  * ACPI doesn't provide any formal means to access latch status.
  224.  * Instead, we fake latch status from _STA
  225.  *
  226.  */
  227. static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
  228. {
  229. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  230. int retval = 0;
  231. if (slot == NULL)
  232. return -ENODEV;
  233. dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  234. *value = acpiphp_get_latch_status (slot->acpi_slot);
  235. return retval;
  236. }
  237. /**
  238.  * get_adapter_status - get adapter status of a slot
  239.  * @hotplug_slot: slot to get status
  240.  * @value: pointer to store status
  241.  *
  242.  * ACPI doesn't provide any formal means to access adapter status.
  243.  * Instead, we fake adapter status from _STA
  244.  *
  245.  */
  246. static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
  247. {
  248. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  249. int retval = 0;
  250. if (slot == NULL)
  251. return -ENODEV;
  252. dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  253. *value = acpiphp_get_adapter_status (slot->acpi_slot);
  254. return retval;
  255. }
  256. static int init_acpi (void)
  257. {
  258. int retval;
  259. /* initialize internal data structure etc. */
  260. retval = acpiphp_glue_init();
  261. /* read initial number of slots */
  262. if (!retval) {
  263. num_slots = acpiphp_get_num_slots();
  264. if (num_slots == 0)
  265. retval = -ENODEV;
  266. }
  267. return retval;
  268. }
  269. static void exit_acpi (void)
  270. {
  271. /* deallocate internal data structures etc. */
  272. acpiphp_glue_exit();
  273. }
  274. /**
  275.  * make_slot_name - make a slot name that appears in pcihpfs
  276.  * @slot: slot to name
  277.  *
  278.  */
  279. static void make_slot_name (struct slot *slot)
  280. {
  281. snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%x", slot->acpi_slot->sun);
  282. }
  283. /**
  284.  * init_slots - initialize 'struct slot' structures for each slot
  285.  *
  286.  */
  287. static int init_slots (void)
  288. {
  289. struct slot *slot;
  290. int retval = 0;
  291. int i;
  292. for (i = 0; i < num_slots; ++i) {
  293. slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
  294. if (!slot)
  295. return -ENOMEM;
  296. memset(slot, 0, sizeof(struct slot));
  297. slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
  298. if (!slot->hotplug_slot) {
  299. kfree (slot);
  300. return -ENOMEM;
  301. }
  302. memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
  303. slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
  304. if (!slot->hotplug_slot->info) {
  305. kfree (slot->hotplug_slot);
  306. kfree (slot);
  307. return -ENOMEM;
  308. }
  309. memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
  310. slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
  311. if (!slot->hotplug_slot->name) {
  312. kfree (slot->hotplug_slot->info);
  313. kfree (slot->hotplug_slot);
  314. kfree (slot);
  315. return -ENOMEM;
  316. }
  317. slot->magic = SLOT_MAGIC;
  318. slot->number = i;
  319. slot->hotplug_slot->private = slot;
  320. slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
  321. slot->acpi_slot = get_slot_from_id (i);
  322. slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
  323. slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
  324. slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
  325. slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
  326. make_slot_name (slot);
  327. retval = pci_hp_register (slot->hotplug_slot);
  328. if (retval) {
  329. err ("pci_hp_register failed with error %d", retval);
  330. kfree (slot->hotplug_slot->info);
  331. kfree (slot->hotplug_slot->name);
  332. kfree (slot->hotplug_slot);
  333. kfree (slot);
  334. return retval;
  335. }
  336. /* add slot to our internal list */
  337. list_add (&slot->slot_list, &slot_list);
  338. }
  339. return retval;
  340. }
  341. static void cleanup_slots (void)
  342. {
  343. struct list_head *tmp;
  344. struct slot *slot;
  345. list_for_each (tmp, &slot_list) {
  346. slot = list_entry (tmp, struct slot, slot_list);
  347. list_del (&slot->slot_list);
  348. pci_hp_deregister (slot->hotplug_slot);
  349. kfree (slot->hotplug_slot->info);
  350. kfree (slot->hotplug_slot->name);
  351. kfree (slot->hotplug_slot);
  352. kfree (slot);
  353. }
  354. return;
  355. }
  356. static int __init acpiphp_init(void)
  357. {
  358. int retval;
  359. /* read all the ACPI info from the system */
  360. retval = init_acpi();
  361. if (retval)
  362. return retval;
  363. retval = init_slots();
  364. if (retval)
  365. return retval;
  366. info (DRIVER_DESC " version: " DRIVER_VERSION);
  367. return 0;
  368. }
  369. static void __exit acpiphp_exit(void)
  370. {
  371. cleanup_slots();
  372. exit_acpi();
  373. }
  374. module_init(acpiphp_init);
  375. module_exit(acpiphp_exit);