Commit 9014144e authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Russell King

[PCMCIA] register

Add a more sane socket registration interface.

Previously, it was messed up because Greg's struct class hadn't been
invented when I wrote the code: there may be multiple sockets per
"struct device", and there is the need for one "struct class_device"
for each socket.

 drivers/pcmcia/cs.c         |  217 +++++++++++++++++++++----------------------- drivers/pcmcia/ds.c         |   56 ++---------
 drivers/pcmcia/i82092.c     |   48 ++++-----
 drivers/pcmcia/i82365.c     |   41 ++++----
 drivers/pcmcia/pci_socket.c |   23 +---
 drivers/pcmcia/pci_socket.h |    2
 drivers/pcmcia/tcic.c       |   38 ++++---
 include/pcmcia/ss.h         |   25 +++--
 8 files changed, 210 insertions(+), 240 deletions(-)
parent 432849b8
...@@ -305,13 +305,66 @@ static int proc_read_clients(char *buf, char **start, off_t pos, ...@@ -305,13 +305,66 @@ static int proc_read_clients(char *buf, char **start, off_t pos,
======================================================================*/ ======================================================================*/
static int pccardd(void *__skt); /**
void pcmcia_unregister_socket(struct class_device *dev); * socket drivers are expected to use the following callbacks in their
* .drv struct:
* - pcmcia_socket_dev_suspend
* - pcmcia_socket_dev_resume
* These functions check for the appropriate struct pcmcia_soket arrays,
* and pass them to the low-level functions pcmcia_{suspend,resume}_socket
*/
static int socket_resume(socket_info_t *skt);
static int socket_suspend(socket_info_t *skt);
int pcmcia_socket_dev_suspend(struct device *dev, u32 state, u32 level)
{
struct pcmcia_socket *socket;
if (level != SUSPEND_SAVE_STATE)
return 0;
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
if (socket->dev.dev != dev)
continue;
down(&socket->skt_sem);
socket_suspend(socket);
up(&socket->skt_sem);
}
up_read(&pcmcia_socket_list_rwsem);
return 0;
}
EXPORT_SYMBOL(pcmcia_socket_dev_suspend);
int pcmcia_socket_dev_resume(struct device *dev, u32 level)
{
struct pcmcia_socket *socket;
if (level != RESUME_RESTORE_STATE)
return 0;
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
if (socket->dev.dev != dev)
continue;
down(&socket->skt_sem);
socket_resume(socket);
up(&socket->skt_sem);
}
up_read(&pcmcia_socket_list_rwsem);
return 0;
}
EXPORT_SYMBOL(pcmcia_socket_dev_resume);
static int pccardd(void *__skt);
#define to_class_data(dev) dev->class_data #define to_class_data(dev) dev->class_data
static int pcmcia_add_socket(struct pcmcia_socket *socket) static int pcmcia_add_socket(struct class_device *class_dev)
{ {
struct pcmcia_socket *socket = class_get_devdata(class_dev);
int ret = 0; int ret = 0;
/* base address = 0, map = 0 */ /* base address = 0, map = 0 */
...@@ -352,8 +405,9 @@ static int pcmcia_add_socket(struct pcmcia_socket *socket) ...@@ -352,8 +405,9 @@ static int pcmcia_add_socket(struct pcmcia_socket *socket)
return 0; return 0;
} }
static void pcmcia_remove_socket(struct pcmcia_socket *socket) static void pcmcia_remove_socket(struct class_device *class_dev)
{ {
struct pcmcia_socket *socket = class_get_devdata(class_dev);
client_t *client; client_t *client;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -385,66 +439,74 @@ static void pcmcia_remove_socket(struct pcmcia_socket *socket) ...@@ -385,66 +439,74 @@ static void pcmcia_remove_socket(struct pcmcia_socket *socket)
/** /**
* pcmcia_register_socket - add a new pcmcia socket device * pcmcia_register_socket - add a new pcmcia socket device
*/ */
int pcmcia_register_socket(struct class_device *class_dev) int pcmcia_register_socket(struct pcmcia_socket *socket)
{ {
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev); if (!socket || !socket->ss_entry || !socket->dev.dev)
socket_info_t *s_info;
unsigned int i, ret;
if (!cls_d)
return -EINVAL; return -EINVAL;
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", cls_d->ops); DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ss_entry);
s_info = kmalloc(cls_d->nsock * sizeof(struct pcmcia_socket), GFP_KERNEL);
if (!s_info)
return -ENOMEM;
memset(s_info, 0, cls_d->nsock * sizeof(struct pcmcia_socket));
cls_d->s_info = s_info; /* try to obtain a socket number [yes, it gets ugly if we
ret = 0; * register more than 2^sizeof(unsigned int) pcmcia
* sockets... but the socket number is deprecated
* anyways, so I don't care] */
down_write(&pcmcia_socket_list_rwsem);
if (list_empty(&pcmcia_socket_list))
socket->sock = 0;
else {
unsigned int found, i = 1;
struct pcmcia_socket *tmp;
do {
found = 1;
list_for_each_entry(tmp, &pcmcia_socket_list, socket_list) {
if (tmp->sock == i)
found = 0;
}
i++;
} while (!found);
socket->sock = i - 1;
}
list_add_tail(&socket->socket_list, &pcmcia_socket_list);
up_write(&pcmcia_socket_list_rwsem);
/* socket initialization */
for (i = 0; i < cls_d->nsock; i++) {
struct pcmcia_socket *socket = &s_info[i];
socket->sock = i + cls_d->sock_offset; /* set proper values in socket->dev */
socket->dev.class_data = socket;
socket->dev.class = &pcmcia_socket_class;
snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u\n", socket->sock);
/* register with the device core */
if (class_device_register(&socket->dev)) {
down_write(&pcmcia_socket_list_rwsem); down_write(&pcmcia_socket_list_rwsem);
list_add(&socket->socket_list, &pcmcia_socket_list); list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem); up_write(&pcmcia_socket_list_rwsem);
return -EINVAL;
pcmcia_add_socket(socket);
} }
return ret;
return 0;
} /* pcmcia_register_socket */ } /* pcmcia_register_socket */
EXPORT_SYMBOL(pcmcia_register_socket);
/** /**
* pcmcia_unregister_socket - remove a pcmcia socket device * pcmcia_unregister_socket - remove a pcmcia socket device
*/ */
void pcmcia_unregister_socket(struct class_device *class_dev) void pcmcia_unregister_socket(struct pcmcia_socket *socket)
{ {
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev); if (!socket)
unsigned int i;
struct pcmcia_socket *socket;
if (!cls_d)
return; return;
socket = cls_d->s_info; DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ss_entry);
for (i = 0; i < cls_d->nsock; i++) { /* remove from the device core */
pcmcia_remove_socket(socket); class_device_unregister(&socket->dev);
/* remove from our own list */
down_write(&pcmcia_socket_list_rwsem); down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list); list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem); up_write(&pcmcia_socket_list_rwsem);
socket++;
}
kfree(cls_d->s_info);
} /* pcmcia_unregister_socket */ } /* pcmcia_unregister_socket */
EXPORT_SYMBOL(pcmcia_unregister_socket);
struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr) struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
...@@ -829,68 +891,6 @@ static void parse_events(void *info, u_int events) ...@@ -829,68 +891,6 @@ static void parse_events(void *info, u_int events)
wake_up(&s->thread_wait); wake_up(&s->thread_wait);
} /* parse_events */ } /* parse_events */
/*======================================================================
Another event handler, for power management events.
This does not comply with the latest PC Card spec for handling
power management events.
======================================================================*/
void pcmcia_suspend_socket (socket_info_t *skt)
{
down(&skt->skt_sem);
socket_suspend(skt);
up(&skt->skt_sem);
}
void pcmcia_resume_socket (socket_info_t *skt)
{
down(&skt->skt_sem);
socket_resume(skt);
up(&skt->skt_sem);
}
int pcmcia_socket_dev_suspend(struct pcmcia_socket_class_data *cls_d, u32 state, u32 level)
{
socket_info_t *s;
int i;
if ((!cls_d) || (level != SUSPEND_SAVE_STATE))
return 0;
s = (socket_info_t *) cls_d->s_info;
for (i = 0; i < cls_d->nsock; i++) {
pcmcia_suspend_socket(s);
s++;
}
return 0;
}
EXPORT_SYMBOL(pcmcia_socket_dev_suspend);
int pcmcia_socket_dev_resume(struct pcmcia_socket_class_data *cls_d, u32 level)
{
socket_info_t *s;
int i;
if ((!cls_d) || (level != RESUME_RESTORE_STATE))
return 0;
s = (socket_info_t *) cls_d->s_info;
for (i = 0; i < cls_d->nsock; i++) {
pcmcia_resume_socket(s);
s++;
}
return 0;
}
EXPORT_SYMBOL(pcmcia_socket_dev_resume);
/*====================================================================== /*======================================================================
...@@ -2547,11 +2547,6 @@ EXPORT_SYMBOL(MTDHelperEntry); ...@@ -2547,11 +2547,6 @@ EXPORT_SYMBOL(MTDHelperEntry);
EXPORT_SYMBOL(proc_pccard); EXPORT_SYMBOL(proc_pccard);
#endif #endif
EXPORT_SYMBOL(pcmcia_register_socket);
EXPORT_SYMBOL(pcmcia_unregister_socket);
EXPORT_SYMBOL(pcmcia_suspend_socket);
EXPORT_SYMBOL(pcmcia_resume_socket);
struct class pcmcia_socket_class = { struct class pcmcia_socket_class = {
.name = "pcmcia_socket", .name = "pcmcia_socket",
}; };
...@@ -2559,8 +2554,8 @@ EXPORT_SYMBOL(pcmcia_socket_class); ...@@ -2559,8 +2554,8 @@ EXPORT_SYMBOL(pcmcia_socket_class);
static struct class_interface pcmcia_socket = { static struct class_interface pcmcia_socket = {
.class = &pcmcia_socket_class, .class = &pcmcia_socket_class,
.add = &pcmcia_register_socket, .add = &pcmcia_add_socket,
.remove = &pcmcia_unregister_socket, .remove = &pcmcia_remove_socket,
}; };
......
...@@ -107,7 +107,6 @@ struct pcmcia_bus_socket { ...@@ -107,7 +107,6 @@ struct pcmcia_bus_socket {
struct work_struct removal; struct work_struct removal;
socket_bind_t *bind; socket_bind_t *bind;
struct device *socket_dev; struct device *socket_dev;
struct list_head socket_list;
unsigned int socket_no; /* deprecated */ unsigned int socket_no; /* deprecated */
struct pcmcia_socket *parent; struct pcmcia_socket *parent;
}; };
...@@ -123,10 +122,6 @@ static dev_info_t dev_info = "Driver Services"; ...@@ -123,10 +122,6 @@ static dev_info_t dev_info = "Driver Services";
static int major_dev = -1; static int major_dev = -1;
/* list of all sockets registered with the pcmcia bus driver */
static DECLARE_RWSEM(bus_socket_list_rwsem);
static LIST_HEAD(bus_socket_list);
extern struct proc_dir_entry *proc_pccard; extern struct proc_dir_entry *proc_pccard;
/*====================================================================*/ /*====================================================================*/
...@@ -825,8 +820,9 @@ static struct file_operations ds_fops = { ...@@ -825,8 +820,9 @@ static struct file_operations ds_fops = {
.poll = ds_poll, .poll = ds_poll,
}; };
static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct device *dev, unsigned int socket_nr) static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
{ {
struct pcmcia_socket *socket = class_dev->class_data;
client_reg_t client_reg; client_reg_t client_reg;
bind_req_t bind; bind_req_t bind;
struct pcmcia_bus_socket *s; struct pcmcia_bus_socket *s;
...@@ -848,7 +844,7 @@ static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct ...@@ -848,7 +844,7 @@ static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct
init_waitqueue_head(&s->request); init_waitqueue_head(&s->request);
/* initialize data */ /* initialize data */
s->socket_dev = dev; s->socket_dev = socket->dev.dev;
INIT_WORK(&s->removal, handle_removal, s); INIT_WORK(&s->removal, handle_removal, s);
s->socket_no = socket->sock; s->socket_no = socket->sock;
s->parent = socket; s->parent = socket;
...@@ -882,51 +878,25 @@ static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct ...@@ -882,51 +878,25 @@ static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct
} }
socket->pcmcia = s; socket->pcmcia = s;
list_add(&s->socket_list, &bus_socket_list);
return 0; return 0;
} }
static int pcmcia_bus_add_socket_dev(struct class_device *class_dev) static void pcmcia_bus_remove_socket(struct class_device *class_dev)
{
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
unsigned int i;
unsigned int ret = 0;
if (!cls_d)
return -ENODEV;
down_write(&bus_socket_list_rwsem);
for (i = 0; i < cls_d->nsock; i++)
ret += pcmcia_bus_add_socket(&cls_d->s_info[i], class_dev->dev, i);
up_write(&bus_socket_list_rwsem);
return ret;
}
static void pcmcia_bus_remove_socket_dev(struct class_device *class_dev)
{ {
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev); struct pcmcia_socket *socket = class_dev->class_data;
struct list_head *list_loop;
struct list_head *tmp_storage;
if (!cls_d) if (!socket || !socket->pcmcia)
return; return;
flush_scheduled_work(); flush_scheduled_work();
down_write(&bus_socket_list_rwsem); pcmcia_deregister_client(socket->pcmcia->handle);
list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) {
struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list); kfree(socket->pcmcia);
if (bus_sock->socket_dev == class_dev->dev) { socket->pcmcia = NULL;
bus_sock->parent->pcmcia = NULL;
pcmcia_deregister_client(bus_sock->handle);
list_del(&bus_sock->socket_list);
kfree(bus_sock);
}
}
up_write(&bus_socket_list_rwsem);
return; return;
} }
...@@ -934,8 +904,8 @@ static void pcmcia_bus_remove_socket_dev(struct class_device *class_dev) ...@@ -934,8 +904,8 @@ static void pcmcia_bus_remove_socket_dev(struct class_device *class_dev)
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */ /* the pcmcia_bus_interface is used to handle pcmcia socket devices */
static struct class_interface pcmcia_bus_interface = { static struct class_interface pcmcia_bus_interface = {
.class = &pcmcia_socket_class, .class = &pcmcia_socket_class,
.add = &pcmcia_bus_add_socket_dev, .add = &pcmcia_bus_add_socket,
.remove = &pcmcia_bus_remove_socket_dev, .remove = &pcmcia_bus_remove_socket,
}; };
......
...@@ -44,14 +44,12 @@ MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids); ...@@ -44,14 +44,12 @@ MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state) static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state)
{ {
struct pcmcia_socket_class_data *cls_d = pci_get_drvdata(dev); return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
return pcmcia_socket_dev_suspend(cls_d, state, 0);
} }
static int i82092aa_socket_resume (struct pci_dev *dev) static int i82092aa_socket_resume (struct pci_dev *dev)
{ {
struct pcmcia_socket_class_data *cls_d = pci_get_drvdata(dev); return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
return pcmcia_socket_dev_resume(cls_d, RESUME_RESTORE_STATE);
} }
static struct pci_driver i82092aa_pci_drv = { static struct pci_driver i82092aa_pci_drv = {
...@@ -95,6 +93,7 @@ struct socket_info { ...@@ -95,6 +93,7 @@ struct socket_info {
/* callback to the driver of the card */ /* callback to the driver of the card */
void *info; /* to be passed to the handler */ void *info; /* to be passed to the handler */
struct pcmcia_socket socket;
struct pci_dev *dev; /* The PCI device for the socket */ struct pci_dev *dev; /* The PCI device for the socket */
}; };
...@@ -107,7 +106,6 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic ...@@ -107,7 +106,6 @@ 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");
...@@ -166,26 +164,26 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic ...@@ -166,26 +164,26 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
goto err_out_free_res; goto err_out_free_res;
} }
pci_set_drvdata(dev, &sockets[i].socket);
cls_d = kmalloc(sizeof(*cls_d), GFP_KERNEL); for (i = 0; i<socket_count; i++) {
if (!cls_d) { sockets[i].socket.dev.dev = &dev->dev;
printk(KERN_ERR "i82092aa: kmalloc failed\n"); sockets[i].socket.ss_entry = &i82092aa_operations;
goto err_out_free_irq; ret = pcmcia_register_socket(&sockets[i].socket);
if (ret) {
goto err_out_free_sockets;
}
} }
memset(cls_d, 0, sizeof(*cls_d));
cls_d->nsock = socket_count;
cls_d->ops = &i82092aa_operations;
pci_set_drvdata(dev, &cls_d);
cls_d->class_dev.class = &pcmcia_socket_class;
cls_d->class_dev.dev = &dev->dev;
strlcpy(cls_d->class_dev.class_id, dev->dev.name, BUS_ID_SIZE);
class_set_devdata(&cls_d->class_dev, cls_d);
class_device_register(&cls_d->class_dev);
leave("i82092aa_pci_probe"); leave("i82092aa_pci_probe");
return 0; return 0;
err_out_free_irq: err_out_free_sockets:
if (i) {
for (i--;i>=0;i--) {
pcmcia_unregister_socket(&sockets[i].socket);
}
}
free_irq(dev->irq, i82092aa_interrupt); free_irq(dev->irq, i82092aa_interrupt);
err_out_free_res: err_out_free_res:
release_region(pci_resource_start(dev, 0), 2); release_region(pci_resource_start(dev, 0), 2);
...@@ -196,16 +194,14 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic ...@@ -196,16 +194,14 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
static void __devexit i82092aa_pci_remove(struct pci_dev *dev) static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
{ {
struct pcmcia_socket_class_data *cls_d = pci_get_drvdata(dev); struct pcmcia_socket *socket = pci_get_drvdata(dev);
enter("i82092aa_pci_remove"); enter("i82092aa_pci_remove");
free_irq(dev->irq, i82092aa_interrupt); free_irq(dev->irq, i82092aa_interrupt);
if (cls_d) { if (socket)
class_device_unregister(&cls_d->class_dev); pcmcia_unregister_socket(socket);
kfree(cls_d);
}
leave("i82092aa_pci_remove"); leave("i82092aa_pci_remove");
} }
......
...@@ -166,6 +166,7 @@ typedef struct vg46x_state_t { ...@@ -166,6 +166,7 @@ typedef struct vg46x_state_t {
typedef struct socket_info_t { typedef struct socket_info_t {
u_short type, flags; u_short type, flags;
struct pcmcia_socket socket;
socket_cap_t cap; socket_cap_t cap;
ioaddr_t ioaddr; ioaddr_t ioaddr;
u_short psock; u_short psock;
...@@ -1502,15 +1503,11 @@ static struct pccard_operations pcic_operations = { ...@@ -1502,15 +1503,11 @@ 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,
/* .suspend = pcmcia_socket_dev_suspend, FIXME? */ .suspend = pcmcia_socket_dev_suspend,
/* .resume = pcmcia_socket_dev_resume, FIXME? */ .resume = pcmcia_socket_dev_resume,
}; };
static struct platform_device i82365_device = { static struct platform_device i82365_device = {
...@@ -1521,13 +1518,11 @@ static struct platform_device i82365_device = { ...@@ -1521,13 +1518,11 @@ static struct platform_device i82365_device = {
}, },
}; };
static struct class_device i82365_class_data = {
.class = &pcmcia_socket_class,
};
static int __init init_i82365(void) static int __init init_i82365(void)
{ {
servinfo_t serv; servinfo_t serv;
int i, ret;
pcmcia_get_card_services_info(&serv); pcmcia_get_card_services_info(&serv);
if (serv.Revision != CS_RELEASE_CODE) { if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "i82365: Card Services release " printk(KERN_NOTICE "i82365: Card Services release "
...@@ -1551,19 +1546,25 @@ static int __init init_i82365(void) ...@@ -1551,19 +1546,25 @@ static int __init init_i82365(void)
return -ENODEV; return -ENODEV;
} }
platform_device_register(&i82365_device);
/* Set up interrupt handler(s) */ /* Set up interrupt handler(s) */
#ifdef CONFIG_ISA #ifdef CONFIG_ISA
if (grab_irq != 0) if (grab_irq != 0)
request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
#endif #endif
i82365_data.nsock = sockets; /* register sockets with the pcmcia core */
i82365_class_data.dev = &i82365_device.dev; for (i = 0; i < sockets; i++) {
i82365_class_data.class_data = &i82365_data; socket[i].socket.dev.dev = &i82365_device.dev;
strlcpy(i82365_class_data.class_id, "i82365", BUS_ID_SIZE); socket[i].socket.ss_entry = &pcic_operations;
ret = pcmcia_register_socket(&socket[i].socket);
platform_device_register(&i82365_device); if (ret && i--) {
class_device_register(&i82365_class_data); for (; i>= 0; i--)
pcmcia_unregister_socket(&socket[i].socket);
break;
}
}
/* Finally, schedule a polling interrupt */ /* Finally, schedule a polling interrupt */
if (poll_interval != 0) { if (poll_interval != 0) {
...@@ -1581,10 +1582,12 @@ static int __init init_i82365(void) ...@@ -1581,10 +1582,12 @@ static int __init init_i82365(void)
static void __exit exit_i82365(void) static void __exit exit_i82365(void)
{ {
int i; int i;
for (i = 0; i < sockets; i++) {
pcmcia_unregister_socket(&socket[i].socket);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
for (i = 0; i < sockets; i++) pcic_proc_remove(i); pcic_proc_remove(i);
#endif #endif
class_device_unregister(&i82365_class_data); }
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);
......
...@@ -148,15 +148,10 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock ...@@ -148,15 +148,10 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
memset(socket, 0, sizeof(*socket)); memset(socket, 0, sizeof(*socket));
/* prepare class_data */ /* prepare pcmcia_socket */
socket->cls_d.sock_offset = nr; socket->socket.ss_entry = &pci_socket_operations;
socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses socket->socket.dev.dev = &dev->dev;
this yet */ socket->socket.driver_data = socket;
socket->cls_d.ops = &pci_socket_operations;
socket->cls_d.class_dev.class = &pcmcia_socket_class;
socket->cls_d.class_dev.dev = &dev->dev;
strlcpy(socket->cls_d.class_dev.class_id, dev->dev.bus_id, BUS_ID_SIZE);
class_set_devdata(&socket->cls_d.class_dev, &socket->cls_d);
/* prepare pci_socket_t */ /* prepare pci_socket_t */
socket->dev = dev; socket->dev = dev;
...@@ -168,7 +163,7 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock ...@@ -168,7 +163,7 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
socket->dev = NULL; socket->dev = NULL;
pci_set_drvdata(dev, NULL); pci_set_drvdata(dev, NULL);
} else { } else {
class_device_register(&socket->cls_d.class_dev); pcmcia_register_socket(&socket->socket);
} }
return err; return err;
} }
...@@ -196,7 +191,7 @@ static void __devexit cardbus_remove (struct pci_dev *dev) ...@@ -196,7 +191,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);
/* note: we are already unregistered from the cs core */ /* note: we are already unregistered from the cs core */
class_device_unregister(&socket->cls_d.class_dev); pcmcia_unregister_socket(&socket->socket);
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);
...@@ -204,14 +199,12 @@ static void __devexit cardbus_remove (struct pci_dev *dev) ...@@ -204,14 +199,12 @@ static void __devexit cardbus_remove (struct pci_dev *dev)
static int cardbus_suspend (struct pci_dev *dev, u32 state) static int cardbus_suspend (struct pci_dev *dev, u32 state)
{ {
pci_socket_t *socket = pci_get_drvdata(dev); return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
return pcmcia_socket_dev_suspend(&socket->cls_d, state, 0);
} }
static int cardbus_resume (struct pci_dev *dev) static int cardbus_resume (struct pci_dev *dev)
{ {
pci_socket_t *socket = pci_get_drvdata(dev); return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
return pcmcia_socket_dev_resume(&socket->cls_d, RESUME_RESTORE_STATE);
} }
......
...@@ -23,7 +23,7 @@ typedef struct pci_socket { ...@@ -23,7 +23,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; struct pcmcia_socket socket;
/* 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;
......
...@@ -121,6 +121,7 @@ typedef struct socket_info_t { ...@@ -121,6 +121,7 @@ typedef struct socket_info_t {
void *info; void *info;
u_char last_sstat; u_char last_sstat;
u_char id; u_char id;
struct pcmcia_socket socket;
} socket_info_t; } socket_info_t;
static struct timer_list poll_timer; static struct timer_list poll_timer;
...@@ -372,15 +373,11 @@ static int __init get_tcic_id(void) ...@@ -372,15 +373,11 @@ 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",
.bus = &platform_bus_type, .bus = &platform_bus_type,
/* .suspend = pcmcia_socket_dev_suspend, FIXME? */ .suspend = pcmcia_socket_dev_suspend,
/* .resume = pcmcia_socket_dev_resume, FIXME? */ .resume = pcmcia_socket_dev_resume,
}; };
static struct platform_device tcic_device = { static struct platform_device tcic_device = {
...@@ -391,13 +388,10 @@ static struct platform_device tcic_device = { ...@@ -391,13 +388,10 @@ static struct platform_device tcic_device = {
}, },
}; };
static struct class_device tcic_class_data = {
.class = &pcmcia_socket_class,
};
static int __init init_tcic(void) static int __init init_tcic(void)
{ {
int i, sock; int i, sock, ret = 0;
u_int mask, scan; u_int mask, scan;
servinfo_t serv; servinfo_t serv;
...@@ -524,13 +518,17 @@ static int __init init_tcic(void) ...@@ -524,13 +518,17 @@ 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);
tcic_data.nsock = sockets;
tcic_class_data.dev = &tcic_device.dev;
tcic_class_data.class_data = &tcic_data;
strlcpy(tcic_class_data.class_id, "tcic-pcmcia", BUS_ID_SIZE);
platform_device_register(&tcic_device); platform_device_register(&tcic_device);
class_device_register(&tcic_class_data);
for (i = 0; i < sockets; i++) {
socket_table[i].socket.ss_entry = &tcic_operations;
socket_table[i].socket.dev.dev = &tcic_device.dev;
ret = pcmcia_register_socket(&socket_table[i].socket);
if (ret && i)
pcmcia_unregister_socket(&socket_table[0].socket);
}
return ret;
return 0; return 0;
...@@ -540,13 +538,19 @@ static int __init init_tcic(void) ...@@ -540,13 +538,19 @@ static int __init init_tcic(void)
static void __exit exit_tcic(void) static void __exit exit_tcic(void)
{ {
int i;
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);
free_irq(cs_irq, tcic_interrupt); free_irq(cs_irq, tcic_interrupt);
} }
release_region(tcic_base, 16); release_region(tcic_base, 16);
class_device_unregister(&tcic_class_data);
for (i = 0; i < sockets; i++) {
pcmcia_unregister_socket(&socket_table[i].socket);
}
platform_device_unregister(&tcic_device); platform_device_unregister(&tcic_device);
driver_unregister(&tcic_driver); driver_unregister(&tcic_driver);
} /* exit_tcic */ } /* exit_tcic */
......
...@@ -154,13 +154,6 @@ struct pcmcia_socket_class_data { ...@@ -154,13 +154,6 @@ struct pcmcia_socket_class_data {
struct class_device class_dev; /* generic class structure */ struct class_device class_dev; /* generic class structure */
}; };
extern struct class pcmcia_socket_class;
/* socket drivers are expected to use these callbacks in their .drv struct */
extern int pcmcia_socket_dev_suspend(struct pcmcia_socket_class_data *cls_d, u32 state, u32 level);
extern int pcmcia_socket_dev_resume(struct pcmcia_socket_class_data *cls_d, u32 level);
typedef struct erase_busy_t { typedef struct erase_busy_t {
eraseq_entry_t *erase; eraseq_entry_t *erase;
client_handle_t client; client_handle_t client;
...@@ -249,8 +242,24 @@ struct pcmcia_socket { ...@@ -249,8 +242,24 @@ struct pcmcia_socket {
struct resource * cb_cis_res; struct resource * cb_cis_res;
u_char *cb_cis_virt; u_char *cb_cis_virt;
#endif #endif
/* socket device */
struct class_device dev;
void *driver_data; /* data internal to the socket driver */
}; };
__deprecated struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr); struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr);
extern int pcmcia_register_socket(struct pcmcia_socket *socket);
extern void pcmcia_unregister_socket(struct pcmcia_socket *socket);
extern struct class pcmcia_socket_class;
/* socket drivers are expected to use these callbacks in their .drv struct */
extern int pcmcia_socket_dev_suspend(struct device *dev, u32 state, u32 level);
extern int pcmcia_socket_dev_resume(struct device *dev, u32 level);
#endif /* _LINUX_SS_H */ #endif /* _LINUX_SS_H */
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