sdio_bus.c revision 9a08f82b3cc522f727ace580a2aaee5402435bc8
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/drivers/mmc/core/sdio_bus.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright 2007 Pierre Ossman
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SDIO function driver model
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/card.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/sdio_func.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sdio_cis.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sdio_bus.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dev_to_sdio_func(d)	container_of(d, struct sdio_func, dev)
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define to_sdio_driver(d)      container_of(d, struct sdio_driver, drv)
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* show configuration fields */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sdio_config_attr(field, format_string)				\
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t								\
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfield##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{									\
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func;						\
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									\
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = dev_to_sdio_func (dev);					\
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf (buf, format_string, func->field);		\
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssdio_config_attr(class, "0x%02x\n");
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssdio_config_attr(vendor, "0x%04x\n");
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssdio_config_attr(device, "0x%04x\n");
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func = dev_to_sdio_func (dev);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func->class, func->vendor, func->device);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct device_attribute sdio_dev_attrs[] = {
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__ATTR_RO(class),
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__ATTR_RO(vendor),
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__ATTR_RO(device),
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__ATTR_RO(modalias),
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__ATTR_NULL,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct sdio_device_id *id)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return id;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_driver *sdrv)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct sdio_device_id *ids;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ids = sdrv->id_table;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ids) {
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (ids->class || ids->vendor || ids->device) {
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (sdio_match_one(func, ids))
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return ids;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ids++;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sdio_bus_match(struct device *dev, struct device_driver *drv)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func = dev_to_sdio_func(dev);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_driver *sdrv = to_sdio_driver(drv);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sdio_match_device(func, sdrv))
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int buf_size)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func = dev_to_sdio_func(dev);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0, length = 0;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (add_uevent_var(envp, num_envp, &i,
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf, buf_size, &length,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"SDIO_CLASS=%02X", func->class))
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (add_uevent_var(envp, num_envp, &i,
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf, buf_size, &length,
11228120be5d6830cd7c7777d8bf570bdb20abef58aPaul Walmsley			"SDIO_ID=%04X:%04X", func->vendor, func->device))
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (add_uevent_var(envp, num_envp, &i,
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf, buf_size, &length,
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"MODALIAS=sdio:c%02Xv%04Xd%04X",
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func->class, func->vendor, func->device))
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	envp[i] = NULL;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sdio_bus_probe(struct device *dev)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_driver *drv = to_sdio_driver(dev->driver);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func = dev_to_sdio_func(dev);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct sdio_device_id *id;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	id = sdio_match_device(func, drv);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!id)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set the default block size so the driver is sure it's something
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * sensible. */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sdio_claim_host(func);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = sdio_set_block_size(func, 0);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sdio_release_host(func);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return drv->probe(func, id);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sdio_bus_remove(struct device *dev)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_driver *drv = to_sdio_driver(dev->driver);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func = dev_to_sdio_func(dev);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv->remove(func);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->irq_handler) {
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "WARNING: driver %s did not remove "
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"its interrupt handler!\n", drv->name);
15886dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm		sdio_claim_host(func);
159a4e628328ec60873fec9d506d682155391f589ceMatthew Dharm		sdio_release_irq(func);
160a4e628328ec60873fec9d506d682155391f589ceMatthew Dharm		sdio_release_host(func);
161a4e628328ec60873fec9d506d682155391f589ceMatthew Dharm	}
162a4e628328ec60873fec9d506d682155391f589ceMatthew Dharm
163a4e628328ec60873fec9d506d682155391f589ceMatthew Dharm	return 0;
164a4e628328ec60873fec9d506d682155391f589ceMatthew Dharm}
16528120be5d6830cd7c7777d8bf570bdb20abef58aPaul Walmsley
166a4e628328ec60873fec9d506d682155391f589ceMatthew Dharmstatic struct bus_type sdio_bus_type = {
16786dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm	.name		= "sdio",
16886dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm	.dev_attrs	= sdio_dev_attrs,
16986dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm	.match		= sdio_bus_match,
17086dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm	.uevent		= sdio_bus_uevent,
17186dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm	.probe		= sdio_bus_probe,
17286dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm	.remove		= sdio_bus_remove,
17386dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm};
17486dbde9cbdfe8bc2c2dfe5d33027d3acc55e0470Matthew Dharm
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sdio_register_bus(void)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bus_register(&sdio_bus_type);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sdio_unregister_bus(void)
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bus_unregister(&sdio_bus_type);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	sdio_register_driver - register a function driver
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@drv: SDIO function driver
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sdio_register_driver(struct sdio_driver *drv)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv->drv.name = drv->name;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv->drv.bus = &sdio_bus_type;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return driver_register(&drv->drv);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(sdio_register_driver);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	sdio_unregister_driver - unregister a function driver
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@drv: SDIO function driver
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sdio_unregister_driver(struct sdio_driver *drv)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drv->drv.bus = &sdio_bus_type;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister(&drv->drv);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(sdio_unregister_driver);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sdio_release_func(struct device *dev)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func = dev_to_sdio_func(dev);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sdio_free_func_cis(func);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(func);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate and initialise a new SDIO function structure.
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sdio_func *sdio_alloc_func(struct mmc_card *card)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sdio_func *func;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = kmalloc(sizeof(struct sdio_func), GFP_KERNEL);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(func, 0, sizeof(struct sdio_func));
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->card = card;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_initialize(&func->dev);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->dev.parent = &card->dev;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->dev.bus = &sdio_bus_type;
236226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm	func->dev.release = sdio_release_func;
237226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm
238226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm	return func;
239226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
242226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm * Register a new SDIO function with the driver model.
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sdio_add_func(struct sdio_func *func)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	snprintf(func->dev.bus_id, sizeof(func->dev.bus_id),
249226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm		 "%s:%d", mmc_card_id(func->card), func->num);
250226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm
251226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm	ret = device_add(&func->dev);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret == 0)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sdio_func_set_present(func);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
257226173edae1c49c68ebb723771a02302c85e3475Matthew Dharm
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unregister a SDIO function with the driver model, and
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (eventually) free it.
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sdio_remove_func(struct sdio_func *func)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sdio_func_present(func))
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_del(&func->dev);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	put_device(&func->dev);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds