Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62ea6d80 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (46 commits)
  mmc-omap: Clean up omap set_ios and make MMC_POWER_ON work
  mmc-omap: Fix omap to use MMC_POWER_ON
  mmc-omap: add missing '\n'
  mmc: make tifm_sd_set_dma_data() static
  mmc: remove old card states
  mmc: support unsafe resume of cards
  mmc: separate out reading EXT_CSD
  mmc: break apart switch function
  MMC: Fix handling of low-voltage cards
  MMC: Consolidate voltage definitions
  mmc: add bus handler
  wbsd: check for data opcode earlier
  mmc: Separate out protocol ops
  mmc: Move core functions to subdir
  mmc: deprecate mmc bus topology
  mmc: remove card upon suspend
  mmc: allow suspended block driver to be removed
  mmc: Flush pending detects on host removal
  mmc: Move host and card drivers to subdirs
  mmc: Move queue functions to mmc_block
  ...
parents fa24aa56 d3af5abe
Loading
Loading
Loading
Loading
+141 −191
Original line number Diff line number Diff line
@@ -11,10 +11,20 @@

#include <linux/tifm.h>
#include <linux/dma-mapping.h>
#include <linux/freezer.h>

#define DRIVER_NAME "tifm_7xx1"
#define DRIVER_VERSION "0.7"
#define DRIVER_VERSION "0.8"

#define TIFM_IRQ_ENABLE           0x80000000
#define TIFM_IRQ_SOCKMASK(x)      (x)
#define TIFM_IRQ_CARDMASK(x)      ((x) << 8)
#define TIFM_IRQ_FIFOMASK(x)      ((x) << 16)
#define TIFM_IRQ_SETALL           0xffffffff

static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm,
				  struct tifm_dev *sock)
{
}

static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
{
@@ -22,7 +32,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)

	spin_lock_irqsave(&fm->lock, flags);
	fm->socket_change_set |= 1 << sock->socket_id;
	wake_up_all(&fm->change_set_notify);
	tifm_queue_work(&fm->media_switcher);
	spin_unlock_irqrestore(&fm->lock, flags);
}

@@ -30,8 +40,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{
	struct tifm_adapter *fm = dev_id;
	struct tifm_dev *sock;
	unsigned int irq_status;
	unsigned int sock_irq_status, cnt;
	unsigned int irq_status, cnt;

	spin_lock(&fm->lock);
	irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
@@ -45,12 +54,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)

		for (cnt = 0; cnt < fm->num_sockets; cnt++) {
			sock = fm->sockets[cnt];
			sock_irq_status = (irq_status >> cnt)
					  & (TIFM_IRQ_FIFOMASK(1)
					     | TIFM_IRQ_CARDMASK(1));

			if (sock && sock_irq_status)
				sock->signal_irq(sock, sock_irq_status);
			if (sock) {
				if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1))
					sock->data_event(sock);
				if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1))
					sock->card_event(sock);
			}
		}

		fm->socket_change_set |= irq_status
@@ -58,55 +67,55 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
	}
	writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);

	if (!fm->socket_change_set)
	if (fm->finish_me)
		complete_all(fm->finish_me);
	else if (!fm->socket_change_set)
		writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
	else
		wake_up_all(&fm->change_set_notify);
		tifm_queue_work(&fm->media_switcher);

	spin_unlock(&fm->lock);
	return IRQ_HANDLED;
}

static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
						 int is_x2)
