Commit 2a089f7e authored by Russell King's avatar Russell King

[ARM] Dynamically allocate SA1100 PCMCIA sockets.

parent cd2cb093
...@@ -58,14 +58,6 @@ ...@@ -58,14 +58,6 @@
static int pc_debug; static int pc_debug;
#endif #endif
/* This structure maintains housekeeping state for each socket, such
* as the last known values of the card detect pins, or the Card Services
* callback value associated with the socket:
*/
static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x))
#define to_sa1100_socket(x) container_of(x, struct sa1100_pcmcia_socket, socket) #define to_sa1100_socket(x) container_of(x, struct sa1100_pcmcia_socket, socket)
/* /*
...@@ -682,6 +674,9 @@ void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *ir ...@@ -682,6 +674,9 @@ void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *ir
} }
EXPORT_SYMBOL(sa11xx_enable_irqs); EXPORT_SYMBOL(sa11xx_enable_irqs);
static LIST_HEAD(sa1100_sockets);
static DECLARE_MUTEX(sa1100_sockets_lock);
static const char *skt_names[] = { static const char *skt_names[] = {
"PCMCIA socket 0", "PCMCIA socket 0",
"PCMCIA socket 1", "PCMCIA socket 1",
...@@ -689,8 +684,12 @@ static const char *skt_names[] = { ...@@ -689,8 +684,12 @@ static const char *skt_names[] = {
struct skt_dev_info { struct skt_dev_info {
int nskt; int nskt;
struct sa1100_pcmcia_socket skt[0];
}; };
#define SKT_DEV_INFO_SIZE(n) \
(sizeof(struct skt_dev_info) + (n)*sizeof(struct sa1100_pcmcia_socket))
int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
{ {
struct skt_dev_info *sinfo; struct skt_dev_info *sinfo;
...@@ -704,13 +703,15 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in ...@@ -704,13 +703,15 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
if (!ops->socket_get_timing) if (!ops->socket_get_timing)
ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing; ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing;
sinfo = kmalloc(sizeof(struct skt_dev_info), GFP_KERNEL); down(&sa1100_sockets_lock);
sinfo = kmalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
if (!sinfo) { if (!sinfo) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
memset(sinfo, 0, sizeof(struct skt_dev_info)); memset(sinfo, 0, SKT_DEV_INFO_SIZE(nr));
sinfo->nskt = nr; sinfo->nskt = nr;
cpu_clock = cpufreq_get(0); cpu_clock = cpufreq_get(0);
...@@ -719,8 +720,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in ...@@ -719,8 +720,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
* Initialise the per-socket structure. * Initialise the per-socket structure.
*/ */
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); struct sa1100_pcmcia_socket *skt = &sinfo->skt[i];
memset(skt, 0, sizeof(*skt));
skt->socket.ops = &sa11xx_pcmcia_operations; skt->socket.ops = &sa11xx_pcmcia_operations;
skt->socket.owner = ops->owner; skt->socket.owner = ops->owner;
...@@ -778,6 +778,8 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in ...@@ -778,6 +778,8 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
goto out_err_5; goto out_err_5;
} }
list_add(&skt->node, &sa1100_sockets);
/* /*
* We initialize the MECR to default values here, because * We initialize the MECR to default values here, because
* we are not guaranteed to see a SetIOMap operation at * we are not guaranteed to see a SetIOMap operation at
...@@ -809,10 +811,11 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in ...@@ -809,10 +811,11 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
} }
dev_set_drvdata(dev, sinfo); dev_set_drvdata(dev, sinfo);
return 0; ret = 0;
goto out;
do { do {
struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); struct sa1100_pcmcia_socket *skt = &sinfo->skt[i];
del_timer_sync(&skt->poll_timer); del_timer_sync(&skt->poll_timer);
pcmcia_unregister_socket(&skt->socket); pcmcia_unregister_socket(&skt->socket);
...@@ -822,6 +825,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in ...@@ -822,6 +825,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
ops->hw_shutdown(skt); ops->hw_shutdown(skt);
out_err_6: out_err_6:
list_del(&skt->node);
iounmap(skt->virt_io); iounmap(skt->virt_io);
out_err_5: out_err_5:
release_resource(&skt->res_attr); release_resource(&skt->res_attr);
...@@ -838,6 +842,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in ...@@ -838,6 +842,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
kfree(sinfo); kfree(sinfo);
out: out:
up(&sa1100_sockets_lock);
return ret; return ret;
} }
EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
...@@ -849,8 +854,9 @@ int sa11xx_drv_pcmcia_remove(struct device *dev) ...@@ -849,8 +854,9 @@ int sa11xx_drv_pcmcia_remove(struct device *dev)
dev_set_drvdata(dev, NULL); dev_set_drvdata(dev, NULL);
down(&sa1100_sockets_lock);
for (i = 0; i < sinfo->nskt; i++) { for (i = 0; i < sinfo->nskt; i++) {
struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); struct sa1100_pcmcia_socket *skt = &sinfo->skt[i];
del_timer_sync(&skt->poll_timer); del_timer_sync(&skt->poll_timer);
...@@ -862,6 +868,7 @@ int sa11xx_drv_pcmcia_remove(struct device *dev) ...@@ -862,6 +868,7 @@ int sa11xx_drv_pcmcia_remove(struct device *dev)
sa1100_pcmcia_config_skt(skt, &dead_socket); sa1100_pcmcia_config_skt(skt, &dead_socket);
list_del(&skt->node);
iounmap(skt->virt_io); iounmap(skt->virt_io);
skt->virt_io = NULL; skt->virt_io = NULL;
release_resource(&skt->res_attr); release_resource(&skt->res_attr);
...@@ -869,6 +876,7 @@ int sa11xx_drv_pcmcia_remove(struct device *dev) ...@@ -869,6 +876,7 @@ int sa11xx_drv_pcmcia_remove(struct device *dev)
release_resource(&skt->res_io); release_resource(&skt->res_io);
release_resource(&skt->res_skt); release_resource(&skt->res_skt);
} }
up(&sa1100_sockets_lock);
kfree(sinfo); kfree(sinfo);
...@@ -886,13 +894,12 @@ EXPORT_SYMBOL(sa11xx_drv_pcmcia_remove); ...@@ -886,13 +894,12 @@ EXPORT_SYMBOL(sa11xx_drv_pcmcia_remove);
*/ */
static void sa1100_pcmcia_update_mecr(unsigned int clock) static void sa1100_pcmcia_update_mecr(unsigned int clock)
{ {
unsigned int sock; struct sa1100_pcmcia_socket *skt;
for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) { down(&sa1100_sockets_lock);
struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); list_for_each_entry(skt, &sa1100_sockets, node)
if (skt->ops) sa1100_pcmcia_set_mecr(skt, clock);
sa1100_pcmcia_set_mecr(skt, clock); up(&sa1100_sockets_lock);
}
} }
/* sa1100_pcmcia_notifier() /* sa1100_pcmcia_notifier()
......
...@@ -73,6 +73,7 @@ struct sa1100_pcmcia_socket { ...@@ -73,6 +73,7 @@ struct sa1100_pcmcia_socket {
unsigned int irq_state; unsigned int irq_state;
struct timer_list poll_timer; struct timer_list poll_timer;
struct list_head node;
}; };
struct pcmcia_low_level { struct pcmcia_low_level {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment