* [PATCH] Add Winbond WB528SD Secure Digital (SD) card reader driver
@ 2012-01-21 10:52 Németh Márton
2012-01-21 12:51 ` Greg KH
0 siblings, 1 reply; 4+ messages in thread
From: Németh Márton @ 2012-01-21 10:52 UTC (permalink / raw)
To: Chris Ball, linux-mmc, Greg Kroah-Hartman, devel; +Cc: techeng, clyu, LKML
From: Márton Németh <nm127@freemail.hu>
This driver version of Winbond WB528SD can detect mechanical card
presence only. The information is provided through sysfs.
Signed-off-by: Márton Németh <nm127@freemail.hu>
Cc: techeng <dzshen@gmail.com>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/wb528sd/Kconfig | 16 ++
drivers/staging/wb528sd/Makefile | 1 +
drivers/staging/wb528sd/wb528sd.c | 274 +++++++++++++++++++++++++++++++++++++
5 files changed, 294 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/wb528sd/Kconfig
create mode 100644 drivers/staging/wb528sd/Makefile
create mode 100644 drivers/staging/wb528sd/wb528sd.c
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 21e2f4b..c1ce429 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -132,4 +132,6 @@ source "drivers/staging/omapdrm/Kconfig"
source "drivers/staging/android/Kconfig"
+source "drivers/staging/wb528sd/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 7c5808d..7da8c3b 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_ANDROID) += android/
+obj-$(CONFIG_WB528SD) += wb528sd/
diff --git a/drivers/staging/wb528sd/Kconfig b/drivers/staging/wb528sd/Kconfig
new file mode 100644
index 0000000..b7af426
--- /dev/null
+++ b/drivers/staging/wb528sd/Kconfig
@@ -0,0 +1,16 @@
+config WB528SD
+ tristate "Winbond 528SD Secure Digital (SD) card reader"
+ depends on PCI
+ help
+ The Winbond 528SD Secure Digital (SD) card reader connects to
+ the PCI bus and can be found in laptop Clevo model D4J, product
+ code D410J. It can be identified by its PCI ID 1050:8481
+ (for example by using "lspci" and "lspci -n" commands).
+ The driver currently only detects whether an SD card is
+ mechanically inserted in the reader (dummy SD card is also
+ detected). The information can be fetched in Clevo D410J
+ with the command
+ "cat /sys/devices/pci0000:00/0000:00:0e.0/card_present".
+
+ Currently (Jan 2012) there is a lack of register description
+ of this device.
diff --git a/drivers/staging/wb528sd/Makefile b/drivers/staging/wb528sd/Makefile
new file mode 100644
index 0000000..758026d
--- /dev/null
+++ b/drivers/staging/wb528sd/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_WB528SD) += wb528sd.o
diff --git a/drivers/staging/wb528sd/wb528sd.c b/drivers/staging/wb528sd/wb528sd.c
new file mode 100644
index 0000000..7f6380a
--- /dev/null
+++ b/drivers/staging/wb528sd/wb528sd.c
@@ -0,0 +1,274 @@
+/*
+ * Winbond 528SD Secure Digital (SD) card reader
+ *
+ * # lspci -d 1050:8481 -vv -xx
+ * 00:0e.0 Mass storage controller: Winbond Electronics Corp Device 8481 (rev 01)
+ * Subsystem: Winbond Electronics Corp Device 1050
+ * Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
+ * Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort+ <TAbort- <MAbort- >SERR- <PERR- INTx-
+ * Interrupt: pin A routed to IRQ 19
+ * Region 0: Memory at d0001000 (32-bit, non-prefetchable) [size=4K]
+ * Region 1: Memory at d0000000 (32-bit, non-prefetchable) [size=4K]
+ * Capabilities: [c0] Power Management version 2
+ * Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=100mA PME(D0-,D1+,D2+,D3hot+,D3cold+)
+ * Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME+
+ * 00: 50 10 81 84 13 00 90 0a 01 00 80 01 10 42 80 00
+ * 10: 00 10 00 d0 00 00 00 d0 00 00 00 00 00 00 00 00
+ * 20: 00 00 00 00 00 00 00 00 00 00 00 00 50 10 50 10
+ * 30: 00 00 00 00 c0 00 00 00 00 00 00 00 05 01 08 1a
+ *
+ * There are two memory mapped regions: region 0 and region 1.
+ * Region 0 has a 4KiB address window but it contains only 256 bytes
+ * of registers, the same registers repeats every 256 bytes.
+ * Region 1 truly has a 4KiB address window.
+ *
+ * There is one interrupt associated to this device.
+ *
+ * Region 0 registers:
+ * BASE0+0x00: ?
+ * ...
+ * BASE0+0xFF: ?
+ *
+ * Region 1 registers:
+ * BASE1+0x000: ?
+ * ...
+ * BASE1+0x51C: bit7: ?
+ * bit6: ?
+ * bit5: ?
+ * bit4: ?
+ * bit3: ?
+ * bit2: ?
+ * bit1: ?
+ * bit0: mechanical card persence (dummy card is also detected)
+ * 0: card not present
+ * 1: card present
+ * ...
+ * BASE1+0xFFF: ?
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
+MODULE_DESCRIPTION("Winbond 528SD Secure Digital (SD) card reader");
+MODULE_LICENSE("GPL");
+
+#define PCI_DEVICE_ID_WINBOND_528SD 0x8481
+
+#define WB528SD_REG_STATUS_51C 0x51C
+#define WB528SD_CARD_PRESENCE_MASK 0x01
+
+#define WB528SD_SIZE_4K 0x1000
+
+struct wb528sd_data {
+ void __iomem *ioaddr0;
+ void __iomem *ioaddr1;
+};
+
+static ssize_t card_present_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct wb528sd_data *data = dev_get_drvdata(dev);
+ unsigned int data51c;
+
+ data51c = ioread8(data->ioaddr1 + WB528SD_REG_STATUS_51C);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ data51c & WB528SD_CARD_PRESENCE_MASK ? 1 : 0);
+}
+static DEVICE_ATTR(card_present, S_IRUGO, card_present_show, NULL);
+
+static irqreturn_t wb528sd_handler(int irq, void *dev_id)
+{
+#if 0
+ struct pci_dev *dev = dev_id;
+ struct wb528sd_data *data = pci_get_drvdata(dev);
+#endif
+ int ret = IRQ_NONE;
+
+ if (0) {
+ /* TODO: find out how to detect if wb528sd is the source
+ * of the interrupt. Note that the interrupt might be
+ * shared with other hardware devices.
+ */
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+#if 0
+static void dump_content(char *name, void __iomem *base, unsigned long length)
+{
+ unsigned int i;
+ unsigned int data;
+
+ for (i = 0; i < length; i += 4) {
+ data = ioread32(base + i);
+ printk(KERN_DEBUG "%s+0x%X: 0x%X\n", name, i, data);
+ }
+}
+#endif
+
+static int probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned long addr0_start, addr0_end, addr0_len, addr0_flags;
+ unsigned long addr1_start, addr1_end, addr1_len, addr1_flags;
+ void __iomem *ioaddr0;
+ void __iomem *ioaddr1;
+ int result;
+ u8 irq;
+ struct wb528sd_data *data = NULL;
+ int ret;
+
+ addr0_start = pci_resource_start(dev, 0);
+ addr0_end = pci_resource_end(dev, 0);
+ addr0_len = pci_resource_len(dev, 0);
+ addr0_flags = pci_resource_flags(dev, 0);
+ printk(KERN_DEBUG "Resource 0: 0x%lX..0x%lX, length=0x%lX, flags=0x%lX\n",
+ addr0_start, addr0_end, addr0_len, addr0_flags);
+
+ addr1_start = pci_resource_start(dev, 1);
+ addr1_end = pci_resource_end(dev, 1);
+ addr1_len = pci_resource_len(dev, 1);
+ addr1_flags = pci_resource_flags(dev, 1);
+ printk(KERN_DEBUG "Resource 1: 0x%lX..0x%lX, length=0x%lX, flags=0x%lX\n",
+ addr1_start, addr1_end, addr1_len, addr1_flags);
+
+ printk(KERN_DEBUG "dev->irq: IRQ #%u\n", dev->irq);
+
+ result = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ if (!result)
+ printk(KERN_DEBUG "PCI_INTERRUPT_LINE: IRQ #%u\n", irq);
+ else
+ printk(KERN_DEBUG "Can't read PCI_INTERRUPT_LINE\n");
+
+ if (!(addr0_flags & IORESOURCE_MEM)) {
+ dev_err(&dev->dev, "region #0 not an MMIO resource, aborting\n");
+ return -ENODEV;
+ }
+ if (addr0_len != WB528SD_SIZE_4K) {
+ dev_err(&dev->dev, "Invalid PCI mem region size, aborting\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&dev->dev, "%s : kzalloc failed", __func__);
+ return -ENOMEM;
+ }
+
+ printk(KERN_DEBUG "pci_enable_device()\n");
+ result = pci_enable_device(dev);
+ if (result) {
+ printk(KERN_DEBUG "Error enabling wb528sd PCI device: %u\n",
+ result);
+ kfree(data);
+ return result;
+ }
+
+ printk(KERN_DEBUG "pci_request_regions()\n");
+ result = pci_request_regions(dev, KBUILD_MODNAME);
+ if (result) {
+ printk(KERN_DEBUG "pci_request_regions failed, error %d\n",
+ result);
+ pci_disable_device(dev);
+ kfree(data);
+ return result;
+ }
+
+ ioaddr0 = pci_iomap(dev, 0, 0);
+ if (!ioaddr0) {
+ printk(KERN_DEBUG "cannot remap MMIO #0\n");
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(data);
+ return result;
+ } else {
+ data->ioaddr0 = ioaddr0;
+ }
+
+ ioaddr1 = pci_iomap(dev, 1, 0);
+ if (!ioaddr1) {
+ printk(KERN_DEBUG "cannot remap MMIO #1\n");
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(data);
+ return result;
+ } else {
+ data->ioaddr1 = ioaddr1;
+ }
+
+ printk(KERN_DEBUG "request_irq()\n");
+ result = request_irq(dev->irq, wb528sd_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (result != 0) {
+ printk(KERN_DEBUG "Error requesting IRQ #%u device: %d\n",
+ dev->irq, result);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(data);
+ return result;
+ }
+
+ /* TODO: enable wb528sd interrupt generation */
+
+ pci_set_drvdata(dev, data);
+
+ ret = device_create_file(&dev->dev, &dev_attr_card_present);
+ if (!ret)
+ ;
+
+ printk(KERN_DEBUG "done\n");
+
+ return 0;
+}
+
+static void remove(struct pci_dev *dev)
+{
+ struct wb528sd_data *data = pci_get_drvdata(dev);
+
+ printk(KERN_DEBUG "%s: remove\n", KBUILD_MODNAME);
+
+ device_remove_file(&dev->dev, &dev_attr_card_present);
+ pci_disable_device(dev);
+ pci_release_regions(dev);
+ if (data) {
+ pci_iounmap(dev, data->ioaddr0);
+ pci_iounmap(dev, data->ioaddr1);
+ }
+ free_irq(dev->irq, dev);
+
+}
+
+static DEFINE_PCI_DEVICE_TABLE(wb528sd_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND_528SD) },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, wb528sd_ids);
+
+static struct pci_driver pci_driver = {
+ .name = "wb528sd",
+ .id_table = wb528sd_ids,
+ .probe = probe,
+ .remove = remove,
+};
+
+static int __init wb528sd_init(void)
+{
+ printk(KERN_DEBUG "%s: init\n", KBUILD_MODNAME);
+ return pci_register_driver(&pci_driver);
+}
+
+static void wb528sd_exit(void)
+{
+ printk(KERN_DEBUG "%s: exit\n", KBUILD_MODNAME);
+ pci_unregister_driver(&pci_driver);
+}
+
+module_init(wb528sd_init);
+module_exit(wb528sd_exit);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] Add Winbond WB528SD Secure Digital (SD) card reader driver
2012-01-21 10:52 [PATCH] Add Winbond WB528SD Secure Digital (SD) card reader driver Németh Márton
@ 2012-01-21 12:51 ` Greg KH
2012-01-21 14:54 ` Németh Márton
0 siblings, 1 reply; 4+ messages in thread
From: Greg KH @ 2012-01-21 12:51 UTC (permalink / raw)
To: Németh Márton; +Cc: Chris Ball, linux-mmc, devel, techeng, clyu, LKML
On Sat, Jan 21, 2012 at 11:52:37AM +0100, Németh Márton wrote:
> From: Márton Németh <nm127@freemail.hu>
>
> This driver version of Winbond WB528SD can detect mechanical card
> presence only. The information is provided through sysfs.
How is it provided through sysfs? Is this done in a standard way? If
not, why not?
Why is this driver submitted to the staging tree? What is keeping it
from going into the "real" portion of the kernel for other card readers?
We need a TODO file for what is needed to get it moved out of staging.
Oh, and it needs to do a bit more than just detect a card to be useful,
right? How about read/write to it?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add Winbond WB528SD Secure Digital (SD) card reader driver
2012-01-21 12:51 ` Greg KH
@ 2012-01-21 14:54 ` Németh Márton
2012-01-21 15:02 ` Greg KH
0 siblings, 1 reply; 4+ messages in thread
From: Németh Márton @ 2012-01-21 14:54 UTC (permalink / raw)
To: Greg KH; +Cc: Chris Ball, linux-mmc, devel, techeng, clyu, LKML
Hi Greg,
thanks for your response and your questions, I think it will help my
work very much.
Greg KH wrote:
> On Sat, Jan 21, 2012 at 11:52:37AM +0100, Németh Márton wrote:
>> From: Márton Németh <nm127@freemail.hu>
>>
>> This driver version of Winbond WB528SD can detect mechanical card
>> presence only. The information is provided through sysfs.
>
> How is it provided through sysfs? Is this done in a standard way? If
> not, why not?
I used device_create_file()/device_remove_file() and DEVICE_ATTR(), in
that sense it is standard. I'm not sure, however, that you a referring
to this, rather referring to the standard way how other SD card readers
provide the card presence information to the user space, right?
To tell you the truth, I could not find an other PCI card driver which
I can take as an example, I would need some help on this.
> Why is this driver submitted to the staging tree? What is keeping it
> from going into the "real" portion of the kernel for other card readers?
Interrupt handling, read, write and connecting the driver upwards to the
block subsystem, I guess.
> We need a TODO file for what is needed to get it moved out of staging.
I can create one, no problem.
> Oh, and it needs to do a bit more than just detect a card to be useful,
> right? How about read/write to it?
Sure. My intention was to get feedback for my work as early as possible.
I reached a state where a minimal level of functionality is available:
the mechanical SD card presence is available for userspace programs.
The read/write access will be a bit more difficult, I guess because I
currently don't have access to the register programming reference of
this device, I can use the trial-and-error method, for example.
Márton Németh
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add Winbond WB528SD Secure Digital (SD) card reader driver
2012-01-21 14:54 ` Németh Márton
@ 2012-01-21 15:02 ` Greg KH
0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2012-01-21 15:02 UTC (permalink / raw)
To: Németh Márton; +Cc: Chris Ball, linux-mmc, devel, techeng, clyu, LKML
On Sat, Jan 21, 2012 at 03:54:13PM +0100, Németh Márton wrote:
> Hi Greg,
>
> thanks for your response and your questions, I think it will help my
> work very much.
>
> Greg KH wrote:
> > On Sat, Jan 21, 2012 at 11:52:37AM +0100, Németh Márton wrote:
> >> From: Márton Németh <nm127@freemail.hu>
> >>
> >> This driver version of Winbond WB528SD can detect mechanical card
> >> presence only. The information is provided through sysfs.
> >
> > How is it provided through sysfs? Is this done in a standard way? If
> > not, why not?
>
> I used device_create_file()/device_remove_file() and DEVICE_ATTR(), in
> that sense it is standard. I'm not sure, however, that you a referring
> to this, rather referring to the standard way how other SD card readers
> provide the card presence information to the user space, right?
Yes, the latter is what matters.
> To tell you the truth, I could not find an other PCI card driver which
> I can take as an example, I would need some help on this.
I don't think that any other device does this, as it properly hooks up
the block device for the card inserted, which generates the needed
userspace notifications.
So please don't create a non-standard way of determining if a card is
present or not, you are creating a kernel/user API here that needs to be
preserved if it gets into the kernel tree.
> > Why is this driver submitted to the staging tree? What is keeping it
> > from going into the "real" portion of the kernel for other card readers?
>
> Interrupt handling, read, write and connecting the driver upwards to the
> block subsystem, I guess.
>
> > We need a TODO file for what is needed to get it moved out of staging.
>
> I can create one, no problem.
>
> > Oh, and it needs to do a bit more than just detect a card to be useful,
> > right? How about read/write to it?
>
> Sure. My intention was to get feedback for my work as early as possible.
> I reached a state where a minimal level of functionality is available:
> the mechanical SD card presence is available for userspace programs.
What could a userspace program do with this information?
> The read/write access will be a bit more difficult, I guess because I
> currently don't have access to the register programming reference of
> this device, I can use the trial-and-error method, for example.
Yeah, doing this type of work is hard, and I understand your want to get
it into the tree at this early stage. However, we really need something
that actually works, otherwise people are going to be very confused when
they see their device bound to this driver, yet nothing works.
So I think we need to wait until it can handle the block device handling
logic first, before we can add it to the kernel tree, even in the
staging directory.
Good luck with this effort, it is not easy at all.
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-01-21 15:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-21 10:52 [PATCH] Add Winbond WB528SD Secure Digital (SD) card reader driver Németh Márton
2012-01-21 12:51 ` Greg KH
2012-01-21 14:54 ` Németh Márton
2012-01-21 15:02 ` Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).