static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)
{
	unsigned int s_state;
	int cnt;

	writel(0x0e00, sock_addr + SOCK_CONTROL);

	for (cnt = 0; cnt < 100; cnt++) {
	for (cnt = 16; cnt <= 256; cnt <<= 1) {
		if (!(TIFM_SOCK_STATE_POWERED
		      & readl(sock_addr + SOCK_PRESENT_STATE)))
			break;
		msleep(10);

		msleep(cnt);
	}

	s_state = readl(sock_addr + SOCK_PRESENT_STATE);
	if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
		return FM_NULL;
		return 0;

	if (is_x2) {
		writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
	} else {
		// SmartMedia cards need extra 40 msec
		if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
			msleep(40);
	writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
	       sock_addr + SOCK_CONTROL);
		msleep(10);
		writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
			sock_addr + SOCK_CONTROL);
	}

	for (cnt = 0; cnt < 100; cnt++) {
	/* xd needs some extra time before power on */
	if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7)
	    == TIFM_TYPE_XD)
		msleep(40);

	writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
	/* wait for power to stabilize */
	msleep(20);
	for (cnt = 16; cnt <= 256; cnt <<= 1) {
		if ((TIFM_SOCK_STATE_POWERED
		     & readl(sock_addr + SOCK_PRESENT_STATE)))
			break;
		msleep(10);

		msleep(cnt);
	}

	if (!is_x2)
	writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
	       sock_addr + SOCK_CONTROL);

@@ -119,88 +128,53 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
	return base_addr + ((sock_num + 1) << 10);
}

static int tifm_7xx1_switch_media(void *data)
static void tifm_7xx1_switch_media(struct work_struct *work)
{
	struct tifm_adapter *fm = data;
	unsigned long flags;
	tifm_media_id media_id;
	char *card_name = "xx";
	int cnt, rc;
	struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
					       media_switcher);
	struct tifm_dev *sock;
	unsigned int socket_change_set;

	while (1) {
		rc = wait_event_interruptible(fm->change_set_notify,
					      fm->socket_change_set);
		if (rc == -ERESTARTSYS)
			try_to_freeze();
	unsigned long flags;
	unsigned char media_id;
	unsigned int socket_change_set, cnt;

	spin_lock_irqsave(&fm->lock, flags);
	socket_change_set = fm->socket_change_set;
	fm->socket_change_set = 0;

		dev_dbg(fm->dev, "checking media set %x\n",
	dev_dbg(fm->cdev.dev, "checking media set %x\n",
		socket_change_set);

		if (kthread_should_stop())
			socket_change_set = (1 << fm->num_sockets) - 1;
	if (!socket_change_set) {
		spin_unlock_irqrestore(&fm->lock, flags);
		return;
	}

		if (!socket_change_set)
			continue;

		spin_lock_irqsave(&fm->lock, flags);
	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
		if (!(socket_change_set & (1 << cnt)))
			continue;
		sock = fm->sockets[cnt];
		if (sock) {
				printk(KERN_INFO DRIVER_NAME
				       ": demand removing card from socket %d\n",
				       cnt);
			printk(KERN_INFO
			       "%s : demand removing card from socket %u:%u\n",
			       fm->cdev.class_id, fm->id, cnt);
			fm->sockets[cnt] = NULL;
			spin_unlock_irqrestore(&fm->lock, flags);
			device_unregister(&sock->dev);
			spin_lock_irqsave(&fm->lock, flags);
				writel(0x0e00,
				       tifm_7xx1_sock_addr(fm->addr, cnt)
			writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
			       + SOCK_CONTROL);
		}
			if (kthread_should_stop())
				continue;

		spin_unlock_irqrestore(&fm->lock, flags);

		media_id = tifm_7xx1_toggle_sock_power(
					tifm_7xx1_sock_addr(fm->addr, cnt),
					fm->num_sockets == 2);
			if (media_id) {
				sock = tifm_alloc_device(fm);
				tifm_7xx1_sock_addr(fm->addr, cnt));

		// tifm_alloc_device will check if media_id is valid
		sock = tifm_alloc_device(fm, cnt, media_id);
		if (sock) {
					sock->addr = tifm_7xx1_sock_addr(fm->addr,
									 cnt);
					sock->media_id = media_id;
					sock->socket_id = cnt;
					switch (media_id) {
					case 1:
						card_name = "xd";
						break;
					case 2:
						card_name = "ms";
						break;
					case 3:
						card_name = "sd";
						break;
					default:
						tifm_free_device(&sock->dev);
						spin_lock_irqsave(&fm->lock, flags);
						continue;
					}
					snprintf(sock->dev.bus_id, BUS_ID_SIZE,
						 "tifm_%s%u:%u", card_name,
						 fm->id, cnt);
					printk(KERN_INFO DRIVER_NAME
					       ": %s card detected in socket %d\n",
					       card_name, cnt);
			sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt);

			if (!device_register(&sock->dev)) {
				spin_lock_irqsave(&fm->lock, flags);
				if (!fm->sockets[cnt]) {
@@ -214,33 +188,18 @@ static int tifm_7xx1_switch_media(void *data)
		}
		spin_lock_irqsave(&fm->lock, flags);
	}
		}

		if (!kthread_should_stop()) {
	writel(TIFM_IRQ_FIFOMASK(socket_change_set)
	       | TIFM_IRQ_CARDMASK(socket_change_set),
	       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);

	writel(TIFM_IRQ_FIFOMASK(socket_change_set)
	       | TIFM_IRQ_CARDMASK(socket_change_set),
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
			writel(TIFM_IRQ_ENABLE,
			       fm->addr + FM_SET_INTERRUPT_ENABLE);
			spin_unlock_irqrestore(&fm->lock, flags);
		} else {
			for (cnt = 0; cnt < fm->num_sockets; cnt++) {
				if (fm->sockets[cnt])
					fm->socket_change_set |= 1 << cnt;
			}
			if (!fm->socket_change_set) {
				spin_unlock_irqrestore(&fm->lock, flags);
				return 0;
			} else {

	writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
	spin_unlock_irqrestore(&fm->lock, flags);
}
		}
	}
	return 0;
}

