Commit b93931a6 authored by Pierre Ossman's avatar Pierre Ossman

mmc: refactor host class handling

Move basic host class device handling to its own file for clarity.
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 4101c16a
...@@ -7,6 +7,6 @@ ifeq ($(CONFIG_MMC_DEBUG),y) ...@@ -7,6 +7,6 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
endif endif
obj-$(CONFIG_MMC) += mmc_core.o obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o sysfs.o bus.o \ mmc_core-y := core.o sysfs.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o mmc.o mmc_ops.o sd.o sd_ops.o
...@@ -496,7 +496,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) ...@@ -496,7 +496,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
EXPORT_SYMBOL(mmc_detect_change); EXPORT_SYMBOL(mmc_detect_change);
static void mmc_rescan(struct work_struct *work) void mmc_rescan(struct work_struct *work)
{ {
struct mmc_host *host = struct mmc_host *host =
container_of(work, struct mmc_host, detect.work); container_of(work, struct mmc_host, detect.work);
...@@ -545,69 +545,13 @@ static void mmc_rescan(struct work_struct *work) ...@@ -545,69 +545,13 @@ static void mmc_rescan(struct work_struct *work)
} }
} }
void mmc_start_host(struct mmc_host *host)
/**
* 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 = mmc_alloc_host_sysfs(extra, dev);
if (host) {
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 ret; mmc_power_off(host);
mmc_detect_change(host, 0);
ret = mmc_add_host_sysfs(host);
if (ret == 0) {
mmc_power_off(host);
mmc_detect_change(host, 0);
}
return ret;
} }
EXPORT_SYMBOL(mmc_add_host); void mmc_stop_host(struct mmc_host *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)
{ {
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
unsigned long flags; unsigned long flags;
...@@ -632,24 +576,8 @@ void mmc_remove_host(struct mmc_host *host) ...@@ -632,24 +576,8 @@ void mmc_remove_host(struct mmc_host *host)
BUG_ON(host->card); BUG_ON(host->card);
mmc_power_off(host); mmc_power_off(host);
mmc_remove_host_sysfs(host);
} }
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)
{
mmc_free_host_sysfs(host);
}
EXPORT_SYMBOL(mmc_free_host);
#ifdef CONFIG_PM #ifdef CONFIG_PM
/** /**
......
...@@ -66,5 +66,9 @@ static inline void mmc_delay(unsigned int ms) ...@@ -66,5 +66,9 @@ static inline void mmc_delay(unsigned int ms)
} }
} }
void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
#endif #endif
/*
* 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);
/*
* linux/drivers/mmc/core/host.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 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.
*/
#ifndef _MMC_CORE_HOST_H
#define _MMC_CORE_HOST_H
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
#endif
...@@ -20,11 +20,9 @@ ...@@ -20,11 +20,9 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include "bus.h" #include "bus.h"
#include "host.h"
#include "sysfs.h" #include "sysfs.h"
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs) int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs)
{ {
int error = 0; int error = 0;
...@@ -50,82 +48,6 @@ void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs) ...@@ -50,82 +48,6 @@ void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs)
device_remove_file(&card->dev, &attrs[i]); device_remove_file(&card->dev, &attrs[i]);
} }
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,
};
static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
/*
* Internal function. Allocate a new MMC host.
*/
struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
{
struct mmc_host *host;
host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (host) {
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);
}
return host;
}
/*
* Internal function. Register a new MMC host with the MMC class.
*/
int mmc_add_host_sysfs(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);
return device_add(&host->class_dev);
}
/*
* Internal function. Unregister a MMC host with the MMC class.
*/
void mmc_remove_host_sysfs(struct mmc_host *host)
{
device_del(&host->class_dev);
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
spin_unlock(&mmc_host_lock);
}
/*
* Internal function. Free a MMC host.
*/
void mmc_free_host_sysfs(struct mmc_host *host)
{
put_device(&host->class_dev);
}
static struct workqueue_struct *workqueue; static struct workqueue_struct *workqueue;
/* /*
...@@ -154,7 +76,7 @@ static int __init mmc_init(void) ...@@ -154,7 +76,7 @@ static int __init mmc_init(void)
ret = mmc_register_bus(); ret = mmc_register_bus();
if (ret == 0) { if (ret == 0) {
ret = class_register(&mmc_host_class); ret = mmc_register_host_class();
if (ret) if (ret)
mmc_unregister_bus(); mmc_unregister_bus();
} }
...@@ -163,7 +85,7 @@ static int __init mmc_init(void) ...@@ -163,7 +85,7 @@ static int __init mmc_init(void)
static void __exit mmc_exit(void) static void __exit mmc_exit(void)
{ {
class_unregister(&mmc_host_class); mmc_unregister_host_class();
mmc_unregister_bus(); mmc_unregister_bus();
destroy_workqueue(workqueue); destroy_workqueue(workqueue);
} }
......
...@@ -23,11 +23,6 @@ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *a ...@@ -23,11 +23,6 @@ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *a
int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs); int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs);
void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs); void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs);
struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
int mmc_add_host_sysfs(struct mmc_host *host);
void mmc_remove_host_sysfs(struct mmc_host *host);
void mmc_free_host_sysfs(struct mmc_host *host);
int mmc_schedule_work(struct work_struct *work); int mmc_schedule_work(struct work_struct *work);
int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay);
void mmc_flush_scheduled_work(void); void mmc_flush_scheduled_work(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment