Commit 8416d21c authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] pcmcia: use device_class->add_device/remove_device

This patch removes the {un}register_ss_entry/pcmcia_{un}register_socket
calls, and replaces them with generic driver-model-compatible functions.

Also, update the CodingStyle of these cs.c functions to what's recommended
in the Linux kernel.
parent 467f07e0
...@@ -309,44 +309,57 @@ static void reset_socket(socket_info_t *); ...@@ -309,44 +309,57 @@ static void reset_socket(socket_info_t *);
static void unreset_socket(socket_info_t *); static void unreset_socket(socket_info_t *);
static void parse_events(void *info, u_int events); static void parse_events(void *info, u_int events);
socket_info_t *pcmcia_register_socket (int slot, #define to_class_data(dev) dev->class_data
struct pccard_operations * ss_entry,
int use_bus_pm) /**
* pcmcia_register_socket - add a new pcmcia socket device
*/
int pcmcia_register_socket(struct device *dev)
{ {
socket_info_t *s; struct pcmcia_socket_class_data *cls_d = to_class_data(dev);
int i; socket_info_t *s_info;
unsigned int i, j;
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", ss_entry); if (!cls_d)
return -EINVAL;
s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL); DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", cls_d->ops);
if (!s)
return NULL; s_info = kmalloc(cls_d->nsock * sizeof(struct socket_info_t), GFP_KERNEL);
memset(s, 0, sizeof(socket_info_t)); if (!s_info)
return -ENOMEM;
memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
s->ss_entry = ss_entry; /* socket initialization */
s->sock = slot; for (i = 0; i < cls_d->nsock; i++) {
socket_info_t *s = &s_info[i];
cls_d->s_info[i] = s;
s->ss_entry = cls_d->ops;
s->sock = i;
/* base address = 0, map = 0 */ /* base address = 0, map = 0 */
s->cis_mem.flags = 0; s->cis_mem.flags = 0;
s->cis_mem.speed = cis_speed; s->cis_mem.speed = cis_speed;
s->use_bus_pm = use_bus_pm; s->use_bus_pm = cls_d->use_bus_pm;
s->erase_busy.next = s->erase_busy.prev = &s->erase_busy; s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
spin_lock_init(&s->lock); spin_lock_init(&s->lock);
for (i = 0; i < sockets; i++) /* TBD: remove usage of socket_table, use class_for_each_dev instead */
if (socket_table[i] == NULL) break; for (j = 0; j < sockets; j++)
socket_table[i] = s; if (socket_table[j] == NULL) break;
if (i == sockets) sockets++; socket_table[j] = s;
if (j == sockets) sockets++;
init_socket(s); init_socket(s);
ss_entry->inquire_socket(slot, &s->cap); s->ss_entry->inquire_socket(i, &s->cap);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (proc_pccard) { if (proc_pccard) {
char name[3]; char name[3];
sprintf(name, "%02d", i); sprintf(name, "%02d", i);
s->proc = proc_mkdir(name, proc_pccard); s->proc = proc_mkdir(name, proc_pccard);
if (s->proc) if (s->proc)
ss_entry->proc_setup(slot, s->proc); s->ss_entry->proc_setup(i, s->proc);
#ifdef PCMCIA_DEBUG #ifdef PCMCIA_DEBUG
if (s->proc) if (s->proc)
create_proc_read_entry("clients", 0, s->proc, create_proc_read_entry("clients", 0, s->proc,
...@@ -354,36 +367,35 @@ socket_info_t *pcmcia_register_socket (int slot, ...@@ -354,36 +367,35 @@ socket_info_t *pcmcia_register_socket (int slot,
#endif #endif
} }
#endif #endif
return s;
} /* pcmcia_register_socket */
int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
{
int ns;
DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry);
for (ns = 0; ns < nsock; ns++) {
pcmcia_register_socket (ns, ss_entry, 0);
} }
return 0; return 0;
} /* register_ss_entry */ } /* pcmcia_register_socket */
/*====================================================================*/
void pcmcia_unregister_socket(socket_info_t *s) /**
* pcmcia_unregister_socket - remove a pcmcia socket device
*/
void pcmcia_unregister_socket(struct device *dev)
{ {
struct pcmcia_socket_class_data *cls_d = to_class_data(dev);
unsigned int i;
int j, socket = -1; int j, socket = -1;
client_t *client; client_t *client;
socket_info_t *s;
if (!cls_d)
return;
s = (socket_info_t *) cls_d->s_info;
for (i = 0; i < cls_d->nsock; i++) {
for (j = 0; j < MAX_SOCK; j++) for (j = 0; j < MAX_SOCK; j++)
if (socket_table [j] == s) { if (socket_table [j] == s) {
socket = j; socket = j;
break; break;
} }
if (socket < 0) if (socket < 0)
return; continue;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (proc_pccard) { if (proc_pccard) {
...@@ -404,24 +416,16 @@ void pcmcia_unregister_socket(socket_info_t *s) ...@@ -404,24 +416,16 @@ void pcmcia_unregister_socket(socket_info_t *s)
kfree(client); kfree(client);
} }
s->ss_entry = NULL; s->ss_entry = NULL;
kfree(s);
socket_table[socket] = NULL; socket_table[socket] = NULL;
for (j = socket; j < sockets-1; j++) for (j = socket; j < sockets-1; j++)
socket_table[j] = socket_table[j+1]; socket_table[j] = socket_table[j+1];
sockets--; sockets--;
} /* pcmcia_unregister_socket */
void unregister_ss_entry(struct pccard_operations * ss_entry) s++;
{
int i;
for (i = sockets-1; i >= 0; i-- ) {
socket_info_t *socket = socket_table[i];
if (socket->ss_entry == ss_entry)
pcmcia_unregister_socket (socket);
} }
} /* unregister_ss_entry */ kfree(cls_d->s_info);
} /* pcmcia_unregister_socket */
/*====================================================================== /*======================================================================
...@@ -2403,8 +2407,6 @@ EXPORT_SYMBOL(pcmcia_validate_cis); ...@@ -2403,8 +2407,6 @@ EXPORT_SYMBOL(pcmcia_validate_cis);
EXPORT_SYMBOL(pcmcia_write_memory); EXPORT_SYMBOL(pcmcia_write_memory);
EXPORT_SYMBOL(dead_socket); EXPORT_SYMBOL(dead_socket);
EXPORT_SYMBOL(register_ss_entry);
EXPORT_SYMBOL(unregister_ss_entry);
EXPORT_SYMBOL(CardServices); EXPORT_SYMBOL(CardServices);
EXPORT_SYMBOL(MTDHelperEntry); EXPORT_SYMBOL(MTDHelperEntry);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -2418,6 +2420,8 @@ EXPORT_SYMBOL(pcmcia_resume_socket); ...@@ -2418,6 +2420,8 @@ EXPORT_SYMBOL(pcmcia_resume_socket);
struct device_class pcmcia_socket_class = { struct device_class pcmcia_socket_class = {
.name = "pcmcia_socket", .name = "pcmcia_socket",
.add_device = &pcmcia_register_socket,
.remove_device = &pcmcia_unregister_socket,
}; };
EXPORT_SYMBOL(pcmcia_socket_class); EXPORT_SYMBOL(pcmcia_socket_class);
......
...@@ -961,6 +961,10 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base, ...@@ -961,6 +961,10 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
hs_reset_socket(sp, 1); hs_reset_socket(sp, 1);
printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n",
i, sp->mem_base, sp->irq,
sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);
return 0; return 0;
} }
...@@ -991,6 +995,10 @@ static void hs_exit_socket(hs_socket_t *sp) ...@@ -991,6 +995,10 @@ static void hs_exit_socket(hs_socket_t *sp)
vfree(sp->io_vma->addr); vfree(sp->io_vma->addr);
} }
static struct pcmcia_socket_class_data hd64465_data = {
.nsock = HS_MAX_SOCKETS,
.ops = &hs_operations,
};
static struct device_driver hd64465_driver = { static struct device_driver hd64465_driver = {
.name = "hd64465-pcmcia", .name = "hd64465-pcmcia",
...@@ -1067,23 +1075,7 @@ static int __init init_hs(void) ...@@ -1067,23 +1075,7 @@ static int __init init_hs(void)
/* hd64465_io_debug = 0; */ /* hd64465_io_debug = 0; */
platform_device_register(&hd64465_device); platform_device_register(&hd64465_device);
hd64465_device.dev.class_data = &hd64465_data;
if (register_ss_entry(HS_MAX_SOCKETS, &hs_operations) != 0) {
for (i=0 ; i<HS_MAX_SOCKETS ; i++)
hs_exit_socket(&hs_sockets[i]);
platform_device_unregister(&hd64465_device);
unregister_driver(&hd64465_driver);
return -ENODEV;
}
printk(KERN_INFO "HD64465 PCMCIA bridge:\n");
for (i=0 ; i<HS_MAX_SOCKETS ; i++) {
hs_socket_t *sp = &hs_sockets[i];
printk(KERN_INFO " socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n",
i, sp->mem_base, sp->irq,
sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);
}
return 0; return 0;
} }
...@@ -1101,7 +1093,6 @@ static void __exit exit_hs(void) ...@@ -1101,7 +1093,6 @@ static void __exit exit_hs(void)
for (i=0 ; i<HS_MAX_SOCKETS ; i++) for (i=0 ; i<HS_MAX_SOCKETS ; i++)
hs_exit_socket(&hs_sockets[i]); hs_exit_socket(&hs_sockets[i]);
platform_device_unregister(&hd64465_device); platform_device_unregister(&hd64465_device);
unregister_ss_entry(&hs_operations);
restore_flags(flags); restore_flags(flags);
unregister_driver(&hd64465_driver); unregister_driver(&hd64465_driver);
......
...@@ -97,6 +97,7 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic ...@@ -97,6 +97,7 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
{ {
unsigned char configbyte; unsigned char configbyte;
int i, ret; int i, ret;
struct pcmcia_socket_class_data *cls_d;
enter("i82092aa_pci_probe"); enter("i82092aa_pci_probe");
...@@ -155,10 +156,16 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic ...@@ -155,10 +156,16 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
goto err_out_free_res; goto err_out_free_res;
} }
if ((ret = register_ss_entry(socket_count, &i82092aa_operations) != 0)) {
printk(KERN_ERR "i82092aa: register_ss_entry() failed\n"); cls_d = kmalloc(sizeof(*cls_d), GFP_KERNEL);
if (!cls_d) {
printk(KERN_ERR "i82092aa: kmalloc failed\n");
goto err_out_free_irq; goto err_out_free_irq;
} }
memset(cls_d, 0, sizeof(*cls_d));
cls_d->nsock = socket_count;
cls_d->ops = &i82092aa_operations;
dev->dev.class_data = cls_d;
leave("i82092aa_pci_probe"); leave("i82092aa_pci_probe");
return 0; return 0;
...@@ -177,6 +184,8 @@ static void __devexit i82092aa_pci_remove(struct pci_dev *dev) ...@@ -177,6 +184,8 @@ static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
enter("i82092aa_pci_remove"); enter("i82092aa_pci_remove");
free_irq(dev->irq, i82092aa_interrupt); free_irq(dev->irq, i82092aa_interrupt);
if (dev->dev.class_data)
kfree(dev->dev.class_data);
leave("i82092aa_pci_remove"); leave("i82092aa_pci_remove");
} }
...@@ -907,7 +916,6 @@ static void i82092aa_module_exit(void) ...@@ -907,7 +916,6 @@ static void i82092aa_module_exit(void)
{ {
enter("i82092aa_module_exit"); enter("i82092aa_module_exit");
pci_unregister_driver(&i82092aa_pci_drv); pci_unregister_driver(&i82092aa_pci_drv);
unregister_ss_entry(&i82092aa_operations);
if (sockets[0].io_base>0) if (sockets[0].io_base>0)
release_region(sockets[0].io_base, 2); release_region(sockets[0].io_base, 2);
leave("i82092aa_module_exit"); leave("i82092aa_module_exit");
......
...@@ -1584,6 +1584,10 @@ static struct pccard_operations pcic_operations = { ...@@ -1584,6 +1584,10 @@ static struct pccard_operations pcic_operations = {
/*====================================================================*/ /*====================================================================*/
static struct pcmcia_socket_class_data i82365_data = {
.ops = &pcic_operations,
};
static struct device_driver i82365_driver = { static struct device_driver i82365_driver = {
.name = "i82365", .name = "i82365",
.bus = &platform_bus_type, .bus = &platform_bus_type,
...@@ -1629,8 +1633,9 @@ static int __init init_i82365(void) ...@@ -1629,8 +1633,9 @@ static int __init init_i82365(void)
#endif #endif
platform_device_register(&i82365_device); platform_device_register(&i82365_device);
if (register_ss_entry(sockets, &pcic_operations) != 0)
printk(KERN_NOTICE "i82365: register_ss_entry() failed\n"); i82365_data.nsock = sockets;
i82365_device.dev.class_data = &i82365_data;
/* Finally, schedule a polling interrupt */ /* Finally, schedule a polling interrupt */
if (poll_interval != 0) { if (poll_interval != 0) {
...@@ -1651,7 +1656,6 @@ static void __exit exit_i82365(void) ...@@ -1651,7 +1656,6 @@ static void __exit exit_i82365(void)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
for (i = 0; i < sockets; i++) pcic_proc_remove(i); for (i = 0; i < sockets; i++) pcic_proc_remove(i);
#endif #endif
unregister_ss_entry(&pcic_operations);
platform_device_unregister(&i82365_device); platform_device_unregister(&i82365_device);
if (poll_interval != 0) if (poll_interval != 0)
del_timer_sync(&poll_timer); del_timer_sync(&poll_timer);
......
...@@ -190,11 +190,21 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock ...@@ -190,11 +190,21 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
return err; return err;
} }
void cardbus_register(pci_socket_t *socket) int cardbus_register(struct pci_dev *p_dev)
{ {
int nr = socket - pci_socket_array; pci_socket_t *socket = pci_get_drvdata(p_dev);
struct pcmcia_socket_class_data *cls_d;
socket->pcmcia_socket = pcmcia_register_socket(nr, &pci_socket_operations, 1); if (!socket)
return -EINVAL;
cls_d = &socket->cls_d;
cls_d->nsock = 1; /* yenta is 1, no other low-level driver uses
this yet */
cls_d->ops = &pci_socket_operations;
cls_d->use_bus_pm = 1;
p_dev->dev.class_data = cls_d;
return 0;
} }
static int __devinit static int __devinit
...@@ -214,7 +224,7 @@ static void __devexit cardbus_remove (struct pci_dev *dev) ...@@ -214,7 +224,7 @@ static void __devexit cardbus_remove (struct pci_dev *dev)
{ {
pci_socket_t *socket = pci_get_drvdata(dev); pci_socket_t *socket = pci_get_drvdata(dev);
pcmcia_unregister_socket (socket->pcmcia_socket); /* note: we are already unregistered from the cs core */
if (socket->op && socket->op->close) if (socket->op && socket->op->close)
socket->op->close(socket); socket->op->close(socket);
pci_set_drvdata(dev, NULL); pci_set_drvdata(dev, NULL);
......
...@@ -24,6 +24,7 @@ typedef struct pci_socket { ...@@ -24,6 +24,7 @@ typedef struct pci_socket {
struct work_struct tq_task; struct work_struct tq_task;
struct timer_list poll_timer; struct timer_list poll_timer;
struct pcmcia_socket_class_data cls_d;
/* A few words of private data for the low-level driver.. */ /* A few words of private data for the low-level driver.. */
unsigned int private[8]; unsigned int private[8];
} pci_socket_t; } pci_socket_t;
......
...@@ -376,6 +376,9 @@ static int __init get_tcic_id(void) ...@@ -376,6 +376,9 @@ static int __init get_tcic_id(void)
/*====================================================================*/ /*====================================================================*/
static struct pcmcia_socket_class_data tcic_data = {
.ops = &tcic_operations,
};
static struct device_driver tcic_driver = { static struct device_driver tcic_driver = {
.name = "tcic-pcmcia", .name = "tcic-pcmcia",
...@@ -521,15 +524,8 @@ static int __init init_tcic(void) ...@@ -521,15 +524,8 @@ static int __init init_tcic(void)
/* jump start interrupt handler, if needed */ /* jump start interrupt handler, if needed */
tcic_interrupt(0, NULL, NULL); tcic_interrupt(0, NULL, NULL);
if (register_ss_entry(sockets, &tcic_operations) != 0) { tcic_data.nsock = sockets;
printk(KERN_NOTICE "tcic: register_ss_entry() failed\n"); tcic_device.dev.class_data = &tcic_data;
release_region(tcic_base, 16);
if (cs_irq != 0)
free_irq(cs_irq, tcic_interrupt);
platform_device_unregister(&tcic_device);
driver_unregister(&tcic_driver);
return -ENODEV;
}
return 0; return 0;
...@@ -539,7 +535,6 @@ static int __init init_tcic(void) ...@@ -539,7 +535,6 @@ static int __init init_tcic(void)
static void __exit exit_tcic(void) static void __exit exit_tcic(void)
{ {
unregister_ss_entry(&tcic_operations);
del_timer_sync(&poll_timer); del_timer_sync(&poll_timer);
if (cs_irq != 0) { if (cs_irq != 0) {
tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00); tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
......
...@@ -577,39 +577,6 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket, u32 isa_irq_mask ...@@ -577,39 +577,6 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket, u32 isa_irq_mask
printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq); printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
} }
extern void cardbus_register(pci_socket_t *socket);
/*
* 'Bottom half' for the yenta_open routine. Allocate the interrupt line
* and register the socket with the upper layers.
*/
static void yenta_open_bh(void * data)
{
pci_socket_t * socket = (pci_socket_t *) data;
/* It's OK to overwrite this now */
INIT_WORK(&socket->tq_task, yenta_bh, socket);
if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) {
/* No IRQ or request_irq failed. Poll */
socket->cb_irq = 0; /* But zero is a valid IRQ number. */
init_timer(&socket->poll_timer);
socket->poll_timer.function = yenta_interrupt_wrapper;
socket->poll_timer.data = (unsigned long)socket;
socket->poll_timer.expires = jiffies + HZ;
add_timer(&socket->poll_timer);
}
/* Figure out what the dang thing can do for the PCMCIA layer... */
yenta_get_socket_capabilities(socket, isa_interrupts);
printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
/* Register it with the pcmcia layer.. */
cardbus_register(socket);
MOD_DEC_USE_COUNT;
}
static void yenta_clear_maps(pci_socket_t *socket) static void yenta_clear_maps(pci_socket_t *socket)
{ {
int i; int i;
...@@ -881,6 +848,9 @@ static struct cardbus_override_struct { ...@@ -881,6 +848,9 @@ static struct cardbus_override_struct {
#define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct)) #define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct))
extern int cardbus_register(struct pci_dev *p_dev);
/* /*
* Initialize a cardbus controller. Make sure we have a usable * Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the * interrupt, and that we can map the cardbus area. Fill in the
...@@ -932,16 +902,26 @@ static int yenta_open(pci_socket_t *socket) ...@@ -932,16 +902,26 @@ static int yenta_open(pci_socket_t *socket)
} }
} }
/* Get the PCMCIA kernel thread to complete the /* We must finish initialization here */
initialisation later. We can't do this here,
because, er, because Linus says so :)
*/
INIT_WORK(&socket->tq_task, yenta_open_bh, socket);
MOD_INC_USE_COUNT; INIT_WORK(&socket->tq_task, yenta_bh, socket);
schedule_work(&socket->tq_task);
return 0; if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) {
/* No IRQ or request_irq failed. Poll */
socket->cb_irq = 0; /* But zero is a valid IRQ number. */
init_timer(&socket->poll_timer);
socket->poll_timer.function = yenta_interrupt_wrapper;
socket->poll_timer.data = (unsigned long)socket;
socket->poll_timer.expires = jiffies + HZ;
add_timer(&socket->poll_timer);
}
/* Figure out what the dang thing can do for the PCMCIA layer... */
yenta_get_socket_capabilities(socket, isa_interrupts);
printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
/* Register it with the pcmcia layer.. */
return cardbus_register(dev);
} }
/* /*
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define _LINUX_SS_H #define _LINUX_SS_H
#include <pcmcia/cs_types.h> #include <pcmcia/cs_types.h>
#include <linux/device.h>
/* Definitions for card status flags for GetStatus */ /* Definitions for card status flags for GetStatus */
#define SS_WRPROT 0x0001 #define SS_WRPROT 0x0001
...@@ -142,8 +143,15 @@ struct pccard_operations { ...@@ -142,8 +143,15 @@ struct pccard_operations {
/* /*
* Calls to set up low-level "Socket Services" drivers * Calls to set up low-level "Socket Services" drivers
*/ */
extern int register_ss_entry(int nsock, struct pccard_operations *ops);
extern void unregister_ss_entry(struct pccard_operations *ops); #define MAX_SOCKETS_PER_DEV 8
struct pcmcia_socket_class_data {
unsigned int nsock; /* number of sockets */
struct pccard_operations *ops; /* see above */
void *s_info[MAX_SOCKETS_PER_DEV]; /* socket_info_t */
unsigned int use_bus_pm;
};
extern struct device_class pcmcia_socket_class; extern struct device_class pcmcia_socket_class;
......
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