pcmcia: export pcmcia_bus_type
PATCH 1/1 pcmcia: export pcmcia_bus_type
Export pcmcia_bus_type so modules can register bus notifiers.
drivers/pcmcia/ds.c +1 -0
@@ -1515,6 +1515,7 @@ struct bus_type pcmcia_bus_type = { .suspend = pcmcia_dev_suspend, .resume = pcmcia_dev_resume, }; +EXPORT_SYMBOL (pcmcia_bus_type);static int __init init_pcmcia_bus (void )
PATCH v2 1/1 pcmcia: export pcmcia_bus_type
Export pcmcia_bus_type so module-based drivers can register bus notifiers, and add it to what seems to be the main include file.
---
Missed the include file in the last patch.
drivers/pcmcia/ds.c +1 -0
@@ -1404,6 +1404,7 @@ struct bus_type pcmcia_bus_type = { .suspend = pcmcia_dev_suspend, .resume = pcmcia_dev_resume, }; +EXPORT_SYMBOL (pcmcia_bus_type);static int __init init_pcmcia_bus (void )
include/pcmcia/ss.h +1 -0
@@ -298,6 +298,7 @@ extern int pcmcia_register_socket(structextern void pcmcia_unregister_socket (struct pcmcia_socket *socket);extern struct class pcmcia_socket_class; +extern struct bus_type pcmcia_bus_type;/* socket drivers are expected to use these callbacks in their .drv struct */ extern int pcmcia_socket_dev_suspend (struct device *dev,pm_message_t state);
Quoted 2 lines · Olof Johansson
Export
pcmcia_bus_typeso module-based drivers can register bus notifiers, and add it to what seems to be the main include file.
This all sounds rather fishy to me. Care to send the code along that makes use of it.
And even if we're going to add the export it should be _GPL because it's a deeply internal implementation detail. Then again I'm not exactly convinced we should export it yet.
Hi,
Quoted 6 lines · Christoph Hellwig
Quoted 2 lines · Olof Johansson
Export
pcmcia_bus_typeso module-based drivers can register bus notifiers, and add it to what seems to be the main include file.This all sounds rather fishy to me. Care to send the code along that makes use of it.
Sure. I was planning on sending the code that uses this on Friday but ran out of time. Also, given the other discussions regarding I/O space and mappings, I need to rework it so I ended up holding back until I had time to do that.
I use the notifier hooks to fix up the ->archdata.dma_ops for the devices added. Maybe there's an easier way to do it that I'm missing.
Current patch included below, note that it's not not 100% cleaned up.
Quoted 3 lines
And even if we're going to add the export it should be
_GPLbecause it's a deeply internal implementation detail. Then again I'm not exactly convinced we should export it yet.
Other buses already export it (i.e. PCI). Also, other symbols in the drivers were exported non-_GPL so I went with that. I'll be happy to switch to the other kind of export if needed. Seems like PCI exports it non-_GPL as well.
-Olof
Driver for the CompactFlash slot on the PA Semi Electra eval board. It's a simple device sitting on localbus, with interrupts and detect/voltage control over GPIO.
The driver is implemented as an of_platform driver, and adds localbus as a bus being probed by the of_platform framework.
---
This patch depends on the PCMCIA pcmcia_bus_type export to compile:
http://lists.infradead.org/pipermail/linux-pcmcia/2007-May/004613.html
and on the ioaddr_t + ioport_map changes to work at runtime:
http://patchwork.ozlabs.org/linuxppc/patch?id=11092
http://patchwork.ozlabs.org/linuxppc/patch?id=11093
drivers/pcmcia/Kconfig +7 -0
@@ -270,6 +270,13 @@ config AT91_CF Say Y here to support the CompactFlash controller on AT91 chips. Or choose M to compile the driver as a module named "at91_cf". +config ELECTRA_CF + tristate "Electra CompactFlash Controller" + depends on PCMCIA && PPC_PASEMI + help + Say Y here to support the CompactFlash controller on the + PA Semi Electra eval board. + config PCCARD_NONSTATIC tristate
drivers/pcmcia/Makefile +1 -0
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4171) += vrc417 obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o obj-$(CONFIG_OMAP_CF) += omap_cf.o obj-$(CONFIG_AT91_CF) += at91_cf.o +obj-$(CONFIG_ELECTRA_CF) += electra_cf.o sa11xx_core-y += soc_common.o sa11xx_base.o pxa2xx_core-y += soc_common.o pxa2xx_base.o
drivers/pcmcia/electra_cf.c new file +393 -0
393 lines not on this page · raw message
arch/powerpc/platforms/pasemi/setup.c +1 -0
@@ -245,6 +245,7 @@ static void __init pas_init_early(void) }static struct of_device_id pasemi_bus_ids[] = { + { .type ="localbus" , }, { .type ="sdc" , }, {}, };
Some random review comments on your driver, while I was passing. Spotted a few things.
drivers/pcmcia/electra_cf.c line 27
Quoted 5 lines · Olof Johansson
drivers/pcmcia/electra_cf.c new file +5
-0+#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/platform_device.h> +#include <linux/platform_device.h>
Silly duplicate includes.
Quoted 6 lines
drivers/pcmcia/electra_cf.c new file +6
-0+#include <linux/errno.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <pcmcia/ss.h>
drivers/pcmcia/electra_cf.c line 103
Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +9
-0+#include <asm/of_platform.h> + +static const char driver_name[] ="electra-cf" ; +static int electra_cf_get_status (struct pcmcia_socket *s,u_int *sp) +{ +struct electra_cf_socket *cf; + +if (!sp) +return -EINVAL ;
Never called with a NULL argument, so useless check.
Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10
-0+ + cf = container_of(s, struct electra_cf_socket, socket); + +/* NOTE CF is always 3VCARD */ +if (electra_cf_present (cf)) { +struct electra_cf_socket *cf; + + *sp =SS_READY |SS_DETECT |SS_POWERON |SS_3VCARD ; + cf = container_of(s, struct electra_cf_socket, socket); + s->pci_irq = cf->irq;
drivers/pcmcia/electra_cf.c line 157
Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +9
-0+ }else + *sp =0 ; +return 0 ; +} +static int electra_cf_ss_suspend (struct pcmcia_socket *s) +{ +pr_debug ("%s: %s\n" , driver_name, __FUNCTION__); +return electra_cf_set_socket (s, &dead_socket); +}
That's already done for you. Remove this function entirely and set the ".suspend" method to NULL.
drivers/pcmcia/electra_cf.c line 169
Quoted 11 lines
drivers/pcmcia/electra_cf.c new file +11
-0+static int electra_cf_set_io_map (struct pcmcia_socket *s, +struct pccard_io_map *io) +{ +struct electra_cf_socket *cf; + + cf = container_of(s, struct electra_cf_socket, socket); + io->flags &=MAP_ACTIVE |MAP_ATTRIB |MAP_16BIT ; + io->start = (unsigned long )cf->io_base; + io->stop = (unsigned long )cf->io_base +0x800 -1 ; +return 0 ; +}
PCMCIA code will ignore your writes to 'io'. Therefore, does this do anything useful? If not, an empty function will do.
Quoted 81 lines
...
drivers/pcmcia/electra_cf.c new file +80
-0+static int __devinit electra_cf_probe (struct of_device *ofdev, +const struct of_device_id *match) +{ +struct device *device = &ofdev->dev; +struct device_node *np = ofdev->node; +struct electra_cf_socket *cf; +struct resource mem, io; +int status; +const unsigned int *prop; +int err; + + err =of_address_to_resource (np,0 , &mem); +if (err) +return -EINVAL ; + + err =of_address_to_resource (np,1 , &io); +if (err) +return -EINVAL ; + + cf =kzalloc (sizeof *cf,GFP_KERNEL ); +if (!cf) +return -ENOMEM ; + +init_timer (&cf->timer); + cf->timer.function = electra_cf_timer; + cf->timer.data = (unsigned long ) cf; + + cf->ofdev = ofdev; + cf->mem_phys = mem.start; + cf->mem_base =ioremap (mem.start, mem.end - mem.start); + cf->io_base =ioremap (io.start, io.end - io.start); + cf->gpio_base =ioremap (0xfc103000 ,0x1000 ); +dev_set_drvdata (device, cf); + +if (!cf->mem_base || !cf->io_base || !cf->gpio_base) { +dev_err (device,"can't ioremap ranges\n" ); + status = -ENOMEM ; + goto fail1; + } + + cf->iomem.start = (unsigned long )cf->io_base; + cf->iomem.end = (unsigned long )cf->io_base + (io.end - io.start); + cf->iomem.flags =IORESOURCE_MEM ; + + cf->irq =irq_of_parse_and_map (np,0 ); + + status =request_irq (cf->irq, electra_cf_irq,IRQF_SHARED , + driver_name, cf); +if (status <0 ) { +dev_err (device,"request_irq failed\n" ); + goto fail1; + } + + cf->socket.pci_irq = cf->irq; + + prop =get_property (np,"card-detect-gpio" ,NULL ); + cf->gpio_detect = *prop; + prop =get_property (np,"card-vsense-gpio" ,NULL ); + cf->gpio_vsense = *prop; + prop =get_property (np,"card-3v-gpio" ,NULL ); + cf->gpio_3v = *prop; + prop =get_property (np,"card-5v-gpio" ,NULL ); + cf->gpio_5v = *prop; + +/* pcmcia layer only remaps "real" memory not iospace */ + cf->socket.io_offset = (unsigned long )cf->io_base; + +/* reserve chip-select regions */ +if (!request_mem_region (mem.start, mem.end +1 - mem.start, + driver_name)) { + status = -ENXIO ; +dev_err (device,"Can't claim memory region\n" ); + goto fail1; + } + +if (!request_mem_region (io.start, io.end +1 - io.start, + driver_name)) { + status = -ENXIO ; +dev_err (device,"Can't claim I/O region\n" ); + goto fail2;
drivers/pcmcia/electra_cf.c line 284
Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10
-0+ } + + cf->socket.owner =THIS_MODULE ; + cf->socket.dev.parent = &ofdev->dev; + cf->socket.ops = &electra_cf_ops; + cf->socket.resource_ops = &pccard_static_ops; + cf->socket.features =SS_CAP_PCCARD |SS_CAP_STATIC_MAP | +SS_CAP_MEM_ALIGN ; + cf->socket.map_size =0x800 ; + cf->socket.io[0 ].res = &cf->iomem;
Not a good idea - PCMCIA manages this resources itself and will free it when the card is removed. Use ss_cap_static_map and socket.io_offset.
Quoted 32 lines
drivers/pcmcia/electra_cf.c new file +32
-0+ + status =pcmcia_register_socket (&cf->socket); +if (status <0 ) { +dev_err (device,"pcmcia_register_socket failed\n" ); + goto fail3; + } + +dev_info (device,"at mem 0x%lx io 0x%lx irq %d\n" , + mem.start, io.start, cf->irq); + + cf->active =1 ; +electra_cf_timer ((unsigned long )cf); +return 0 ; + +fail3: +release_mem_region (io.start, io.end +1 - io.start); +fail2: +release_mem_region (mem.start, mem.end +1 - mem.start); +fail1: +if (cf->io_base) +iounmap (cf->io_base); +if (cf->mem_base) +iounmap (cf->mem_base); +if (cf->gpio_base) +iounmap (cf->gpio_base); +device_init_wakeup (&ofdev->dev,0 ); +kfree (cf); +return status; + +} + +static int __devexit electra_cf_remove(struct of_device *ofdev)
drivers/pcmcia/electra_cf.c line 326
Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +10
-0+{ +struct device *device = &ofdev->dev; +struct electra_cf_socket *cf; + + cf =dev_get_drvdata (device); + + cf->active =0 ; +pcmcia_unregister_socket (&cf->socket); +del_timer_sync (&cf->timer); +free_irq (cf->irq, cf);
What if an IRQ occurs after the timer has been deleted? Doesn't the interrupt handler re-add the timer back?
Quoted 11 lines
drivers/pcmcia/electra_cf.c new file +11
-0+ +iounmap (cf->io_base); +iounmap (cf->mem_base); +iounmap (cf->gpio_base); +release_mem_region (cf->mem_phys, cf->mem_size); +release_region (cf->io_phys, cf->io_size); + +kfree (cf); + +return 0 ; +}
Signature · 3 lines
Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of:
Hi,
Quoted 2 lines · Russell King
Some random review comments on your driver, while I was passing. Spotted a few things.
Thanks, I appreciate the feedback.
Quoted 8 lines · Olof Johansson
drivers/pcmcia/electra_cf.c line 27
Quoted 5 lines
drivers/pcmcia/electra_cf.c new file +5
-0+#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/platform_device.h> +#include <linux/platform_device.h> Silly duplicate includes.
Silly indeed.
Quoted 10 lines
Quoted 10 lines
drivers/pcmcia/electra_cf.c new file +9
-0+#include <linux/errno.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <pcmcia/ss.h> +#include <asm/of_platform.h> + +static const char driver_name[] ="electra-cf" ;
Quoted 8 lines
drivers/pcmcia/electra_cf.c line 103
Quoted 6 lines
drivers/pcmcia/electra_cf.c new file +6
-0+static int electra_cf_get_status (struct pcmcia_socket *s,u_int *sp) +{ +struct electra_cf_socket *cf; + +if (!sp) +return -EINVAL ;Never called with a NULL argument, so useless check.
Ok. Carried over from omap_cf, but I'll definitely fix it here.
Quoted 15 lines
Quoted 15 lines
drivers/pcmcia/electra_cf.c new file +14
-0+ + cf = container_of(s, struct electra_cf_socket, socket); + +/* NOTE CF is always 3VCARD */ +if (electra_cf_present (cf)) { +struct electra_cf_socket *cf; + + *sp =SS_READY |SS_DETECT |SS_POWERON |SS_3VCARD ; + cf = container_of(s, struct electra_cf_socket, socket); + s->pci_irq = cf->irq; + }else + *sp =0 ; +return 0 ; +}
Quoted 8 lines
drivers/pcmcia/electra_cf.c line 157
Quoted 5 lines
drivers/pcmcia/electra_cf.c new file +5
-0+static int electra_cf_ss_suspend (struct pcmcia_socket *s) +{ +pr_debug ("%s: %s\n" , driver_name, __FUNCTION__); +return electra_cf_set_socket (s, &dead_socket); +}That's already done for you. Remove this function entirely and set the ".suspend" method to NULL.
Thanks, will do.
Quoted 15 lines
drivers/pcmcia/electra_cf.c line 169
Quoted 12 lines
drivers/pcmcia/electra_cf.c new file +11
-0+static int electra_cf_set_io_map (struct pcmcia_socket *s, +struct pccard_io_map *io) +{ +struct electra_cf_socket *cf; + + cf = container_of(s, struct electra_cf_socket, socket); + io->flags &=MAP_ACTIVE |MAP_ATTRIB |MAP_16BIT ; + io->start = (unsigned long )cf->io_base; + io->stop = (unsigned long )cf->io_base +0x800 -1 ; +return 0 ; +}PCMCIA code will ignore your writes to 'io'. Therefore, does this do anything useful? If not, an empty function will do.
Not sure if it does, it came over from omap_cf with some modifications by me. I'll take a closer look when I rework the rest of the I/O mapping stuff.
Quoted 11 lines
drivers/pcmcia/electra_cf.c line 284
Quoted 8 lines
drivers/pcmcia/electra_cf.c new file +8
-0+ cf->socket.owner =THIS_MODULE ; + cf->socket.dev.parent = &ofdev->dev; + cf->socket.ops = &electra_cf_ops; + cf->socket.resource_ops = &pccard_static_ops; + cf->socket.features =SS_CAP_PCCARD |SS_CAP_STATIC_MAP | +SS_CAP_MEM_ALIGN ; + cf->socket.map_size =0x800 ; + cf->socket.io[0 ].res = &cf->iomem;Not a good idea - PCMCIA manages this resources itself and will free it when the card is removed. Use
ss_cap_static_mapand socket.io_offset.
Right, I'm going to rework those parts alltogether.
Quoted 6 lines
Quoted 6 lines
drivers/pcmcia/electra_cf.c new file +6
-0+static int __devexit electra_cf_remove(struct of_device *ofdev) +{ +struct device *device = &ofdev->dev; +struct electra_cf_socket *cf; + + cf =dev_get_drvdata (device);
Quoted 8 lines
drivers/pcmcia/electra_cf.c line 326
Quoted 5 lines
drivers/pcmcia/electra_cf.c new file +5
-0+ + cf->active =0 ; +pcmcia_unregister_socket (&cf->socket); +del_timer_sync (&cf->timer); +free_irq (cf->irq, cf);What if an IRQ occurs after the timer has been deleted? Doesn't the interrupt handler re-add the timer back?
Ah, yes, good point.
Thanks,
-Olof
PATCH v3 1/1 pcmcia: export pcmcia_bus_type (GPL-only)
In reply to Olof JohanssonExport pcmcia_bus_type so module-based drivers can register bus notifiers.
drivers/pcmcia/ds.c +1 -0
@@ -1404,6 +1404,7 @@ struct bus_type pcmcia_bus_type = { .suspend = pcmcia_dev_suspend, .resume = pcmcia_dev_resume, }; +EXPORT_SYMBOL_GPL (pcmcia_bus_type);static int __init init_pcmcia_bus (void )
include/pcmcia/ss.h +1 -0
@@ -298,6 +298,7 @@ extern int pcmcia_register_socket(structextern void pcmcia_unregister_socket (struct pcmcia_socket *socket);extern struct class pcmcia_socket_class; +extern struct bus_type pcmcia_bus_type;/* socket drivers are expected to use these callbacks in their .drv struct */ extern int pcmcia_socket_dev_suspend (struct device *dev,pm_message_t state);