|
@@ -0,0 +1,156 @@
|
|
|
+/*
|
|
|
+ * linux/drivers/mmc/core/host.c
|
|
|
+ *
|
|
|
+ * Copyright (C) 2003 Russell King, All Rights Reserved.
|
|
|
+ * Copyright (C) 2007 Pierre Ossman
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ *
|
|
|
+ * MMC host class device management
|
|
|
+ */
|
|
|
+
|
|
|
+#include <linux/device.h>
|
|
|
+#include <linux/err.h>
|
|
|
+#include <linux/idr.h>
|
|
|
+#include <linux/pagemap.h>
|
|
|
+
|
|
|
+#include <linux/mmc/host.h>
|
|
|
+
|
|
|
+#include "core.h"
|
|
|
+#include "host.h"
|
|
|
+
|
|
|
+#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
|
|
|
+
|
|
|
+static void mmc_host_classdev_release(struct device *dev)
|
|
|
+{
|
|
|
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
|
|
+ kfree(host);
|
|
|
+}
|
|
|
+
|
|
|
+static struct class mmc_host_class = {
|
|
|
+ .name = "mmc_host",
|
|
|
+ .dev_release = mmc_host_classdev_release,
|
|
|
+};
|
|
|
+
|
|
|
+int mmc_register_host_class(void)
|
|
|
+{
|
|
|
+ return class_register(&mmc_host_class);
|
|
|
+}
|
|
|
+
|
|
|
+void mmc_unregister_host_class(void)
|
|
|
+{
|
|
|
+ class_unregister(&mmc_host_class);
|
|
|
+}
|
|
|
+
|
|
|
+static DEFINE_IDR(mmc_host_idr);
|
|
|
+static DEFINE_SPINLOCK(mmc_host_lock);
|
|
|
+
|
|
|
+/**
|
|
|
+ * mmc_alloc_host - initialise the per-host structure.
|
|
|
+ * @extra: sizeof private data structure
|
|
|
+ * @dev: pointer to host device model structure
|
|
|
+ *
|
|
|
+ * Initialise the per-host structure.
|
|
|
+ */
|
|
|
+struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
|
|
+{
|
|
|
+ struct mmc_host *host;
|
|
|
+
|
|
|
+ host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
|
|
|
+ if (!host)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ memset(host, 0, sizeof(struct mmc_host) + extra);
|
|
|
+
|
|
|
+ host->parent = dev;
|
|
|
+ host->class_dev.parent = dev;
|
|
|
+ host->class_dev.class = &mmc_host_class;
|
|
|
+ device_initialize(&host->class_dev);
|
|
|
+
|
|
|
+ spin_lock_init(&host->lock);
|
|
|
+ init_waitqueue_head(&host->wq);
|
|
|
+ INIT_DELAYED_WORK(&host->detect, mmc_rescan);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * By default, hosts do not support SGIO or large requests.
|
|
|
+ * They have to set these according to their abilities.
|
|
|
+ */
|
|
|
+ host->max_hw_segs = 1;
|
|
|
+ host->max_phys_segs = 1;
|
|
|
+ host->max_seg_size = PAGE_CACHE_SIZE;
|
|
|
+
|
|
|
+ host->max_req_size = PAGE_CACHE_SIZE;
|
|
|
+ host->max_blk_size = 512;
|
|
|
+ host->max_blk_count = PAGE_CACHE_SIZE / 512;
|
|
|
+
|
|
|
+ return host;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(mmc_alloc_host);
|
|
|
+
|
|
|
+/**
|
|
|
+ * mmc_add_host - initialise host hardware
|
|
|
+ * @host: mmc host
|
|
|
+ */
|
|
|
+int mmc_add_host(struct mmc_host *host)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ spin_lock(&mmc_host_lock);
|
|
|
+ err = idr_get_new(&mmc_host_idr, host, &host->index);
|
|
|
+ spin_unlock(&mmc_host_lock);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
|
|
|
+ "mmc%d", host->index);
|
|
|
+
|
|
|
+ err = device_add(&host->class_dev);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ mmc_start_host(host);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(mmc_add_host);
|
|
|
+
|
|
|
+/**
|
|
|
+ * mmc_remove_host - remove host hardware
|
|
|
+ * @host: mmc host
|
|
|
+ *
|
|
|
+ * Unregister and remove all cards associated with this host,
|
|
|
+ * and power down the MMC bus.
|
|
|
+ */
|
|
|
+void mmc_remove_host(struct mmc_host *host)
|
|
|
+{
|
|
|
+ mmc_stop_host(host);
|
|
|
+
|
|
|
+ device_del(&host->class_dev);
|
|
|
+
|
|
|
+ spin_lock(&mmc_host_lock);
|
|
|
+ idr_remove(&mmc_host_idr, host->index);
|
|
|
+ spin_unlock(&mmc_host_lock);
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(mmc_remove_host);
|
|
|
+
|
|
|
+/**
|
|
|
+ * mmc_free_host - free the host structure
|
|
|
+ * @host: mmc host
|
|
|
+ *
|
|
|
+ * Free the host once all references to it have been dropped.
|
|
|
+ */
|
|
|
+void mmc_free_host(struct mmc_host *host)
|
|
|
+{
|
|
|
+ put_device(&host->class_dev);
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(mmc_free_host);
|
|
|
+
|