linux/drivers/mmc/core/host.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/mmc/core/host.c
   3 *
   4 *  Copyright (C) 2003 Russell King, All Rights Reserved.
   5 *  Copyright (C) 2007-2008 Pierre Ossman
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 *  MMC host class device management
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/err.h>
  16#include <linux/idr.h>
  17#include <linux/pagemap.h>
  18#include <linux/leds.h>
  19
  20#include <linux/mmc/host.h>
  21
  22#include "core.h"
  23#include "host.h"
  24
  25#define cls_dev_to_mmc_host(d)  container_of(d, struct mmc_host, class_dev)
  26
  27static void mmc_host_classdev_release(struct device *dev)
  28{
  29        struct mmc_host *host = cls_dev_to_mmc_host(dev);
  30        kfree(host);
  31}
  32
  33static struct class mmc_host_class = {
  34        .name           = "mmc_host",
  35        .dev_release    = mmc_host_classdev_release,
  36};
  37
  38int mmc_register_host_class(void)
  39{
  40        return class_register(&mmc_host_class);
  41}
  42
  43void mmc_unregister_host_class(void)
  44{
  45        class_unregister(&mmc_host_class);
  46}
  47
  48static DEFINE_IDR(mmc_host_idr);
  49static DEFINE_SPINLOCK(mmc_host_lock);
  50
  51/**
  52 *      mmc_alloc_host - initialise the per-host structure.
  53 *      @extra: sizeof private data structure
  54 *      @dev: pointer to host device model structure
  55 *
  56 *      Initialise the per-host structure.
  57 */
  58struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
  59{
  60        int err;
  61        struct mmc_host *host;
  62
  63        if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
  64                return NULL;
  65
  66        host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
  67        if (!host)
  68                return NULL;
  69
  70        spin_lock(&mmc_host_lock);
  71        err = idr_get_new(&mmc_host_idr, host, &host->index);
  72        spin_unlock(&mmc_host_lock);
  73        if (err)
  74                goto free;
  75
  76        dev_set_name(&host->class_dev, "mmc%d", host->index);
  77
  78        host->parent = dev;
  79        host->class_dev.parent = dev;
  80        host->class_dev.class = &mmc_host_class;
  81        device_initialize(&host->class_dev);
  82
  83        spin_lock_init(&host->lock);
  84        init_waitqueue_head(&host->wq);
  85        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
  86        INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
  87
  88        /*
  89         * By default, hosts do not support SGIO or large requests.
  90         * They have to set these according to their abilities.
  91         */
  92        host->max_hw_segs = 1;
  93        host->max_phys_segs = 1;
  94        host->max_seg_size = PAGE_CACHE_SIZE;
  95
  96        host->max_req_size = PAGE_CACHE_SIZE;
  97        host->max_blk_size = 512;
  98        host->max_blk_count = PAGE_CACHE_SIZE / 512;
  99
 100        return host;
 101
 102free:
 103        kfree(host);
 104        return NULL;
 105}
 106
 107EXPORT_SYMBOL(mmc_alloc_host);
 108
 109/**
 110 *      mmc_add_host - initialise host hardware
 111 *      @host: mmc host
 112 *
 113 *      Register the host with the driver model. The host must be
 114 *      prepared to start servicing requests before this function
 115 *      completes.
 116 */
 117int mmc_add_host(struct mmc_host *host)
 118{
 119        int err;
 120
 121        WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
 122                !host->ops->enable_sdio_irq);
 123
 124        led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
 125
 126        err = device_add(&host->class_dev);
 127        if (err)
 128                return err;
 129
 130#ifdef CONFIG_DEBUG_FS
 131        mmc_add_host_debugfs(host);
 132#endif
 133
 134        mmc_start_host(host);
 135
 136        return 0;
 137}
 138
 139EXPORT_SYMBOL(mmc_add_host);
 140
 141/**
 142 *      mmc_remove_host - remove host hardware
 143 *      @host: mmc host
 144 *
 145 *      Unregister and remove all cards associated with this host,
 146 *      and power down the MMC bus. No new requests will be issued
 147 *      after this function has returned.
 148 */
 149void mmc_remove_host(struct mmc_host *host)
 150{
 151        mmc_stop_host(host);
 152
 153#ifdef CONFIG_DEBUG_FS
 154        mmc_remove_host_debugfs(host);
 155#endif
 156
 157        device_del(&host->class_dev);
 158
 159        led_trigger_unregister_simple(host->led);
 160}
 161
 162EXPORT_SYMBOL(mmc_remove_host);
 163
 164/**
 165 *      mmc_free_host - free the host structure
 166 *      @host: mmc host
 167 *
 168 *      Free the host once all references to it have been dropped.
 169 */
 170void mmc_free_host(struct mmc_host *host)
 171{
 172        spin_lock(&mmc_host_lock);
 173        idr_remove(&mmc_host_idr, host->index);
 174        spin_unlock(&mmc_host_lock);
 175
 176        put_device(&host->class_dev);
 177}
 178
 179EXPORT_SYMBOL(mmc_free_host);
 180
 181