logo       


Choosing A Webhost:
A web hosting service is a type of Internet hosting service that allows individuals and organizations to provide their own website accessible via the World Wide Web. Web hosts are companies that provide space on a server they own for use by their clients as well as providing Internet connectivity, typically in a data center. Web hosts can also provide data center space and connectivity to the Internet for servers they do not own to be located in their data center, called colocation. more...

[FEISTY]: [PATCH 1/3] UBUNTU: Update tifm driver to 0.8d: msg#00005

Subject: [FEISTY]: [PATCH 1/3] UBUNTU: Update tifm driver to 0.8d
>From 6bec583645852716f3fee4a7d2534be1acf060d6 Mon Sep 17 00:00:00 2001
From: Phillip Lougher <phillip@xxxxxxxxxx>
Date: Tue, 1 May 2007 19:39:09 +0100
Subject: [PATCH 1/3] UBUNTU: Update tifm driver to 0.8d
Bug: 53923

Signed-off-by: Phillip lougher <phillip@xxxxxxxxxx>
---
 drivers/misc/tifm_7xx1.c   |  340 +++++++---------
 drivers/misc/tifm_core.c   |  308 +++++++++------
 drivers/mmc/host/tifm_sd.c |  976 +++++++++++++++++++++++++-------------------
 include/linux/tifm.h       |   91 +++--
 4 files changed, 938 insertions(+), 777 deletions(-)

diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index bc60e2f..3ede4c5 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -10,11 +10,22 @@
  */
 
 #include <linux/tifm.h>
+#include <linux/pci_ids.h>
 #include <linux/dma-mapping.h>
-#include <linux/freezer.h>
 
 #define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8d"
+
+#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 +33,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 +41,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);
@@ -44,13 +54,13 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
                writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
 
                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);
+                       sock = fm->sockets[cnt].dev;
+                       if (sock) {
+                               if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1))
+                                       sock->data_event(sock);
+                               if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1))
+                                       sock->event(sock);
+                       }
                }
 
                fm->socket_change_set |= irq_status
@@ -58,57 +68,58 @@ 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 caps)
 {
        unsigned int s_state;
        int cnt;
 
        writel(0x0e00, sock_addr + SOCK_CONTROL);
 
-       for (cnt = 0; cnt < 100; cnt++) {
+       /* half a second should be enough  */
+       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
+       writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
+              sock_addr + SOCK_CONTROL);
+
+       if (caps & TIFM_SOCK_XD_CAP) {
                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);
        }
+       writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+       msleep(10);
 
-       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);
        }
 
-       if (!is_x2)
-               writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
-                      sock_addr + SOCK_CONTROL);
+       writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
+              sock_addr + SOCK_CONTROL);
 
        return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
 }
@@ -119,127 +130,78 @@ 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;
+       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",
-                       socket_change_set);
+       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)
+       for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+               if (!(socket_change_set & (1 << cnt)))
                        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);
-                               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)
-                                      + SOCK_CONTROL);
-                       }
-                       if (kthread_should_stop())
-                               continue;
-
+               sock = fm->sockets[cnt].dev;
+               if (sock) {
+                       printk(KERN_INFO
+                              "%s : demand removing card from socket %u:%u\n",
+                              fm->cdev.class_id, fm->id, cnt);
+                       fm->sockets[cnt].dev = NULL;
                        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);
-                               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);
-                                       if (!device_register(&sock->dev)) {
-                                               spin_lock_irqsave(&fm->lock, 
flags);
-                                               if (!fm->sockets[cnt]) {
-                                                       fm->sockets[cnt] = sock;
-                                                       sock = NULL;
-                                               }
-                                               
spin_unlock_irqrestore(&fm->lock, flags);
-                                       }
-                                       if (sock)
-                                               tifm_free_device(&sock->dev);
-                               }
-                               spin_lock_irqsave(&fm->lock, flags);
-                       }
+                       device_unregister(&sock->dev);
+                       spin_lock_irqsave(&fm->lock, flags);
+                       writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
+                              + SOCK_CONTROL);
                }
 
-               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 {
+               spin_unlock_irqrestore(&fm->lock, flags);
+
+               media_id = tifm_7xx1_toggle_sock_power(
+                               tifm_7xx1_sock_addr(fm->addr, cnt),
+                               fm->sockets[cnt].caps);
+
+               // 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);
+
+                       if (!device_register(&sock->dev)) {
+                               spin_lock_irqsave(&fm->lock, flags);
+                               if (!fm->sockets[cnt].dev) {
+                                       fm->sockets[cnt].dev = sock;
+                                       sock = NULL;
+                               }
                                spin_unlock_irqrestore(&fm->lock, flags);
                        }
+                       if (sock)
+                               tifm_free_device(&sock->dev);
                }
