提交 097e296d 编写于 作者: R Russell King - ARM Linux 提交者: Dominik Brodowski

PCMCIA: soc_common: provide single socket add/remove functionality

Factor out the functionality for adding and removing a single
socket, thereby allowing SoCs to individually register each
socket.  The advantage of this approach is that SoCs can then
extend soc_pcmcia_socket as they wish.
Signed-off-by: NRussell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: NDominik Brodowski <linux@dominikbrodowski.net>
上级 0f767de6
...@@ -574,7 +574,7 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, ...@@ -574,7 +574,7 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt,
EXPORT_SYMBOL(soc_pcmcia_enable_irqs); EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
LIST_HEAD(soc_pcmcia_sockets); static LIST_HEAD(soc_pcmcia_sockets);
static DEFINE_MUTEX(soc_pcmcia_sockets_lock); static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
...@@ -619,158 +619,174 @@ module_exit(soc_pcmcia_cpufreq_unregister); ...@@ -619,158 +619,174 @@ module_exit(soc_pcmcia_cpufreq_unregister);
#endif #endif
int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
struct skt_dev_info *sinfo)
{ {
struct soc_pcmcia_socket *skt;
int ret, i;
mutex_lock(&soc_pcmcia_sockets_lock); mutex_lock(&soc_pcmcia_sockets_lock);
del_timer_sync(&skt->poll_timer);
/* pcmcia_unregister_socket(&skt->socket);
* Initialise the per-socket structure.
*/
for (i = 0; i < sinfo->nskt; i++) {
skt = &sinfo->skt[i];
skt->socket.ops = &soc_common_pcmcia_operations; flush_scheduled_work();
skt->socket.owner = ops->owner;
skt->socket.dev.parent = dev;
init_timer(&skt->poll_timer); skt->ops->hw_shutdown(skt);
skt->poll_timer.function = soc_common_pcmcia_poll_event;
skt->poll_timer.data = (unsigned long)skt;
skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
skt->dev = dev; soc_common_pcmcia_config_skt(skt, &dead_socket);
skt->ops = ops;
ret = request_resource(&iomem_resource, &skt->res_skt); list_del(&skt->node);
if (ret) mutex_unlock(&soc_pcmcia_sockets_lock);
goto out_err_1;
ret = request_resource(&skt->res_skt, &skt->res_io); iounmap(skt->virt_io);
if (ret) skt->virt_io = NULL;
goto out_err_2; release_resource(&skt->res_attr);
release_resource(&skt->res_mem);
release_resource(&skt->res_io);
release_resource(&skt->res_skt);
}
EXPORT_SYMBOL(soc_pcmcia_remove_one);
ret = request_resource(&skt->res_skt, &skt->res_mem); int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
if (ret) {
goto out_err_3; int ret;
ret = request_resource(&skt->res_skt, &skt->res_attr); init_timer(&skt->poll_timer);
if (ret) skt->poll_timer.function = soc_common_pcmcia_poll_event;
goto out_err_4; skt->poll_timer.data = (unsigned long)skt;
skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
skt->virt_io = ioremap(skt->res_io.start, 0x10000); ret = request_resource(&iomem_resource, &skt->res_skt);
if (skt->virt_io == NULL) { if (ret)
ret = -ENOMEM; goto out_err_1;
goto out_err_5;
}
list_add(&skt->node, &soc_pcmcia_sockets); ret = request_resource(&skt->res_skt, &skt->res_io);
if (ret)
goto out_err_2;
/* ret = request_resource(&skt->res_skt, &skt->res_mem);
* We initialize default socket timing here, because if (ret)
* we are not guaranteed to see a SetIOMap operation at goto out_err_3;
* runtime.
*/
ops->set_timing(skt);
ret = ops->hw_init(skt); ret = request_resource(&skt->res_skt, &skt->res_attr);
if (ret) if (ret)
goto out_err_6; goto out_err_4;
skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; skt->virt_io = ioremap(skt->res_io.start, 0x10000);
skt->socket.resource_ops = &pccard_static_ops; if (skt->virt_io == NULL) {
skt->socket.irq_mask = 0; ret = -ENOMEM;
skt->socket.map_size = PAGE_SIZE; goto out_err_5;
skt->socket.pci_irq = skt->irq; }
skt->socket.io_offset = (unsigned long)skt->virt_io;
skt->status = soc_common_pcmcia_skt_state(skt); mutex_lock(&soc_pcmcia_sockets_lock);
ret = pcmcia_register_socket(&skt->socket); list_add(&skt->node, &soc_pcmcia_sockets);
if (ret)
goto out_err_7;
WARN_ON(skt->socket.sock != i); /*
* We initialize default socket timing here, because
* we are not guaranteed to see a SetIOMap operation at
* runtime.
*/
skt->ops->set_timing(skt);
add_timer(&skt->poll_timer); ret = skt->ops->hw_init(skt);
if (ret)
goto out_err_6;
ret = device_create_file(&skt->socket.dev, &dev_attr_status); skt->socket.ops = &soc_common_pcmcia_operations;
if (ret) skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
goto out_err_8; skt->socket.resource_ops = &pccard_static_ops;
} skt->socket.irq_mask = 0;
skt->socket.map_size = PAGE_SIZE;
skt->socket.pci_irq = skt->irq;
skt->socket.io_offset = (unsigned long)skt->virt_io;
dev_set_drvdata(dev, sinfo); skt->status = soc_common_pcmcia_skt_state(skt);
ret = 0;
goto out;
do { ret = pcmcia_register_socket(&skt->socket);
skt = &sinfo->skt[i]; if (ret)
goto out_err_7;
add_timer(&skt->poll_timer);
mutex_unlock(&soc_pcmcia_sockets_lock);
ret = device_create_file(&skt->socket.dev, &dev_attr_status);
if (ret)
goto out_err_8;
return ret;
device_remove_file(&skt->socket.dev, &dev_attr_status);
out_err_8: out_err_8:
del_timer_sync(&skt->poll_timer); mutex_lock(&soc_pcmcia_sockets_lock);
pcmcia_unregister_socket(&skt->socket); del_timer_sync(&skt->poll_timer);
pcmcia_unregister_socket(&skt->socket);
out_err_7: out_err_7:
flush_scheduled_work(); flush_scheduled_work();
ops->hw_shutdown(skt); skt->ops->hw_shutdown(skt);
out_err_6: out_err_6:
list_del(&skt->node); list_del(&skt->node);
iounmap(skt->virt_io); mutex_unlock(&soc_pcmcia_sockets_lock);
iounmap(skt->virt_io);
out_err_5: out_err_5:
release_resource(&skt->res_attr); release_resource(&skt->res_attr);
out_err_4: out_err_4:
release_resource(&skt->res_mem); release_resource(&skt->res_mem);
out_err_3: out_err_3:
release_resource(&skt->res_io); release_resource(&skt->res_io);
out_err_2: out_err_2:
release_resource(&skt->res_skt); release_resource(&skt->res_skt);
out_err_1: out_err_1:
i--;
} while (i > 0);
kfree(sinfo);
out:
mutex_unlock(&soc_pcmcia_sockets_lock);
return ret; return ret;
} }
EXPORT_SYMBOL(soc_common_drv_pcmcia_probe); EXPORT_SYMBOL(soc_pcmcia_add_one);
int soc_common_drv_pcmcia_remove(struct device *dev) int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
struct skt_dev_info *sinfo)
{ {
struct skt_dev_info *sinfo = dev_get_drvdata(dev); struct soc_pcmcia_socket *skt;
int i; int ret, i;
dev_set_drvdata(dev, NULL); /*
* Initialise the per-socket structure.
*/
for (i = ret = 0; i < sinfo->nskt; i++) {
skt = &sinfo->skt[i];
mutex_lock(&soc_pcmcia_sockets_lock); skt->socket.owner = ops->owner;
for (i = 0; i < sinfo->nskt; i++) { skt->socket.dev.parent = dev;
struct soc_pcmcia_socket *skt = &sinfo->skt[i];
del_timer_sync(&skt->poll_timer); skt->dev = dev;
skt->ops = ops;
pcmcia_unregister_socket(&skt->socket); ret = soc_pcmcia_add_one(skt);
if (ret)
break;
flush_scheduled_work(); WARN_ON(skt->socket.sock != i);
}
skt->ops->hw_shutdown(skt); if (ret) {
while (--i >= 0)
soc_pcmcia_remove_one(&sinfo->skt[i]);
kfree(sinfo);
} else {
dev_set_drvdata(dev, sinfo);
}
soc_common_pcmcia_config_skt(skt, &dead_socket); return ret;
}
EXPORT_SYMBOL(soc_common_drv_pcmcia_probe);
list_del(&skt->node); int soc_common_drv_pcmcia_remove(struct device *dev)
iounmap(skt->virt_io); {
skt->virt_io = NULL; struct skt_dev_info *sinfo = dev_get_drvdata(dev);
release_resource(&skt->res_attr); int i;
release_resource(&skt->res_mem);
release_resource(&skt->res_io); dev_set_drvdata(dev, NULL);
release_resource(&skt->res_skt);
} for (i = 0; i < sinfo->nskt; i++)
mutex_unlock(&soc_pcmcia_sockets_lock); soc_pcmcia_remove_one(&sinfo->skt[i]);
kfree(sinfo); kfree(sinfo);
......
...@@ -135,7 +135,8 @@ extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_ ...@@ -135,7 +135,8 @@ extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_
extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *); extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
extern struct list_head soc_pcmcia_sockets; void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo); extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo);
extern int soc_common_drv_pcmcia_remove(struct device *dev); extern int soc_common_drv_pcmcia_remove(struct device *dev);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册