mmc: refactor bus operations
Move bus operations to its own file for the sake of clarity. Also delegate sysfs attributes to bus handlers in preparation for other more exotic types. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
This commit is contained in:
parent
7de064ebc6
commit
4101c16a91
|
@ -7,5 +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 mmc.o mmc_ops.o sd.o sd_ops.o
|
mmc_core-y := core.o sysfs.o bus.o \
|
||||||
|
mmc.o mmc_ops.o sd.o sd_ops.o
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* linux/drivers/mmc/core/bus.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 card bus driver model
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
|
||||||
|
#include <linux/mmc/card.h>
|
||||||
|
#include <linux/mmc/host.h>
|
||||||
|
|
||||||
|
#include "sysfs.h"
|
||||||
|
#include "core.h"
|
||||||
|
#include "bus.h"
|
||||||
|
|
||||||
|
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
|
||||||
|
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
|
||||||
|
|
||||||
|
static ssize_t mmc_type_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
|
||||||
|
switch (card->type) {
|
||||||
|
case MMC_TYPE_MMC:
|
||||||
|
return sprintf(buf, "MMC\n");
|
||||||
|
case MMC_TYPE_SD:
|
||||||
|
return sprintf(buf, "SD\n");
|
||||||
|
default:
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_attribute mmc_dev_attrs[] = {
|
||||||
|
MMC_ATTR_RO(type),
|
||||||
|
__ATTR_NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This currently matches any MMC driver to any MMC card - drivers
|
||||||
|
* themselves make the decision whether to drive this card in their
|
||||||
|
* probe method.
|
||||||
|
*/
|
||||||
|
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
|
||||||
|
int buf_size)
|
||||||
|
{
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
int retval = 0, i = 0, length = 0;
|
||||||
|
|
||||||
|
#define add_env(fmt,val) do { \
|
||||||
|
retval = add_uevent_var(envp, num_envp, &i, \
|
||||||
|
buf, buf_size, &length, \
|
||||||
|
fmt, val); \
|
||||||
|
if (retval) \
|
||||||
|
return retval; \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
switch (card->type) {
|
||||||
|
case MMC_TYPE_MMC:
|
||||||
|
add_env("MMC_TYPE=%s", "MMC");
|
||||||
|
break;
|
||||||
|
case MMC_TYPE_SD:
|
||||||
|
add_env("MMC_TYPE=%s", "SD");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_env("MMC_NAME=%s", mmc_card_name(card));
|
||||||
|
|
||||||
|
#undef add_env
|
||||||
|
|
||||||
|
envp[i] = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmc_bus_probe(struct device *dev)
|
||||||
|
{
|
||||||
|
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
|
||||||
|
return drv->probe(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmc_bus_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
|
||||||
|
drv->remove(card);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmc_bus_suspend(struct device *dev, pm_message_t state)
|
||||||
|
{
|
||||||
|
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (dev->driver && drv->suspend)
|
||||||
|
ret = drv->suspend(card, state);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmc_bus_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (dev->driver && drv->resume)
|
||||||
|
ret = drv->resume(card);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bus_type mmc_bus_type = {
|
||||||
|
.name = "mmc",
|
||||||
|
.dev_attrs = mmc_dev_attrs,
|
||||||
|
.match = mmc_bus_match,
|
||||||
|
.uevent = mmc_bus_uevent,
|
||||||
|
.probe = mmc_bus_probe,
|
||||||
|
.remove = mmc_bus_remove,
|
||||||
|
.suspend = mmc_bus_suspend,
|
||||||
|
.resume = mmc_bus_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
int mmc_register_bus(void)
|
||||||
|
{
|
||||||
|
return bus_register(&mmc_bus_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmc_unregister_bus(void)
|
||||||
|
{
|
||||||
|
bus_unregister(&mmc_bus_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mmc_register_driver - register a media driver
|
||||||
|
* @drv: MMC media driver
|
||||||
|
*/
|
||||||
|
int mmc_register_driver(struct mmc_driver *drv)
|
||||||
|
{
|
||||||
|
drv->drv.bus = &mmc_bus_type;
|
||||||
|
return driver_register(&drv->drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(mmc_register_driver);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mmc_unregister_driver - unregister a media driver
|
||||||
|
* @drv: MMC media driver
|
||||||
|
*/
|
||||||
|
void mmc_unregister_driver(struct mmc_driver *drv)
|
||||||
|
{
|
||||||
|
drv->drv.bus = &mmc_bus_type;
|
||||||
|
driver_unregister(&drv->drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(mmc_unregister_driver);
|
||||||
|
|
||||||
|
static void mmc_release_card(struct device *dev)
|
||||||
|
{
|
||||||
|
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||||
|
|
||||||
|
kfree(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and initialise a new MMC card structure.
|
||||||
|
*/
|
||||||
|
struct mmc_card *mmc_alloc_card(struct mmc_host *host)
|
||||||
|
{
|
||||||
|
struct mmc_card *card;
|
||||||
|
|
||||||
|
card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
|
||||||
|
if (!card)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
memset(card, 0, sizeof(struct mmc_card));
|
||||||
|
|
||||||
|
card->host = host;
|
||||||
|
|
||||||
|
device_initialize(&card->dev);
|
||||||
|
|
||||||
|
card->dev.parent = mmc_classdev(host);
|
||||||
|
card->dev.bus = &mmc_bus_type;
|
||||||
|
card->dev.release = mmc_release_card;
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a new MMC card with the driver model.
|
||||||
|
*/
|
||||||
|
int mmc_add_card(struct mmc_card *card)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
|
||||||
|
"%s:%04x", mmc_hostname(card->host), card->rca);
|
||||||
|
|
||||||
|
card->dev.uevent_suppress = 1;
|
||||||
|
|
||||||
|
ret = device_add(&card->dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (card->host->bus_ops->sysfs_add) {
|
||||||
|
ret = card->host->bus_ops->sysfs_add(card->host, card);
|
||||||
|
if (ret) {
|
||||||
|
device_del(&card->dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
card->dev.uevent_suppress = 0;
|
||||||
|
|
||||||
|
kobject_uevent(&card->dev.kobj, KOBJ_ADD);
|
||||||
|
|
||||||
|
mmc_card_set_present(card);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unregister a new MMC card with the driver model, and
|
||||||
|
* (eventually) free it.
|
||||||
|
*/
|
||||||
|
void mmc_remove_card(struct mmc_card *card)
|
||||||
|
{
|
||||||
|
if (mmc_card_present(card)) {
|
||||||
|
if (card->host->bus_ops->sysfs_remove)
|
||||||
|
card->host->bus_ops->sysfs_remove(card->host, card);
|
||||||
|
device_del(&card->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
put_device(&card->dev);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* linux/drivers/mmc/core/bus.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_BUS_H
|
||||||
|
#define _MMC_CORE_BUS_H
|
||||||
|
|
||||||
|
struct mmc_card *mmc_alloc_card(struct mmc_host *host);
|
||||||
|
int mmc_add_card(struct mmc_card *card);
|
||||||
|
void mmc_remove_card(struct mmc_card *card);
|
||||||
|
|
||||||
|
int mmc_register_bus(void);
|
||||||
|
void mmc_unregister_bus(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -368,22 +368,6 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
|
||||||
mmc_set_ios(host);
|
mmc_set_ios(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a new MMC card
|
|
||||||
*/
|
|
||||||
struct mmc_card *mmc_alloc_card(struct mmc_host *host)
|
|
||||||
{
|
|
||||||
struct mmc_card *card;
|
|
||||||
|
|
||||||
card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
|
|
||||||
if (!card)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
mmc_init_card(card, host);
|
|
||||||
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply power to the MMC stack. This is a two-stage process.
|
* Apply power to the MMC stack. This is a two-stage process.
|
||||||
* First, we enable power to the card without the clock running.
|
* First, we enable power to the card without the clock running.
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
struct mmc_bus_ops {
|
struct mmc_bus_ops {
|
||||||
void (*remove)(struct mmc_host *);
|
void (*remove)(struct mmc_host *);
|
||||||
void (*detect)(struct mmc_host *);
|
void (*detect)(struct mmc_host *);
|
||||||
|
int (*sysfs_add)(struct mmc_host *, struct mmc_card *card);
|
||||||
|
void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card);
|
||||||
void (*suspend)(struct mmc_host *);
|
void (*suspend)(struct mmc_host *);
|
||||||
void (*resume)(struct mmc_host *);
|
void (*resume)(struct mmc_host *);
|
||||||
};
|
};
|
||||||
|
@ -54,8 +56,6 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||||
|
|
||||||
struct mmc_card *mmc_alloc_card(struct mmc_host *host);
|
|
||||||
|
|
||||||
static inline void mmc_delay(unsigned int ms)
|
static inline void mmc_delay(unsigned int ms)
|
||||||
{
|
{
|
||||||
if (ms < 1000 / HZ) {
|
if (ms < 1000 / HZ) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "sysfs.h"
|
#include "sysfs.h"
|
||||||
|
#include "bus.h"
|
||||||
#include "mmc_ops.h"
|
#include "mmc_ops.h"
|
||||||
|
|
||||||
static const unsigned int tran_exp[] = {
|
static const unsigned int tran_exp[] = {
|
||||||
|
@ -413,8 +414,7 @@ static void mmc_detect(struct mmc_host *host)
|
||||||
mmc_release_host(host);
|
mmc_release_host(host);
|
||||||
|
|
||||||
if (err != MMC_ERR_NONE) {
|
if (err != MMC_ERR_NONE) {
|
||||||
mmc_remove_card(host->card);
|
mmc_remove(host);
|
||||||
host->card = NULL;
|
|
||||||
|
|
||||||
mmc_claim_host(host);
|
mmc_claim_host(host);
|
||||||
mmc_detach_bus(host);
|
mmc_detach_bus(host);
|
||||||
|
@ -422,6 +422,53 @@ static void mmc_detect(struct mmc_host *host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MMC_ATTR_FN(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
|
||||||
|
card->raw_cid[2], card->raw_cid[3]);
|
||||||
|
MMC_ATTR_FN(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
|
||||||
|
card->raw_csd[2], card->raw_csd[3]);
|
||||||
|
MMC_ATTR_FN(date, "%02d/%04d\n", card->cid.month, card->cid.year);
|
||||||
|
MMC_ATTR_FN(fwrev, "0x%x\n", card->cid.fwrev);
|
||||||
|
MMC_ATTR_FN(hwrev, "0x%x\n", card->cid.hwrev);
|
||||||
|
MMC_ATTR_FN(manfid, "0x%06x\n", card->cid.manfid);
|
||||||
|
MMC_ATTR_FN(name, "%s\n", card->cid.prod_name);
|
||||||
|
MMC_ATTR_FN(oemid, "0x%04x\n", card->cid.oemid);
|
||||||
|
MMC_ATTR_FN(serial, "0x%08x\n", card->cid.serial);
|
||||||
|
|
||||||
|
static struct device_attribute mmc_dev_attrs[] = {
|
||||||
|
MMC_ATTR_RO(cid),
|
||||||
|
MMC_ATTR_RO(csd),
|
||||||
|
MMC_ATTR_RO(date),
|
||||||
|
MMC_ATTR_RO(fwrev),
|
||||||
|
MMC_ATTR_RO(hwrev),
|
||||||
|
MMC_ATTR_RO(manfid),
|
||||||
|
MMC_ATTR_RO(name),
|
||||||
|
MMC_ATTR_RO(oemid),
|
||||||
|
MMC_ATTR_RO(serial),
|
||||||
|
__ATTR_NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds sysfs entries as relevant.
|
||||||
|
*/
|
||||||
|
static int mmc_sysfs_add(struct mmc_host *host, struct mmc_card *card)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mmc_add_attrs(card, mmc_dev_attrs);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes the sysfs entries added by mmc_sysfs_add().
|
||||||
|
*/
|
||||||
|
static void mmc_sysfs_remove(struct mmc_host *host, struct mmc_card *card)
|
||||||
|
{
|
||||||
|
mmc_remove_attrs(card, mmc_dev_attrs);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MMC_UNSAFE_RESUME
|
#ifdef CONFIG_MMC_UNSAFE_RESUME
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -455,9 +502,7 @@ static void mmc_resume(struct mmc_host *host)
|
||||||
|
|
||||||
err = mmc_sd_init_card(host, host->ocr, host->card);
|
err = mmc_sd_init_card(host, host->ocr, host->card);
|
||||||
if (err != MMC_ERR_NONE) {
|
if (err != MMC_ERR_NONE) {
|
||||||
mmc_remove_card(host->card);
|
mmc_remove(host);
|
||||||
host->card = NULL;
|
|
||||||
|
|
||||||
mmc_detach_bus(host);
|
mmc_detach_bus(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,6 +519,8 @@ static void mmc_resume(struct mmc_host *host)
|
||||||
static const struct mmc_bus_ops mmc_ops = {
|
static const struct mmc_bus_ops mmc_ops = {
|
||||||
.remove = mmc_remove,
|
.remove = mmc_remove,
|
||||||
.detect = mmc_detect,
|
.detect = mmc_detect,
|
||||||
|
.sysfs_add = mmc_sysfs_add,
|
||||||
|
.sysfs_remove = mmc_sysfs_remove,
|
||||||
.suspend = mmc_suspend,
|
.suspend = mmc_suspend,
|
||||||
.resume = mmc_resume,
|
.resume = mmc_resume,
|
||||||
};
|
};
|
||||||
|
@ -518,7 +565,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
|
||||||
|
|
||||||
mmc_release_host(host);
|
mmc_release_host(host);
|
||||||
|
|
||||||
err = mmc_register_card(host->card);
|
err = mmc_add_card(host->card);
|
||||||
if (err)
|
if (err)
|
||||||
goto reclaim_host;
|
goto reclaim_host;
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,10 @@
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "sysfs.h"
|
#include "sysfs.h"
|
||||||
|
#include "bus.h"
|
||||||
#include "mmc_ops.h"
|
#include "mmc_ops.h"
|
||||||
#include "sd_ops.h"
|
#include "sd_ops.h"
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
|
|
||||||
static const unsigned int tran_exp[] = {
|
static const unsigned int tran_exp[] = {
|
||||||
10000, 100000, 1000000, 10000000,
|
10000, 100000, 1000000, 10000000,
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
|
@ -487,8 +486,7 @@ static void mmc_sd_detect(struct mmc_host *host)
|
||||||
mmc_release_host(host);
|
mmc_release_host(host);
|
||||||
|
|
||||||
if (err != MMC_ERR_NONE) {
|
if (err != MMC_ERR_NONE) {
|
||||||
mmc_remove_card(host->card);
|
mmc_sd_remove(host);
|
||||||
host->card = NULL;
|
|
||||||
|
|
||||||
mmc_claim_host(host);
|
mmc_claim_host(host);
|
||||||
mmc_detach_bus(host);
|
mmc_detach_bus(host);
|
||||||
|
@ -496,6 +494,55 @@ static void mmc_sd_detect(struct mmc_host *host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MMC_ATTR_FN(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
|
||||||
|
card->raw_cid[2], card->raw_cid[3]);
|
||||||
|
MMC_ATTR_FN(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
|
||||||
|
card->raw_csd[2], card->raw_csd[3]);
|
||||||
|
MMC_ATTR_FN(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
|
||||||
|
MMC_ATTR_FN(date, "%02d/%04d\n", card->cid.month, card->cid.year);
|
||||||
|
MMC_ATTR_FN(fwrev, "0x%x\n", card->cid.fwrev);
|
||||||
|
MMC_ATTR_FN(hwrev, "0x%x\n", card->cid.hwrev);
|
||||||
|
MMC_ATTR_FN(manfid, "0x%06x\n", card->cid.manfid);
|
||||||
|
MMC_ATTR_FN(name, "%s\n", card->cid.prod_name);
|
||||||
|
MMC_ATTR_FN(oemid, "0x%04x\n", card->cid.oemid);
|
||||||
|
MMC_ATTR_FN(serial, "0x%08x\n", card->cid.serial);
|
||||||
|
|
||||||
|
static struct device_attribute mmc_sd_dev_attrs[] = {
|
||||||
|
MMC_ATTR_RO(cid),
|
||||||
|
MMC_ATTR_RO(csd),
|
||||||
|
MMC_ATTR_RO(scr),
|
||||||
|
MMC_ATTR_RO(date),
|
||||||
|
MMC_ATTR_RO(fwrev),
|
||||||
|
MMC_ATTR_RO(hwrev),
|
||||||
|
MMC_ATTR_RO(manfid),
|
||||||
|
MMC_ATTR_RO(name),
|
||||||
|
MMC_ATTR_RO(oemid),
|
||||||
|
MMC_ATTR_RO(serial),
|
||||||
|
__ATTR_NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds sysfs entries as relevant.
|
||||||
|
*/
|
||||||
|
static int mmc_sd_sysfs_add(struct mmc_host *host, struct mmc_card *card)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mmc_add_attrs(card, mmc_sd_dev_attrs);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes the sysfs entries added by mmc_sysfs_add().
|
||||||
|
*/
|
||||||
|
static void mmc_sd_sysfs_remove(struct mmc_host *host, struct mmc_card *card)
|
||||||
|
{
|
||||||
|
mmc_remove_attrs(card, mmc_sd_dev_attrs);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MMC_UNSAFE_RESUME
|
#ifdef CONFIG_MMC_UNSAFE_RESUME
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -529,9 +576,7 @@ static void mmc_sd_resume(struct mmc_host *host)
|
||||||
|
|
||||||
err = mmc_sd_init_card(host, host->ocr, host->card);
|
err = mmc_sd_init_card(host, host->ocr, host->card);
|
||||||
if (err != MMC_ERR_NONE) {
|
if (err != MMC_ERR_NONE) {
|
||||||
mmc_remove_card(host->card);
|
mmc_sd_remove(host);
|
||||||
host->card = NULL;
|
|
||||||
|
|
||||||
mmc_detach_bus(host);
|
mmc_detach_bus(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,6 +593,8 @@ static void mmc_sd_resume(struct mmc_host *host)
|
||||||
static const struct mmc_bus_ops mmc_sd_ops = {
|
static const struct mmc_bus_ops mmc_sd_ops = {
|
||||||
.remove = mmc_sd_remove,
|
.remove = mmc_sd_remove,
|
||||||
.detect = mmc_sd_detect,
|
.detect = mmc_sd_detect,
|
||||||
|
.sysfs_add = mmc_sd_sysfs_add,
|
||||||
|
.sysfs_remove = mmc_sd_sysfs_remove,
|
||||||
.suspend = mmc_sd_suspend,
|
.suspend = mmc_sd_suspend,
|
||||||
.resume = mmc_sd_resume,
|
.resume = mmc_sd_resume,
|
||||||
};
|
};
|
||||||
|
@ -599,7 +646,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
|
||||||
|
|
||||||
mmc_release_host(host);
|
mmc_release_host(host);
|
||||||
|
|
||||||
err = mmc_register_card(host->card);
|
err = mmc_add_card(host->card);
|
||||||
if (err)
|
if (err)
|
||||||
goto reclaim_host;
|
goto reclaim_host;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* linux/drivers/mmc/core/sysfs.c
|
* linux/drivers/mmc/core/sysfs.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2003 Russell King, All Rights Reserved.
|
* Copyright (C) 2003 Russell King, All Rights Reserved.
|
||||||
|
* Copyright 2007 Pierre Ossman
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -18,226 +19,37 @@
|
||||||
#include <linux/mmc/card.h>
|
#include <linux/mmc/card.h>
|
||||||
#include <linux/mmc/host.h>
|
#include <linux/mmc/host.h>
|
||||||
|
|
||||||
|
#include "bus.h"
|
||||||
#include "sysfs.h"
|
#include "sysfs.h"
|
||||||
|
|
||||||
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
|
|
||||||
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
|
#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)
|
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
|
||||||
|
|
||||||
#define MMC_ATTR(name, fmt, args...) \
|
int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs)
|
||||||
static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
|
|
||||||
{ \
|
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev); \
|
|
||||||
return sprintf(buf, fmt, args); \
|
|
||||||
}
|
|
||||||
|
|
||||||
MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
|
|
||||||
card->raw_cid[2], card->raw_cid[3]);
|
|
||||||
MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
|
|
||||||
card->raw_csd[2], card->raw_csd[3]);
|
|
||||||
MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
|
|
||||||
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
|
|
||||||
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
|
|
||||||
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
|
|
||||||
MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
|
|
||||||
MMC_ATTR(name, "%s\n", card->cid.prod_name);
|
|
||||||
MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
|
|
||||||
MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
|
|
||||||
|
|
||||||
#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
|
|
||||||
|
|
||||||
static struct device_attribute mmc_dev_attrs[] = {
|
|
||||||
MMC_ATTR_RO(cid),
|
|
||||||
MMC_ATTR_RO(csd),
|
|
||||||
MMC_ATTR_RO(date),
|
|
||||||
MMC_ATTR_RO(fwrev),
|
|
||||||
MMC_ATTR_RO(hwrev),
|
|
||||||
MMC_ATTR_RO(manfid),
|
|
||||||
MMC_ATTR_RO(name),
|
|
||||||
MMC_ATTR_RO(oemid),
|
|
||||||
MMC_ATTR_RO(serial),
|
|
||||||
__ATTR_NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
|
|
||||||
|
|
||||||
|
|
||||||
static void mmc_release_card(struct device *dev)
|
|
||||||
{
|
{
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
int error = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
kfree(card);
|
for (i = 0; attr_name(attrs[i]); i++) {
|
||||||
}
|
error = device_create_file(&card->dev, &attrs[i]);
|
||||||
|
if (error) {
|
||||||
/*
|
while (--i >= 0)
|
||||||
* This currently matches any MMC driver to any MMC card - drivers
|
device_remove_file(&card->dev, &attrs[i]);
|
||||||
* themselves make the decision whether to drive this card in their
|
break;
|
||||||
* probe method.
|
|
||||||
*/
|
|
||||||
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
|
|
||||||
int buf_size)
|
|
||||||
{
|
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
|
||||||
char ccc[13];
|
|
||||||
int retval = 0, i = 0, length = 0;
|
|
||||||
|
|
||||||
#define add_env(fmt,val) do { \
|
|
||||||
retval = add_uevent_var(envp, num_envp, &i, \
|
|
||||||
buf, buf_size, &length, \
|
|
||||||
fmt, val); \
|
|
||||||
if (retval) \
|
|
||||||
return retval; \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
for (i = 0; i < 12; i++)
|
|
||||||
ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
|
|
||||||
ccc[12] = '\0';
|
|
||||||
|
|
||||||
add_env("MMC_CCC=%s", ccc);
|
|
||||||
add_env("MMC_MANFID=%06x", card->cid.manfid);
|
|
||||||
add_env("MMC_NAME=%s", mmc_card_name(card));
|
|
||||||
add_env("MMC_OEMID=%04x", card->cid.oemid);
|
|
||||||
#undef add_env
|
|
||||||
envp[i] = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmc_bus_suspend(struct device *dev, pm_message_t state)
|
|
||||||
{
|
|
||||||
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (dev->driver && drv->suspend)
|
|
||||||
ret = drv->suspend(card, state);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmc_bus_resume(struct device *dev)
|
|
||||||
{
|
|
||||||
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (dev->driver && drv->resume)
|
|
||||||
ret = drv->resume(card);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmc_bus_probe(struct device *dev)
|
|
||||||
{
|
|
||||||
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
|
||||||
|
|
||||||
return drv->probe(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmc_bus_remove(struct device *dev)
|
|
||||||
{
|
|
||||||
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
|
||||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
|
||||||
|
|
||||||
drv->remove(card);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct bus_type mmc_bus_type = {
|
|
||||||
.name = "mmc",
|
|
||||||
.dev_attrs = mmc_dev_attrs,
|
|
||||||
.match = mmc_bus_match,
|
|
||||||
.uevent = mmc_bus_uevent,
|
|
||||||
.probe = mmc_bus_probe,
|
|
||||||
.remove = mmc_bus_remove,
|
|
||||||
.suspend = mmc_bus_suspend,
|
|
||||||
.resume = mmc_bus_resume,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mmc_register_driver - register a media driver
|
|
||||||
* @drv: MMC media driver
|
|
||||||
*/
|
|
||||||
int mmc_register_driver(struct mmc_driver *drv)
|
|
||||||
{
|
|
||||||
drv->drv.bus = &mmc_bus_type;
|
|
||||||
return driver_register(&drv->drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(mmc_register_driver);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mmc_unregister_driver - unregister a media driver
|
|
||||||
* @drv: MMC media driver
|
|
||||||
*/
|
|
||||||
void mmc_unregister_driver(struct mmc_driver *drv)
|
|
||||||
{
|
|
||||||
drv->drv.bus = &mmc_bus_type;
|
|
||||||
driver_unregister(&drv->drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(mmc_unregister_driver);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Internal function. Initialise a MMC card structure.
|
|
||||||
*/
|
|
||||||
void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
|
|
||||||
{
|
|
||||||
memset(card, 0, sizeof(struct mmc_card));
|
|
||||||
card->host = host;
|
|
||||||
device_initialize(&card->dev);
|
|
||||||
card->dev.parent = mmc_classdev(host);
|
|
||||||
card->dev.bus = &mmc_bus_type;
|
|
||||||
card->dev.release = mmc_release_card;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Internal function. Register a new MMC card with the driver model.
|
|
||||||
*/
|
|
||||||
int mmc_register_card(struct mmc_card *card)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
|
|
||||||
"%s:%04x", mmc_hostname(card->host), card->rca);
|
|
||||||
|
|
||||||
ret = device_add(&card->dev);
|
|
||||||
if (ret == 0) {
|
|
||||||
if (mmc_card_sd(card)) {
|
|
||||||
ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
|
|
||||||
if (ret)
|
|
||||||
device_del(&card->dev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
|
||||||
mmc_card_set_present(card);
|
return error;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs)
|
||||||
* Internal function. Unregister a new MMC card with the
|
|
||||||
* driver model, and (eventually) free it.
|
|
||||||
*/
|
|
||||||
void mmc_remove_card(struct mmc_card *card)
|
|
||||||
{
|
{
|
||||||
if (mmc_card_present(card)) {
|
int i;
|
||||||
if (mmc_card_sd(card))
|
|
||||||
device_remove_file(&card->dev, &mmc_dev_attr_scr);
|
|
||||||
|
|
||||||
device_del(&card->dev);
|
for (i = 0; attr_name(attrs[i]); i++)
|
||||||
}
|
device_remove_file(&card->dev, &attrs[i]);
|
||||||
|
|
||||||
put_device(&card->dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mmc_host_classdev_release(struct device *dev)
|
static void mmc_host_classdev_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||||
|
@ -340,11 +152,11 @@ static int __init mmc_init(void)
|
||||||
if (!workqueue)
|
if (!workqueue)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = bus_register(&mmc_bus_type);
|
ret = mmc_register_bus();
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = class_register(&mmc_host_class);
|
ret = class_register(&mmc_host_class);
|
||||||
if (ret)
|
if (ret)
|
||||||
bus_unregister(&mmc_bus_type);
|
mmc_unregister_bus();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -352,7 +164,7 @@ static int __init mmc_init(void)
|
||||||
static void __exit mmc_exit(void)
|
static void __exit mmc_exit(void)
|
||||||
{
|
{
|
||||||
class_unregister(&mmc_host_class);
|
class_unregister(&mmc_host_class);
|
||||||
bus_unregister(&mmc_bus_type);
|
mmc_unregister_bus();
|
||||||
destroy_workqueue(workqueue);
|
destroy_workqueue(workqueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,17 @@
|
||||||
#ifndef _MMC_CORE_SYSFS_H
|
#ifndef _MMC_CORE_SYSFS_H
|
||||||
#define _MMC_CORE_SYSFS_H
|
#define _MMC_CORE_SYSFS_H
|
||||||
|
|
||||||
void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
|
#define MMC_ATTR_FN(name, fmt, args...) \
|
||||||
int mmc_register_card(struct mmc_card *card);
|
static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||||
void mmc_remove_card(struct mmc_card *card);
|
{ \
|
||||||
|
struct mmc_card *card = container_of(dev, struct mmc_card, dev);\
|
||||||
|
return sprintf(buf, fmt, args); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
|
||||||
|
|
||||||
|
int mmc_add_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);
|
struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
|
||||||
int mmc_add_host_sysfs(struct mmc_host *host);
|
int mmc_add_host_sysfs(struct mmc_host *host);
|
||||||
|
|
Loading…
Reference in New Issue