mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 15:29:16 +00:00
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
|
||||
|
||||
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
|
||||
|
||||
|
253
drivers/mmc/core/bus.c
Normal file
253
drivers/mmc/core/bus.c
Normal file
@ -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);
|
||||
}
|
||||
|
22
drivers/mmc/core/bus.h
Normal file
22
drivers/mmc/core/bus.h
Normal file
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* First, we enable power to the card without the clock running.
|
||||
|
@ -18,6 +18,8 @@
|
||||
struct mmc_bus_ops {
|
||||
void (*remove)(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 (*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);
|
||||
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)
|
||||
{
|
||||
if (ms < 1000 / HZ) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "sysfs.h"
|
||||
#include "bus.h"
|
||||
#include "mmc_ops.h"
|
||||
|
||||
static const unsigned int tran_exp[] = {
|
||||
@ -413,8 +414,7 @@ static void mmc_detect(struct mmc_host *host)
|
||||
mmc_release_host(host);
|
||||
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_remove_card(host->card);
|
||||
host->card = NULL;
|
||||
mmc_remove(host);
|
||||
|
||||
mmc_claim_host(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
|
||||
|
||||
/*
|
||||
@ -455,9 +502,7 @@ static void mmc_resume(struct mmc_host *host)
|
||||
|
||||
err = mmc_sd_init_card(host, host->ocr, host->card);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_remove_card(host->card);
|
||||
host->card = NULL;
|
||||
|
||||
mmc_remove(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 = {
|
||||
.remove = mmc_remove,
|
||||
.detect = mmc_detect,
|
||||
.sysfs_add = mmc_sysfs_add,
|
||||
.sysfs_remove = mmc_sysfs_remove,
|
||||
.suspend = mmc_suspend,
|
||||
.resume = mmc_resume,
|
||||
};
|
||||
@ -518,7 +565,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
|
||||
|
||||
mmc_release_host(host);
|
||||
|
||||
err = mmc_register_card(host->card);
|
||||
err = mmc_add_card(host->card);
|
||||
if (err)
|
||||
goto reclaim_host;
|
||||
|
||||
|
@ -19,11 +19,10 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "sysfs.h"
|
||||
#include "bus.h"
|
||||
#include "mmc_ops.h"
|
||||
#include "sd_ops.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
static const unsigned int tran_exp[] = {
|
||||
10000, 100000, 1000000, 10000000,
|
||||
0, 0, 0, 0
|
||||
@ -487,8 +486,7 @@ static void mmc_sd_detect(struct mmc_host *host)
|
||||
mmc_release_host(host);
|
||||
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_remove_card(host->card);
|
||||
host->card = NULL;
|
||||
mmc_sd_remove(host);
|
||||
|
||||
mmc_claim_host(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
|
||||
|
||||
/*
|
||||
@ -529,9 +576,7 @@ static void mmc_sd_resume(struct mmc_host *host)
|
||||
|
||||
err = mmc_sd_init_card(host, host->ocr, host->card);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
mmc_remove_card(host->card);
|
||||
host->card = NULL;
|
||||
|
||||
mmc_sd_remove(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 = {
|
||||
.remove = mmc_sd_remove,
|
||||
.detect = mmc_sd_detect,
|
||||
.sysfs_add = mmc_sd_sysfs_add,
|
||||
.sysfs_remove = mmc_sd_sysfs_remove,
|
||||
.suspend = mmc_sd_suspend,
|
||||
.resume = mmc_sd_resume,
|
||||
};
|
||||
@ -599,7 +646,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
|
||||
|
||||
mmc_release_host(host);
|
||||
|
||||
err = mmc_register_card(host->card);
|
||||
err = mmc_add_card(host->card);
|
||||
if (err)
|
||||
goto reclaim_host;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
* linux/drivers/mmc/core/sysfs.c
|
||||
*
|
||||
* 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
|
||||
@ -18,226 +19,37 @@
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include "bus.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 cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
|
||||
|
||||
#define MMC_ATTR(name, fmt, args...) \
|
||||
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)
|
||||
int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs)
|
||||
{
|
||||
struct mmc_card *card = dev_to_mmc_card(dev);
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
for (i = 0; attr_name(attrs[i]); i++) {
|
||||
error = device_create_file(&card->dev, &attrs[i]);
|
||||
if (error) {
|
||||
while (--i >= 0)
|
||||
device_remove_file(&card->dev, &attrs[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == 0)
|
||||
mmc_card_set_present(card);
|
||||
return ret;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal function. Unregister a new MMC card with the
|
||||
* driver model, and (eventually) free it.
|
||||
*/
|
||||
void mmc_remove_card(struct mmc_card *card)
|
||||
void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs)
|
||||
{
|
||||
if (mmc_card_present(card)) {
|
||||
if (mmc_card_sd(card))
|
||||
device_remove_file(&card->dev, &mmc_dev_attr_scr);
|
||||
int i;
|
||||
|
||||
device_del(&card->dev);
|
||||
}
|
||||
|
||||
put_device(&card->dev);
|
||||
for (i = 0; attr_name(attrs[i]); 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);
|
||||
@ -340,11 +152,11 @@ static int __init mmc_init(void)
|
||||
if (!workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = bus_register(&mmc_bus_type);
|
||||
ret = mmc_register_bus();
|
||||
if (ret == 0) {
|
||||
ret = class_register(&mmc_host_class);
|
||||
if (ret)
|
||||
bus_unregister(&mmc_bus_type);
|
||||
mmc_unregister_bus();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -352,7 +164,7 @@ static int __init mmc_init(void)
|
||||
static void __exit mmc_exit(void)
|
||||
{
|
||||
class_unregister(&mmc_host_class);
|
||||
bus_unregister(&mmc_bus_type);
|
||||
mmc_unregister_bus();
|
||||
destroy_workqueue(workqueue);
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,17 @@
|
||||
#ifndef _MMC_CORE_SYSFS_H
|
||||
#define _MMC_CORE_SYSFS_H
|
||||
|
||||
void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
|
||||
int mmc_register_card(struct mmc_card *card);
|
||||
void mmc_remove_card(struct mmc_card *card);
|
||||
#define MMC_ATTR_FN(name, fmt, args...) \
|
||||
static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
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);
|
||||
int mmc_add_host_sysfs(struct mmc_host *host);
|
||||
|
Loading…
x
Reference in New Issue
Block a user