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,
======================================================================*/
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
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;
/* base address = 0, map = 0 */
......@@ -352,8 +405,9 @@ static int pcmcia_add_socket(struct pcmcia_socket *socket)
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;
#ifdef CONFIG_PROC_FS
......@@ -385,66 +439,74 @@ static void pcmcia_remove_socket(struct pcmcia_socket *socket)
/**
* 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);
socket_info_t *s_info;
unsigned int i, ret;
if (!cls_d)
if (!socket || !socket->ss_entry || !socket->dev.dev)
return -EINVAL;
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", cls_d->ops);
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));
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ss_entry);
cls_d->s_info = s_info;
ret = 0;
/* try to obtain a socket number [yes, it gets ugly if we
* 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);
list_add(&socket->socket_list, &pcmcia_socket_list);
list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem);
pcmcia_add_socket(socket);
return -EINVAL;
}
return ret;
return 0;
} /* pcmcia_register_socket */
EXPORT_SYMBOL(pcmcia_register_socket);
/**
* 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);
unsigned int i;
struct pcmcia_socket *socket;
if (!cls_d)
if (!socket)
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++) {
pcmcia_remove_socket(socket);
/* remove from the device core */
class_device_unregister(&socket->dev);
/* remove from our own list */
down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem);
socket++;
}
kfree(cls_d->s_info);
} /* pcmcia_unregister_socket */
EXPORT_SYMBOL(pcmcia_unregister_socket);
struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
......@@ -829,68 +891,6 @@ static void parse_events(void *info, u_int events)
wake_up(&s->thread_wait);
} /* 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);
EXPORT_SYMBOL(proc_pccard);
#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 = {
.name = "pcmcia_socket",
};
......@@ -2559,8 +2554,8 @@ EXPORT_SYMBOL(pcmcia_socket_class);
static struct class_interface pcmcia_socket = {
.class = &pcmcia_socket_class,
.add = &pcmcia_register_socket,
.remove = &pcmcia_unregister_socket,
.add = &pcmcia_add_socket,
.remove = &pcmcia_remove_socket,
};
......
......@@ -107,7 +107,6 @@ struct pcmcia_bus_socket {
struct work_struct removal;
socket_bind_t *bind;
struct device *socket_dev;
struct list_head socket_list;
unsigned int socket_no; /* deprecated */
struct pcmcia_socket *parent;
};
......@@ -123,10 +122,6 @@ static dev_info_t dev_info = "Driver Services";
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;
/*====================================================================*/
......@@ -825,8 +820,9 @@ static struct file_operations ds_fops = {
.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;
bind_req_t bind;
struct pcmcia_bus_socket *s;
......@@ -848,7 +844,7 @@ static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct
init_waitqueue_head(&s->request);
/* initialize data */
s->socket_dev = dev;
s->socket_dev = socket->dev.dev;
INIT_WORK(&s->removal, handle_removal, s);
s->socket_no = socket->sock;
s->parent = socket;
......@@ -882,51 +878,25 @@ static int __devinit pcmcia_bus_add_socket(struct pcmcia_socket *socket, struct
}
socket->pcmcia = s;
list_add(&s->socket_list, &bus_socket_list);
return 0;
}
static int pcmcia_bus_add_socket_dev(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)
static void pcmcia_bus_remove_socket(struct class_device *class_dev)
{
struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
struct list_head *list_loop;
struct list_head *tmp_storage;
struct pcmcia_socket *socket = class_dev->class_data;
if (!cls_d)
if (!socket || !socket->pcmcia)
return;
flush_scheduled_work();
down_write(&bus_socket_list_rwsem);
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);
if (bus_sock->socket_dev == class_dev->dev) {
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);
pcmcia_deregister_client(socket->pcmcia->handle);
kfree(socket->pcmcia);
socket->pcmcia = NULL;
return;
}
......@@ -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 */
static struct class_interface pcmcia_bus_interface = {
.class = &pcmcia_socket_class,
.add = &pcmcia_bus_add_socket_dev,
.remove = &pcmcia_bus_remove_socket_dev,
.add = &pcmcia_bus_add_socket,
.remove = &pcmcia_bus_remove_socket,
};
......
......@@ -44,14 +44,12 @@ MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
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(cls_d, state, 0);
return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
}
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(cls_d, RESUME_RESTORE_STATE);
return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
}
static struct pci_driver i82092aa_pci_drv = {
......@@ -95,6 +93,7 @@ struct socket_info {
/* callback to the driver of the card */
void *info; /* to be passed to the handler */
struct pcmcia_socket 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
{
unsigned char configbyte;
int i, ret;
struct pcmcia_socket_class_data *cls_d;
enter("i82092aa_pci_probe");
......@@ -166,26 +164,26 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
goto err_out_free_res;
}
pci_set_drvdata(dev, &sockets[i].socket);
cls_d = kmalloc(sizeof(*cls_d), GFP_KERNEL);
if (!cls_d) {
printk(KERN_ERR "i82092aa: kmalloc failed\n");
goto err_out_free_irq;
for (i = 0; i<socket_count; i++) {
sockets[i].socket.dev.dev = &dev->dev;
sockets[i].socket.ss_entry = &i82092aa_operations;
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");
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);
err_out_free_res:
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
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");
free_irq(dev->irq, i82092aa_interrupt);
if (cls_d) {
class_device_unregister(&cls_d->class_dev);
kfree(cls_d);
}
if (socket)
pcmcia_unregister_socket(socket);
leave("i82092aa_pci_remove");
}
......
......@@ -166,6 +166,7 @@ typedef struct vg46x_state_t {
typedef struct socket_info_t {
u_short type, flags;
struct pcmcia_socket socket;
socket_cap_t cap;
ioaddr_t ioaddr;
u_short psock;
......@@ -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 = {
.name = "i82365",
.bus = &platform_bus_type,
/* .suspend = pcmcia_socket_dev_suspend, FIXME? */
/* .resume = pcmcia_socket_dev_resume, FIXME? */
.suspend = pcmcia_socket_dev_suspend,
.resume = pcmcia_socket_dev_resume,
};
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)
{
servinfo_t serv;
int i, ret;
pcmcia_get_card_services_info(&serv);
if (serv.Revision != CS_RELEASE_CODE) {
printk(KERN_NOTICE "i82365: Card Services release "
......@@ -1551,19 +1546,25 @@ static int __init init_i82365(void)
return -ENODEV;
}
platform_device_register(&i82365_device);
/* Set up interrupt handler(s) */
#ifdef CONFIG_ISA
if (grab_irq != 0)
request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
#endif
i82365_data.nsock = sockets;
i82365_class_data.dev = &i82365_device.dev;
i82365_class_data.class_data = &i82365_data;
strlcpy(i82365_class_data.class_id, "i82365", BUS_ID_SIZE);
platform_device_register(&i82365_device);
class_device_register(&i82365_class_data);
/* register sockets with the pcmcia core */
for (i = 0; i < sockets; i++) {
socket[i].socket.dev.dev = &i82365_device.dev;
socket[i].socket.ss_entry = &pcic_operations;
ret = pcmcia_register_socket(&socket[i].socket);
if (ret && i--) {
for (; i>= 0; i--)
pcmcia_unregister_socket(&socket[i].socket);
break;
}
}
/* Finally, schedule a polling interrupt */
if (poll_interval != 0) {
......@@ -1581,10 +1582,12 @@ static int __init init_i82365(void)
static void __exit exit_i82365(void)
{
int i;
for (i = 0; i < sockets; i++) {
pcmcia_unregister_socket(&socket[i].socket);
#ifdef CONFIG_PROC_FS
for (i = 0; i < sockets; i++) pcic_proc_remove(i);
pcic_proc_remove(i);
#endif
class_device_unregister(&i82365_class_data);
}
platform_device_unregister(&i82365_device);
if (poll_interval != 0)
del_timer_sync(&poll_timer);
......
......@@ -148,15 +148,10 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
memset(socket, 0, sizeof(*socket));
/* prepare class_data */
socket->cls_d.sock_offset = nr;
socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses
this yet */
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 pcmcia_socket */
socket->socket.ss_entry = &pci_socket_operations;
socket->socket.dev.dev = &dev->dev;
socket->socket.driver_data = socket;
/* prepare pci_socket_t */
socket->dev = dev;
......@@ -168,7 +163,7 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
socket->dev = NULL;
pci_set_drvdata(dev, NULL);
} else {
class_device_register(&socket->cls_d.class_dev);
pcmcia_register_socket(&socket->socket);
}
return err;
}
......@@ -196,7 +191,7 @@ static void __devexit cardbus_remove (struct pci_dev *dev)
pci_socket_t *socket = pci_get_drvdata(dev);
/* 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)
socket->op->close(socket);
pci_set_drvdata(dev, NULL);
......@@ -204,14 +199,12 @@ static void __devexit cardbus_remove (struct pci_dev *dev)
static int cardbus_suspend (struct pci_dev *dev, u32 state)
{
pci_socket_t *socket = pci_get_drvdata(dev);
return pcmcia_socket_dev_suspend(&socket->cls_d, state, 0);
return pcmcia_socket_dev_suspend(&dev->dev, state, 0);
}
static int cardbus_resume (struct pci_dev *dev)
{
pci_socket_t *socket = pci_get_drvdata(dev);
return pcmcia_socket_dev_resume(&socket->cls_d, RESUME_RESTORE_STATE);
return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
}
......
......@@ -23,7 +23,7 @@ typedef struct pci_socket {
struct work_struct tq_task;
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.. */
unsigned int private[8];
} pci_socket_t;
......
......@@ -121,6 +121,7 @@ typedef struct socket_info_t {
void *info;
u_char last_sstat;
u_char id;
struct pcmcia_socket socket;
} socket_info_t;
static struct timer_list poll_timer;
......@@ -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 = {
.name = "tcic-pcmcia",
.bus = &platform_bus_type,
/* .suspend = pcmcia_socket_dev_suspend, FIXME? */
/* .resume = pcmcia_socket_dev_resume, FIXME? */
.suspend = pcmcia_socket_dev_suspend,
.resume = pcmcia_socket_dev_resume,
};
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)
{
int i, sock;
int i, sock, ret = 0;
u_int mask, scan;
servinfo_t serv;
......@@ -524,13 +518,17 @@ static int __init init_tcic(void)
/* jump start interrupt handler, if needed */
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);
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;
......@@ -540,13 +538,19 @@ static int __init init_tcic(void)
static void __exit exit_tcic(void)
{
int i;
del_timer_sync(&poll_timer);
if (cs_irq != 0) {
tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
free_irq(cs_irq, tcic_interrupt);
}
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);
driver_unregister(&tcic_driver);
} /* exit_tcic */
......
......@@ -154,13 +154,6 @@ struct pcmcia_socket_class_data {
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 {
eraseq_entry_t *erase;
client_handle_t client;
......@@ -249,8 +242,24 @@ struct pcmcia_socket {
struct resource * cb_cis_res;
u_char *cb_cis_virt;
#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 */
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