#ifdef CONFIG_PM

@@ -258,9 +217,11 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
static int tifm_7xx1_resume(struct pci_dev *dev)
{
	struct tifm_adapter *fm = pci_get_drvdata(dev);
	int cnt, rc;
	int rc;
	unsigned int good_sockets = 0, bad_sockets = 0;
	unsigned long flags;
	tifm_media_id new_ids[fm->num_sockets];
	unsigned char new_ids[fm->num_sockets];
	DECLARE_COMPLETION_ONSTACK(finish_resume);

	pci_set_power_state(dev, PCI_D0);
	pci_restore_state(dev);
@@ -271,45 +232,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev)

	dev_dbg(&dev->dev, "resuming host\n");

	for (cnt = 0; cnt < fm->num_sockets; cnt++)
		new_ids[cnt] = tifm_7xx1_toggle_sock_power(
					tifm_7xx1_sock_addr(fm->addr, cnt),
					fm->num_sockets == 2);
	for (rc = 0; rc < fm->num_sockets; rc++)
		new_ids[rc] = tifm_7xx1_toggle_sock_power(
					tifm_7xx1_sock_addr(fm->addr, rc));
	spin_lock_irqsave(&fm->lock, flags);
	fm->socket_change_set = 0;
	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
		if (fm->sockets[cnt]) {
			if (fm->sockets[cnt]->media_id == new_ids[cnt])
				fm->socket_change_set |= 1 << cnt;

			fm->sockets[cnt]->media_id = new_ids[cnt];
	for (rc = 0; rc < fm->num_sockets; rc++) {
		if (fm->sockets[rc]) {
			if (fm->sockets[rc]->type == new_ids[rc])
				good_sockets |= 1 << rc;
			else
				bad_sockets |= 1 << rc;
		}
	}

	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	if (!fm->socket_change_set) {
		spin_unlock_irqrestore(&fm->lock, flags);
		return 0;
	} else {
	dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",
		good_sockets, bad_sockets);

	fm->socket_change_set = 0;
	if (good_sockets) {
		fm->finish_me = &finish_resume;
		spin_unlock_irqrestore(&fm->lock, flags);
		rc = wait_for_completion_timeout(&finish_resume, HZ);
		dev_dbg(&dev->dev, "wait returned %d\n", rc);
		writel(TIFM_IRQ_FIFOMASK(good_sockets)
		       | TIFM_IRQ_CARDMASK(good_sockets),
		       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
		writel(TIFM_IRQ_FIFOMASK(good_sockets)
		       | TIFM_IRQ_CARDMASK(good_sockets),
		       fm->addr + FM_SET_INTERRUPT_ENABLE);
		spin_lock_irqsave(&fm->lock, flags);
		fm->finish_me = NULL;
		fm->socket_change_set ^= good_sockets & fm->socket_change_set;
	}

	wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
	fm->socket_change_set |= bad_sockets;
	if (fm->socket_change_set)
		tifm_queue_work(&fm->media_switcher);

	spin_lock_irqsave(&fm->lock, flags);
	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
	       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	spin_unlock_irqrestore(&fm->lock, flags);
	writel(TIFM_IRQ_ENABLE,
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	fm->socket_change_set = 0;

	spin_unlock_irqrestore(&fm->lock, flags);
	return 0;
}

@@ -345,20 +310,14 @@ static int tifm_7xx1_probe(struct pci_dev *dev,

	pci_intx(dev, 1);

	fm = tifm_alloc_adapter();
	fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM
				? 4 : 2, &dev->dev);
	if (!fm) {
		rc = -ENOMEM;
		goto err_out_int;
	}

	fm->dev = &dev->dev;
	fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
			  ? 4 : 2;
	fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
			      GFP_KERNEL);
	if (!fm->sockets)
		goto err_out_free;

	INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
	fm->eject = tifm_7xx1_eject;
	pci_set_drvdata(dev, fm);

@@ -367,19 +326,16 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
	if (!fm->addr)
		goto err_out_free;

	rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm);
	rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
	if (rc)
		goto err_out_unmap;

	init_waitqueue_head(&fm->change_set_notify);
	rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
	rc = tifm_add_adapter(fm);
	if (rc)
		goto err_out_irq;

	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	wake_up_process(fm->media_switcher);
	return 0;

