linux-old/drivers/hotplug/acpiphp_core.c
<<
>>
Prefs
   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,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
   9 * Copyright (C) 2002,2003 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 *                  <t-kochi@bq.jp.nec.com>
  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/* local variables */
  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/* Inline functions to check the sanity of a pointer that is passed to us */
  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 * enable_slot - power on and enable a slot
 133 * @hotplug_slot: slot to enable
 134 *
 135 * Actual tasks are done in acpiphp_enable_slot()
 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        /* enable the specified slot */
 149        retval = acpiphp_enable_slot(slot->acpi_slot);
 150
 151        return retval;
 152}
 153
 154
 155/**
 156 * disable_slot - disable and power off a slot
 157 * @hotplug_slot: slot to disable
 158 *
 159 * Actual tasks are done in acpiphp_disable_slot()
 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        /* disable the specified slot */
 173        retval = acpiphp_disable_slot(slot->acpi_slot);
 174
 175        return retval;
 176}
 177
 178
 179/**
 180 * set_attention_status - set attention LED
 181 *
 182 * TBD:
 183 * ACPI doesn't have known method to manipulate
 184 * attention status LED.
 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                        /* FIXME turn light off */
 196                        hotplug_slot->info->attention_status = 0;
 197                        break;
 198
 199                case 1:
 200                default:
 201                        /* FIXME turn light on */
 202                        hotplug_slot->info->attention_status = 1;
 203                        break;
 204        }
 205
 206        return retval;
 207}
 208
 209
 210/**
 211 * hardware_test - hardware test
 212 *
 213 * We have nothing to do for now...
 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 * get_power_status - get power status of a slot
 235 * @hotplug_slot: slot to get status
 236 * @value: pointer to store status
 237 *
 238 * Some platforms may not implement _STA method properly.
 239 * In that case, the value returned may not be reliable.
 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 * get_attention_status - get attention LED status
 260 *
 261 * TBD:
 262 * ACPI doesn't provide any formal means to access attention LED status.
 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 * get_latch_status - get latch status of a slot
 279 * @hotplug_slot: slot to get status
 280 * @value: pointer to store status
 281 *
 282 * ACPI doesn't provide any formal means to access latch status.
 283 * Instead, we fake latch status from _STA
 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 * get_adapter_status - get adapter status of a slot
 304 * @hotplug_slot: slot to get status
 305 * @value: pointer to store status
 306 *
 307 * ACPI doesn't provide any formal means to access adapter status.
 308 * Instead, we fake adapter status from _STA
 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 * get_address - get pci address of a slot
 329 * @hotplug_slot: slot to get status
 330 * @busdev: pointer to struct pci_busdev (seg, bus, dev)
 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/* return dummy value because ACPI doesn't provide any method... */
 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/* return dummy value because ACPI doesn't provide any method... */
 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        /* initialize internal data structure etc. */
 382        retval = acpiphp_glue_init();
 383
 384        /* read initial number of slots */
 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 * make_slot_name - make a slot name that appears in pcihpfs
 397 * @slot: slot to name
 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 * init_slots - initialize 'struct slot' structures for each slot
 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                /* add slot to our internal list */
 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        /* read all the ACPI info from the system */
 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        /* deallocate internal data structures etc. */
 522        acpiphp_glue_exit();
 523}
 524
 525module_init(acpiphp_init);
 526module_exit(acpiphp_exit);
 527
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.