+               spin_lock_irqsave(&fm->lock, flags);
        }
-       return 0;
+
+       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);
 }
 
 #ifdef CONFIG_PM
@@ -258,9 +220,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 +235,50 @@ 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),
+                                       fm->sockets[rc].caps);
        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].dev) {
+                       if (fm->sockets[rc].dev->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 {
-               fm->socket_change_set = 0;
+       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 +314,26 @@ 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;
+       switch (fm->num_sockets) {
+       case 2:
+               fm->sockets[0].caps |= TIFM_SOCK_MS_PIF;
+               break;
+       case 4:
+               fm->sockets[0].caps |= TIFM_SOCK_XD_CAP;
+               fm->sockets[1].caps |= TIFM_SOCK_XD_CAP;
+               fm->sockets[2].caps |= TIFM_SOCK_XD_CAP | TIFM_SOCK_MS_PIF;
+               fm->sockets[3].caps |= TIFM_SOCK_XD_CAP;
+               break;
+       }
 
+       INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
        fm->eject = tifm_7xx1_eject;
        pci_set_drvdata(dev, fm);
 
@@ -367,19 +342,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 +373,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);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 6b10ebe..404b5b4 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,71 +14,124 @@
 #include <linux/idr.h>
 
 #define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8d"
 
+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++;
-       }
-       return NULL;
+       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;
-
-       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))
+       if (sock->type == id->type)
                return 1;
-       return -ENODEV;
+       return 0;
+}
+
+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;
+                       ++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->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,19 +142,33 @@ 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,
-       .uevent  = tifm_uevent,
-       .suspend = tifm_device_suspend,
-       .resume  = tifm_device_resume
+       .name           = "tifm",
+       .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
 };
 
 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 socket_t) * 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,81 @@ 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;
        }
-       return rc;
+
+       return 0;
 }
 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].dev)
+                       device_unregister(&fm->sockets[cnt].dev->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->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 +304,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)
+void tifm_queue_work(struct work_struct *work)
 {
-       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)
-{
-       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 +326,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);
 
 static int __init tifm_init(void)
 {
-       int rc = bus_register(&tifm_bus_type);
+       int rc;
 
-       if (!rc) {
-               rc = class_register(&tifm_adapter_class);
-               if (rc)
-                       bus_unregister(&tifm_bus_type);
-       }
+       workqueue = create_freezeable_workqueue("tifm");
+       if (!workqueue)
+               return -ENOMEM;
+
+       rc = bus_register(&tifm_bus_type);
+
+       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 +353,7 @@ static void __exit tifm_exit(void)
 {
        class_unregister(&tifm_adapter_class);
        bus_unregister(&tifm_bus_type);
+       destroy_workqueue(workqueue);
 }
 
 subsys_initcall(tifm_init);



Ruby Jobs
Java Jobs
Jobs in California
more...
what
job title, keywords
where
city, state, zip
jobs by job search
<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

Recently Viewed:
db.firebase.por...    text.xml.xalan....    qnx.openqnx.dev...    user-groups.zar...    internationaliz...    kde.devel.konve...    finance.e-gold....    emacs.latex.pre...    gis.therion/200...    web.webmin.gene...    yellowdog.gener...    vserver/2003-08...    redhat.release....    sysutils.tivoli...    xfree86.expert/...    mail.becky.user...    hardware.netapp...    netbsd.ports.xe...    python.distutil...    boot-loaders.gr...    culture.interne...    java.springfram...    activedir/2006-...   
Home | blog view | USPTO Patent Archive | advertise | OSDir is an inevitable website. super tiny logo

Free Magazines

Cisco News
Receive a free quarterly e-newsletter with exclusive articles on how Cisco IT uses its own products and solutions to enable the business.
subscribe

Systems Management News, the newspaper for IT systems administration and data center managers! Each issue of Systems Management News is chock-full of news and analysis to help you understand what's happening in your field.
subscribe

The Enterprise Newsweekly eWeek is the essential technology information source for builders of e-business.
subscribe

Oracle Magazine Oracle Magazine contains technology strategy articles, sample code, tips, Oracle and partner news, how to articles for developers and DBAs, and more. Oracle (NASDAQ: ORCL) is the world's largest enterprise software company.
subscribe

Total Telecom Total Telecom is "The Economist of the communications industry".
subscribe