err_out_irq:
@@ -401,18 +357,12 @@ err_out:
static void tifm_7xx1_remove(struct pci_dev *dev)
{
	struct tifm_adapter *fm = pci_get_drvdata(dev);
	unsigned long flags;

	fm->eject = tifm_7xx1_dummy_eject;
	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
	mmiowb();
	free_irq(dev->irq, fm);

	spin_lock_irqsave(&fm->lock, flags);
	fm->socket_change_set = (1 << fm->num_sockets) - 1;
	spin_unlock_irqrestore(&fm->lock, flags);

	kthread_stop(fm->media_switcher);

	tifm_remove_adapter(fm);

	pci_set_drvdata(dev, NULL);
+182 −123
Original line number Diff line number Diff line
@@ -14,71 +14,124 @@
#include <linux/idr.h>

#define DRIVER_NAME "tifm_core"
#define DRIVER_VERSION "0.7"
#define DRIVER_VERSION "0.8"

static struct workqueue_struct *workqueue;
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);

static tifm_media_id *tifm_device_match(tifm_media_id *ids,
			struct tifm_dev *dev)
static const char *tifm_media_type_name(unsigned char type, unsigned char nt)
{
	while (*ids) {
		if (dev->media_id == *ids)
			return ids;
		ids++;
	}
	const char *card_type_name[3][3] = {
		{ "SmartMedia/xD", "MemoryStick", "MMC/SD" },
		{ "XD", "MS", "SD"},
		{ "xd", "ms", "sd"}
	};

	if (nt > 2 || type < 1 || type > 3)
		return NULL;
	return card_type_name[nt][type - 1];
}

