sdio_bus.c 5.7 KB
Newer Older
P
Pierre Ossman 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 *  linux/drivers/mmc/core/sdio_bus.c
 *
 *  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 as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * SDIO function driver model
 */

#include <linux/device.h>
#include <linux/err.h>

#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>

20
#include "sdio_cis.h"
P
Pierre Ossman 已提交
21 22 23
#include "sdio_bus.h"

#define dev_to_sdio_func(d)	container_of(d, struct sdio_func, dev)
24 25
#define to_sdio_driver(d)      container_of(d, struct sdio_driver, drv)

P
Pierre Ossman 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/* show configuration fields */
#define sdio_config_attr(field, format_string)				\
static ssize_t								\
field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
{									\
	struct sdio_func *func;						\
									\
	func = dev_to_sdio_func (dev);					\
	return sprintf (buf, format_string, func->field);		\
}

sdio_config_attr(class, "0x%02x\n");
sdio_config_attr(vendor, "0x%04x\n");
sdio_config_attr(device, "0x%04x\n");

static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct sdio_func *func = dev_to_sdio_func (dev);

	return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
			func->class, func->vendor, func->device);
}

49
static struct device_attribute sdio_dev_attrs[] = {
P
Pierre Ossman 已提交
50 51 52 53 54 55 56
	__ATTR_RO(class),
	__ATTR_RO(vendor),
	__ATTR_RO(device),
	__ATTR_RO(modalias),
	__ATTR_NULL,
};

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
	const struct sdio_device_id *id)
{
	if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
		return NULL;
	if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
		return NULL;
	if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
		return NULL;
	return id;
}

static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
	struct sdio_driver *sdrv)
{
	const struct sdio_device_id *ids;

	ids = sdrv->id_table;

	if (ids) {
		while (ids->class || ids->vendor || ids->device) {
			if (sdio_match_one(func, ids))
				return ids;
			ids++;
		}
	}

	return NULL;
}
P
Pierre Ossman 已提交
86 87 88

static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{
89 90 91 92 93 94 95
	struct sdio_func *func = dev_to_sdio_func(dev);
	struct sdio_driver *sdrv = to_sdio_driver(drv);

	if (sdio_match_device(func, sdrv))
		return 1;

	return 0;
P
Pierre Ossman 已提交
96 97 98
}

static int
A
Al Viro 已提交
99
sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
P
Pierre Ossman 已提交
100
{
P
Pierre Ossman 已提交
101 102
	struct sdio_func *func = dev_to_sdio_func(dev);

A
Al Viro 已提交
103
	if (add_uevent_var(env,
P
Pierre Ossman 已提交
104 105 106
			"SDIO_CLASS=%02X", func->class))
		return -ENOMEM;

A
Al Viro 已提交
107
	if (add_uevent_var(env, 
P
Pierre Ossman 已提交
108 109 110
			"SDIO_ID=%04X:%04X", func->vendor, func->device))
		return -ENOMEM;

A
Al Viro 已提交
111
	if (add_uevent_var(env,
P
Pierre Ossman 已提交
112 113 114 115
			"MODALIAS=sdio:c%02Xv%04Xd%04X",
			func->class, func->vendor, func->device))
		return -ENOMEM;

P
Pierre Ossman 已提交
116 117 118 119 120
	return 0;
}

static int sdio_bus_probe(struct device *dev)
{
121 122 123
	struct sdio_driver *drv = to_sdio_driver(dev->driver);
	struct sdio_func *func = dev_to_sdio_func(dev);
	const struct sdio_device_id *id;
124
	int ret;
125 126 127 128 129

	id = sdio_match_device(func, drv);
	if (!id)
		return -ENODEV;

130 131 132 133 134 135 136 137
	/* Set the default block size so the driver is sure it's something
	 * sensible. */
	sdio_claim_host(func);
	ret = sdio_set_block_size(func, 0);
	sdio_release_host(func);
	if (ret)
		return ret;

138
	return drv->probe(func, id);
P
Pierre Ossman 已提交
139 140 141 142
}

static int sdio_bus_remove(struct device *dev)
{
143 144 145 146 147
	struct sdio_driver *drv = to_sdio_driver(dev->driver);
	struct sdio_func *func = dev_to_sdio_func(dev);

	drv->remove(func);

148 149 150 151 152 153 154 155
	if (func->irq_handler) {
		printk(KERN_WARNING "WARNING: driver %s did not remove "
			"its interrupt handler!\n", drv->name);
		sdio_claim_host(func);
		sdio_release_irq(func);
		sdio_release_host(func);
	}

P
Pierre Ossman 已提交
156 157 158 159 160
	return 0;
}

static struct bus_type sdio_bus_type = {
	.name		= "sdio",
P
Pierre Ossman 已提交
161
	.dev_attrs	= sdio_dev_attrs,
P
Pierre Ossman 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	.match		= sdio_bus_match,
	.uevent		= sdio_bus_uevent,
	.probe		= sdio_bus_probe,
	.remove		= sdio_bus_remove,
};

int sdio_register_bus(void)
{
	return bus_register(&sdio_bus_type);
}

void sdio_unregister_bus(void)
{
	bus_unregister(&sdio_bus_type);
}

P
Pierre Ossman 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
/**
 *	sdio_register_driver - register a function driver
 *	@drv: SDIO function driver
 */
int sdio_register_driver(struct sdio_driver *drv)
{
	drv->drv.name = drv->name;
	drv->drv.bus = &sdio_bus_type;
	return driver_register(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_register_driver);

/**
 *	sdio_unregister_driver - unregister a function driver
 *	@drv: SDIO function driver
 */
void sdio_unregister_driver(struct sdio_driver *drv)
{
	drv->drv.bus = &sdio_bus_type;
	driver_unregister(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_unregister_driver);

P
Pierre Ossman 已提交
201 202 203
static void sdio_release_func(struct device *dev)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
204

205
	sdio_free_func_cis(func);
P
Pierre Ossman 已提交
206

P
Pierre Ossman 已提交
207 208 209
	if (func->info)
		kfree(func->info);

P
Pierre Ossman 已提交
210 211 212 213 214 215 216 217 218 219
	kfree(func);
}

/*
 * Allocate and initialise a new SDIO function structure.
 */
struct sdio_func *sdio_alloc_func(struct mmc_card *card)
{
	struct sdio_func *func;

220
	func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
P
Pierre Ossman 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	if (!func)
		return ERR_PTR(-ENOMEM);

	func->card = card;

	device_initialize(&func->dev);

	func->dev.parent = &card->dev;
	func->dev.bus = &sdio_bus_type;
	func->dev.release = sdio_release_func;

	return func;
}

/*
 * Register a new SDIO function with the driver model.
 */
int sdio_add_func(struct sdio_func *func)
{
	int ret;

	snprintf(func->dev.bus_id, sizeof(func->dev.bus_id),
		 "%s:%d", mmc_card_id(func->card), func->num);

	ret = device_add(&func->dev);
	if (ret == 0)
		sdio_func_set_present(func);

	return ret;
}

/*
 * Unregister a SDIO function with the driver model, and
 * (eventually) free it.
 */
void sdio_remove_func(struct sdio_func *func)
{
	if (sdio_func_present(func))
		device_del(&func->dev);

	put_device(&func->dev);
}