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 *);
static void unreset_socket(socket_info_t *);
static void parse_events(void *info, u_int events);
socket_info_t *pcmcia_register_socket (int slot,
struct pccard_operations * ss_entry,
int use_bus_pm)
#define to_class_data(dev) dev->class_data
/**
* pcmcia_register_socket - add a new pcmcia socket device
*/
int pcmcia_register_socket(struct device *dev)
{
socket_info_t *s;
int i;
struct pcmcia_socket_class_data *cls_d = to_class_data(dev);
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);
if (!s)
return NULL;
memset(s, 0, sizeof(socket_info_t));
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", cls_d->ops);
s_info = kmalloc(cls_d->nsock * sizeof(struct socket_info_t), GFP_KERNEL);
if (!s_info)
return -ENOMEM;
memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
s->ss_entry = ss_entry;
s->sock = slot;
/* socket initialization */
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 */
s->cis_mem.flags = 0;
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;
spin_lock_init(&s->lock);
for (i = 0; i < sockets; i++)
if (socket_table[i] == NULL) break;
socket_table[i] = s;
if (i == sockets) sockets++;
/* TBD: remove usage of socket_table, use class_for_each_dev instead */
for (j = 0; j < sockets; j++)
if (socket_table[j] == NULL) break;
socket_table[j] = s;
if (j == sockets) sockets++;
init_socket(s);
ss_entry->inquire_socket(slot, &s->cap);
s->ss_entry->inquire_socket(i, &s->cap);
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
char name[3];
sprintf(name, "%02d", i);
s->proc = proc_mkdir(name, proc_pccard);
if (s->proc)
ss_entry->proc_setup(slot, s->proc);
s->ss_entry->proc_setup(i, s->proc);
#ifdef PCMCIA_DEBUG
if (s->proc)
create_proc_read_entry("clients", 0, s->proc,
......@@ -354,36 +367,35 @@ socket_info_t *pcmcia_register_socket (int slot,
#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;
} /* 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;
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++)
if (socket_table [j] == s) {
socket = j;
break;
}
if (socket < 0)
return;
continue;
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
......@@ -404,24 +416,16 @@ void pcmcia_unregister_socket(socket_info_t *s)
kfree(client);
}
s->ss_entry = NULL;
kfree(s);
socket_table[socket] = NULL;
for (j = socket; j < sockets-1; j++)
socket_table[j] = socket_table[j+1];
sockets--;
} /* pcmcia_unregister_socket */
void unregister_ss_entry(struct pccard_operations * ss_entry)
{
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);
s++;
}
} /* unregister_ss_entry */
kfree(cls_d->s_info);
} /* pcmcia_unregister_socket */
/*======================================================================
......@@ -2403,8 +2407,6 @@ EXPORT_SYMBOL(pcmcia_validate_cis);
EXPORT_SYMBOL(pcmcia_write_memory);
EXPORT_SYMBOL(dead_socket);
EXPORT_SYMBOL(register_ss_entry);
EXPORT_SYMBOL(unregister_ss_entry);
EXPORT_SYMBOL(CardServices);
EXPORT_SYMBOL(MTDHelperEntry);
#ifdef CONFIG_PROC_FS
......@@ -2418,6 +2420,8 @@ EXPORT_SYMBOL(pcmcia_resume_socket);
struct device_class pcmcia_socket_class = {
.name = "pcmcia_socket",
.add_device = &pcmcia_register_socket,
.remove_device = &pcmcia_unregister_socket,
};
EXPORT_SYMBOL(pcmcia_socket_class);
......
......@@ -961,6 +961,10 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
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;
}
......@@ -991,6 +995,10 @@ static void hs_exit_socket(hs_socket_t *sp)
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 = {
.name = "hd64465-pcmcia",
......@@ -1067,23 +1075,7 @@ static int __init init_hs(void)
/* hd64465_io_debug = 0; */
platform_device_register(&hd64465_device);
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);
}
hd64465_device.dev.class_data = &hd64465_data;
return 0;
}
......@@ -1101,7 +1093,6 @@ static void __exit exit_hs(void)
for (i=0 ; i<HS_MAX_SOCKETS ; i++)
hs_exit_socket(&hs_sockets[i]);
platform_device_unregister(&hd64465_device);
unregister_ss_entry(&hs_operations);
restore_flags(flags);
unregister_driver(&hd64465_driver);
......
......@@ -97,6 +97,7 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
{
unsigned char configbyte;
int i, ret;
struct pcmcia_socket_class_data *cls_d;
enter("i82092aa_pci_probe");
......@@ -155,10 +156,16 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
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;
}
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");
return 0;
......@@ -177,6 +184,8 @@ static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
enter("i82092aa_pci_remove");
free_irq(dev->irq, i82092aa_interrupt);
if (dev->dev.class_data)
kfree(dev->dev.class_data);
leave("i82092aa_pci_remove");
}
......@@ -907,7 +916,6 @@ static void i82092aa_module_exit(void)
{
enter("i82092aa_module_exit");
pci_unregister_driver(&i82092aa_pci_drv);
unregister_ss_entry(&i82092aa_operations);
if (sockets[0].io_base>0)
release_region(sockets[0].io_base, 2);
leave("i82092aa_module_exit");
......
......@@ -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 = {
.name = "i82365",
.bus = &platform_bus_type,
......@@ -1629,8 +1633,9 @@ static int __init init_i82365(void)
#endif
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 */
if (poll_interval != 0) {
......@@ -1651,7 +1656,6 @@ static void __exit exit_i82365(void)
#ifdef CONFIG_PROC_FS
for (i = 0; i < sockets; i++) pcic_proc_remove(i);
#endif
unregister_ss_entry(&pcic_operations);
platform_device_unregister(&i82365_device);
if (poll_interval != 0)
del_timer_sync(&poll_timer);
......
......@@ -190,11 +190,21 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
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
......@@ -214,7 +224,7 @@ static void __devexit cardbus_remove (struct pci_dev *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)
socket->op->close(socket);
pci_set_drvdata(dev, NULL);
......
......@@ -24,6 +24,7 @@ typedef struct pci_socket {
struct work_struct tq_task;
struct timer_list poll_timer;
struct pcmcia_socket_class_data cls_d;
/* A few words of private data for the low-level driver.. */
unsigned int private[8];
} pci_socket_t;
......
......@@ -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 = {
.name = "tcic-pcmcia",
......@@ -521,15 +524,8 @@ static int __init init_tcic(void)
/* jump start interrupt handler, if needed */
tcic_interrupt(0, NULL, NULL);
if (register_ss_entry(sockets, &tcic_operations) != 0) {
printk(KERN_NOTICE "tcic: register_ss_entry() failed\n");
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;
}
tcic_data.nsock = sockets;
tcic_device.dev.class_data = &tcic_data;
return 0;
......@@ -539,7 +535,6 @@ static int __init init_tcic(void)
static void __exit exit_tcic(void)
{
unregister_ss_entry(&tcic_operations);
del_timer_sync(&poll_timer);
if (cs_irq != 0) {
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
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)
{
int i;
......@@ -881,6 +848,9 @@ static 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
* interrupt, and that we can map the cardbus area. Fill in the
......@@ -932,16 +902,26 @@ static int yenta_open(pci_socket_t *socket)
}
}
/* Get the PCMCIA kernel thread to complete the
initialisation later. We can't do this here,
because, er, because Linus says so :)
*/
INIT_WORK(&socket->tq_task, yenta_open_bh, socket);
/* We must finish initialization here */
MOD_INC_USE_COUNT;
schedule_work(&socket->tq_task);
INIT_WORK(&socket->tq_task, yenta_bh, socket);
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 @@
#define _LINUX_SS_H
#include <pcmcia/cs_types.h>
#include <linux/device.h>
/* Definitions for card status flags for GetStatus */
#define SS_WRPROT 0x0001
......@@ -142,8 +143,15 @@ struct pccard_operations {
/*
* 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;
......
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