static int tifm_match(struct device *dev, struct device_driver *drv)
static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)
{
	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *fm_drv;
	if (sock->type == id->type)
		return 1;
	return 0;
}

	fm_drv = container_of(drv, struct tifm_driver, driver);
	if (!fm_drv->id_table)
		return -EINVAL;
	if (tifm_device_match(fm_drv->id_table, fm_dev))
static int tifm_bus_match(struct device *dev, struct device_driver *drv)
{
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver,
						  driver);
	struct tifm_device_id *ids = fm_drv->id_table;

	if (ids) {
		while (ids->type) {
			if (tifm_dev_match(sock, ids))
				return 1;
	return -ENODEV;
			++ids;
		}
	}
	return 0;
}

static int tifm_uevent(struct device *dev, char **envp, int num_envp,
		       char *buffer, int buffer_size)
{
	struct tifm_dev *fm_dev;
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	int i = 0;
	int length = 0;
	const char *card_type_name[] = {"INV", "SM", "MS", "SD"};

	if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
		return -ENODEV;
	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
			"TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id]))
			   "TIFM_CARD_TYPE=%s",
			   tifm_media_type_name(sock->type, 1)))
		return -ENOMEM;

	return 0;
}

static int tifm_device_probe(struct device *dev)
{
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
					       driver);
	int rc = -ENODEV;

	get_device(dev);
	if (dev->driver && drv->probe) {
		rc = drv->probe(sock);
		if (!rc)
			return 0;
	}
	put_device(dev);
	return rc;
}

static void tifm_dummy_event(struct tifm_dev *sock)
{
	return;
}

static int tifm_device_remove(struct device *dev)
{
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
					       driver);

	if (dev->driver && drv->remove) {
		sock->card_event = tifm_dummy_event;
		sock->data_event = tifm_dummy_event;
		drv->remove(sock);
		sock->dev.driver = NULL;
	}

	put_device(dev);
	return 0;
}

#ifdef CONFIG_PM

static int tifm_device_suspend(struct device *dev, pm_message_t state)
{
	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = fm_dev->drv;
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
					       driver);

	if (drv && drv->suspend)
		return drv->suspend(fm_dev, state);
	if (dev->driver && drv->suspend)
		return drv->suspend(sock, state);
	return 0;
}

static int tifm_device_resume(struct device *dev)
{
	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = fm_dev->drv;
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
					       driver);

	if (drv && drv->resume)
		return drv->resume(fm_dev);
	if (dev->driver && drv->resume)
		return drv->resume(sock);
	return 0;
}

@@ -89,10 +142,25 @@ static int tifm_device_resume(struct device *dev)

#endif /* CONFIG_PM */

static ssize_t type_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	return sprintf(buf, "%x", sock->type);
}

static struct device_attribute tifm_dev_attrs[] = {
	__ATTR(type, S_IRUGO, type_show, NULL),
	__ATTR_NULL
};

static struct bus_type tifm_bus_type = {
	.name      = "tifm",
	.match   = tifm_match,
	.dev_attrs = tifm_dev_attrs,
	.match     = tifm_bus_match,
	.uevent    = tifm_uevent,
	.probe     = tifm_device_probe,
	.remove    = tifm_device_remove,
	.suspend   = tifm_device_suspend,
	.resume    = tifm_device_resume
};
@@ -101,7 +169,6 @@ static void tifm_free(struct class_device *cdev)
{
	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);

	kfree(fm->sockets);
	kfree(fm);
}

@@ -110,28 +177,25 @@ static struct class tifm_adapter_class = {
	.release = tifm_free
};

struct tifm_adapter *tifm_alloc_adapter(void)
struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
					struct device *dev)
{
	struct tifm_adapter *fm;

	fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
	fm = kzalloc(sizeof(struct tifm_adapter)
		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
	if (fm) {
		fm->cdev.class = &tifm_adapter_class;
		spin_lock_init(&fm->lock);
		fm->cdev.dev = dev;
		class_device_initialize(&fm->cdev);
		spin_lock_init(&fm->lock);
		fm->num_sockets = num_sockets;
	}
	return fm;
}
EXPORT_SYMBOL(tifm_alloc_adapter);

void tifm_free_adapter(struct tifm_adapter *fm)
{
	class_device_put(&fm->cdev);
}
EXPORT_SYMBOL(tifm_free_adapter);

int tifm_add_adapter(struct tifm_adapter *fm,
		     int (*mediathreadfn)(void *data))
int tifm_add_adapter(struct tifm_adapter *fm)
{
	int rc;

@@ -141,59 +205,80 @@ int tifm_add_adapter(struct tifm_adapter *fm,
	spin_lock(&tifm_adapter_lock);
	rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
	spin_unlock(&tifm_adapter_lock);
	if (!rc) {
		snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
		fm->media_switcher = kthread_create(mediathreadfn,
						    fm, "tifm/%u", fm->id);

		if (!IS_ERR(fm->media_switcher))
			return class_device_add(&fm->cdev);
	if (rc)
		return rc;

	snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
	rc = class_device_add(&fm->cdev);
	if (rc) {
		spin_lock(&tifm_adapter_lock);
		idr_remove(&tifm_adapter_idr, fm->id);
		spin_unlock(&tifm_adapter_lock);
		rc = -ENOMEM;
	}

	return rc;
}
EXPORT_SYMBOL(tifm_add_adapter);

void tifm_remove_adapter(struct tifm_adapter *fm)
{
	class_device_del(&fm->cdev);
	unsigned int cnt;

	flush_workqueue(workqueue);
	for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
		if (fm->sockets[cnt])
			device_unregister(&fm->sockets[cnt]->dev);
	}

	spin_lock(&tifm_adapter_lock);
	idr_remove(&tifm_adapter_idr, fm->id);
	spin_unlock(&tifm_adapter_lock);
	class_device_del(&fm->cdev);
}
EXPORT_SYMBOL(tifm_remove_adapter);

void tifm_free_device(struct device *dev)
void tifm_free_adapter(struct tifm_adapter *fm)
{
	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
	kfree(fm_dev);
	class_device_put(&fm->cdev);
}
EXPORT_SYMBOL(tifm_free_device);
EXPORT_SYMBOL(tifm_free_adapter);

static void tifm_dummy_signal_irq(struct tifm_dev *sock,
				  unsigned int sock_irq_status)
void tifm_free_device(struct device *dev)
{
	return;
	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
	kfree(sock);
}
EXPORT_SYMBOL(tifm_free_device);

struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
				   unsigned char type)
{
	struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);

	if (dev) {
		spin_lock_init(&dev->lock);

		dev->dev.parent = fm->dev;
		dev->dev.bus = &tifm_bus_type;
		dev->dev.release = tifm_free_device;
		dev->signal_irq = tifm_dummy_signal_irq;
	struct tifm_dev *sock = NULL;

	if (!tifm_media_type_name(type, 0))
		return sock;

	sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
	if (sock) {
		spin_lock_init(&sock->lock);
		sock->type = type;
		sock->socket_id = id;
		sock->card_event = tifm_dummy_event;
		sock->data_event = tifm_dummy_event;

		sock->dev.parent = fm->cdev.dev;
		sock->dev.bus = &tifm_bus_type;
		sock->dev.dma_mask = fm->cdev.dev->dma_mask;
		sock->dev.release = tifm_free_device;

		snprintf(sock->dev.bus_id, BUS_ID_SIZE,
			 "tifm_%s%u:%u", tifm_media_type_name(type, 2),
			 fm->id, id);
		printk(KERN_INFO DRIVER_NAME
		       ": %s card detected in socket %u:%u\n",
		       tifm_media_type_name(type, 0), fm->id, id);
	}
	return dev;
	return sock;
}
EXPORT_SYMBOL(tifm_alloc_device);

@@ -218,54 +303,15 @@ void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
}
EXPORT_SYMBOL(tifm_unmap_sg);

static int tifm_device_probe(struct device *dev)
{
	struct tifm_driver *drv;
	struct tifm_dev *fm_dev;
	int rc = 0;
	const tifm_media_id *id;

	drv = container_of(dev->driver, struct tifm_driver, driver);
	fm_dev = container_of(dev, struct tifm_dev, dev);
	get_device(dev);
	if (!fm_dev->drv && drv->probe && drv->id_table) {
		rc = -ENODEV;
		id = tifm_device_match(drv->id_table, fm_dev);
		if (id)
			rc = drv->probe(fm_dev);
		if (rc >= 0) {
			rc = 0;
			fm_dev->drv = drv;
		}
	}
	if (rc)
		put_device(dev);
	return rc;
}

static int tifm_device_remove(struct device *dev)
void tifm_queue_work(struct work_struct *work)
{
	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
	struct tifm_driver *drv = fm_dev->drv;

	if (drv) {
		fm_dev->signal_irq = tifm_dummy_signal_irq;
		if (drv->remove)
			drv->remove(fm_dev);
		fm_dev->drv = NULL;
	}

	put_device(dev);
	return 0;
	queue_work(workqueue, work);
}
EXPORT_SYMBOL(tifm_queue_work);

int tifm_register_driver(struct tifm_driver *drv)
{
	drv->driver.bus = &tifm_bus_type;
	drv->driver.probe = tifm_device_probe;
	drv->driver.remove = tifm_device_remove;
	drv->driver.suspend = tifm_device_suspend;
	drv->driver.resume = tifm_device_resume;

	return driver_register(&drv->driver);
}
@@ -279,13 +325,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);

static int __init tifm_init(void)
{
	int rc = bus_register(&tifm_bus_type);
	int rc;

	workqueue = create_freezeable_workqueue("tifm");
	if (!workqueue)
		return -ENOMEM;

	rc = bus_register(&tifm_bus_type);

	if (!rc) {
		rc = class_register(&tifm_adapter_class);
	if (rc)
		goto err_out_wq;

	rc = class_register(&tifm_adapter_class);
	if (!rc)
		return 0;

	bus_unregister(&tifm_bus_type);
	}

err_out_wq:
	destroy_workqueue(workqueue);

	return rc;
}
@@ -294,6 +352,7 @@ static void __exit tifm_exit(void)
{
	class_unregister(&tifm_adapter_class);
	bus_unregister(&tifm_bus_type);
	destroy_workqueue(workqueue);
}

subsys_initcall(tifm_init);
+3 −103

File changed.

Preview size limit exceeded, changes collapsed.

+6 −27
Original line number Diff line number Diff line
@@ -2,32 +2,11 @@
# Makefile for the kernel mmc device drivers.
#

#
# Core
#
obj-$(CONFIG_MMC)		+= mmc_core.o

#
# Media drivers
#
obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o

#
# Host drivers
#
obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
obj-$(CONFIG_MMC_PXA)		+= pxamci.o
obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
obj-$(CONFIG_MMC_OMAP)		+= omap.o
obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o

mmc_core-y := mmc.o mmc_sysfs.o
mmc_core-$(CONFIG_BLOCK) += mmc_queue.o

ifeq ($(CONFIG_MMC_DEBUG),y)
	EXTRA_CFLAGS		+= -DDEBUG
endif

obj-$(CONFIG_MMC)		+= core/
obj-$(CONFIG_MMC)		+= card/
obj-$(CONFIG_MMC)		+= host/
+17 −0
Original line number Diff line number Diff line
#
# MMC/SD card drivers
#

comment "MMC/SD Card Drivers"
	depends MMC

config MMC_BLOCK
	tristate "MMC block device driver"
	depends on MMC && BLOCK
	default y
	help
	  Say Y here to enable the MMC block device driver support.
	  This provides a block device driver, which you can use to
	  mount the filesystem. Almost everyone wishing MMC support
	  should say Y or M here.
Loading