handler.
*/
-static int avma1cs_config(struct pcmcia_device *link);
-static void avma1cs_release(struct pcmcia_device *link);
+static void avma1cs_config(dev_link_t *link);
+static void avma1cs_release(dev_link_t *link);
/*
The attach() and detach() entry points are used to create and destroy
/*
A linked list of "instances" of the skeleton device. Each actual
PCMCIA card corresponds to one device instance, and is described
- by one struct pcmcia_device structure (defined in ds.h).
+ by one dev_link_t structure (defined in ds.h).
You may not want to use a linked list for this -- for example, the
- memory card driver uses an array of struct pcmcia_device pointers, where minor
+ memory card driver uses an array of dev_link_t pointers, where minor
device numbers are used to derive the corresponding array index.
*/
example, ethernet cards, modems). In other cases, there may be
many actual or logical devices (SCSI adapters, memory cards with
multiple partitions). The dev_node_t structures need to be kept
- in a linked list starting at the 'dev' field of a struct pcmcia_device
+ in a linked list starting at the 'dev' field of a dev_link_t
structure. We allocate them in the card's private data structure,
because they generally can't be allocated dynamically.
*/
======================================================================*/
-static int avma1cs_probe(struct pcmcia_device *p_dev)
+static int avma1cs_attach(struct pcmcia_device *p_dev)
{
+ dev_link_t *link;
local_info_t *local;
DEBUG(0, "avma1cs_attach()\n");
+ /* Initialize the dev_link_t structure */
+ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+ memset(link, 0, sizeof(struct dev_link_t));
+
/* Allocate space for private device-specific data */
local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
- if (!local)
+ if (!local) {
+ kfree(link);
return -ENOMEM;
-
+ }
memset(local, 0, sizeof(local_info_t));
- p_dev->priv = local;
+ link->priv = local;
/* The io structure describes IO port mapping */
- p_dev->io.NumPorts1 = 16;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.NumPorts2 = 16;
- p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
- p_dev->io.IOAddrLines = 5;
+ link->io.NumPorts1 = 16;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.NumPorts2 = 16;
+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+ link->io.IOAddrLines = 5;
/* Interrupt setup */
- p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
- p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
/* General socket configuration */
- p_dev->conf.Attributes = CONF_ENABLE_IRQ;
- p_dev->conf.IntType = INT_MEMORY_AND_IO;
- p_dev->conf.ConfigIndex = 1;
- p_dev->conf.Present = PRESENT_OPTION;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.ConfigIndex = 1;
+ link->conf.Present = PRESENT_OPTION;
- return avma1cs_config(p_dev);
+ link->handle = p_dev;
+ p_dev->instance = link;
+
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ avma1cs_config(link);
+
+ return 0;
} /* avma1cs_attach */
/*======================================================================
======================================================================*/
-static void avma1cs_detach(struct pcmcia_device *link)
+static void avma1cs_detach(struct pcmcia_device *p_dev)
{
- DEBUG(0, "avma1cs_detach(0x%p)\n", link);
- avma1cs_release(link);
- kfree(link->priv);
+ dev_link_t *link = dev_to_instance(p_dev);
+
+ DEBUG(0, "avma1cs_detach(0x%p)\n", link);
+
+ if (link->state & DEV_CONFIG)
+ avma1cs_release(link);
+
+ kfree(link->priv);
+ kfree(link);
} /* avma1cs_detach */
/*======================================================================
======================================================================*/
-static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
+static int get_tuple(client_handle_t handle, tuple_t *tuple,
cisparse_t *parse)
{
int i = pcmcia_get_tuple_data(handle, tuple);
return pcmcia_parse_tuple(handle, tuple, parse);
}
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
+static int first_tuple(client_handle_t handle, tuple_t *tuple,
cisparse_t *parse)
{
int i = pcmcia_get_first_tuple(handle, tuple);
return get_tuple(handle, tuple, parse);
}
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
+static int next_tuple(client_handle_t handle, tuple_t *tuple,
cisparse_t *parse)
{
int i = pcmcia_get_next_tuple(handle, tuple);
return get_tuple(handle, tuple, parse);
}
-static int avma1cs_config(struct pcmcia_device *link)
+static void avma1cs_config(dev_link_t *link)
{
+ client_handle_t handle;
tuple_t tuple;
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
char devname[128];
IsdnCard_t icard;
int busy = 0;
-
+
+ handle = link->handle;
dev = link->priv;
DEBUG(0, "avma1cs_config(0x%p)\n", link);
*/
do {
tuple.DesiredTuple = CISTPL_CONFIG;
- i = pcmcia_get_first_tuple(link, &tuple);
+ i = pcmcia_get_first_tuple(handle, &tuple);
if (i != CS_SUCCESS) break;
tuple.TupleData = buf;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
- i = pcmcia_get_tuple_data(link, &tuple);
+ i = pcmcia_get_tuple_data(handle, &tuple);
if (i != CS_SUCCESS) break;
- i = pcmcia_parse_tuple(link, &tuple, &parse);
+ i = pcmcia_parse_tuple(handle, &tuple, &parse);
if (i != CS_SUCCESS) break;
link->conf.ConfigBase = parse.config.base;
} while (0);
if (i != CS_SUCCESS) {
- cs_error(link, ParseTuple, i);
- return -ENODEV;
+ cs_error(link->handle, ParseTuple, i);
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
}
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
do {
tuple.DesiredTuple = CISTPL_VERS_1;
devname[0] = 0;
- if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) {
+ if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
sizeof(devname));
}
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
tuple.Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- i = first_tuple(link, &tuple, &parse);
+ i = first_tuple(handle, &tuple, &parse);
while (i == CS_SUCCESS) {
if (cf->io.nwin > 0) {
link->conf.ConfigIndex = cf->index;
printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1 - 1);
- i = pcmcia_request_io(link, &link->io);
+ i = pcmcia_request_io(link->handle, &link->io);
if (i == CS_SUCCESS) goto found_port;
}
- i = next_tuple(link, &tuple, &parse);
+ i = next_tuple(handle, &tuple, &parse);
}
found_port:
if (i != CS_SUCCESS) {
- cs_error(link, RequestIO, i);
+ cs_error(link->handle, RequestIO, i);
break;
}
/*
* allocate an interrupt line
*/
- i = pcmcia_request_irq(link, &link->irq);
+ i = pcmcia_request_irq(link->handle, &link->irq);
if (i != CS_SUCCESS) {
- cs_error(link, RequestIRQ, i);
- /* undo */
- pcmcia_disable_device(link);
+ cs_error(link->handle, RequestIRQ, i);
+ pcmcia_release_io(link->handle, &link->io);
break;
}
-
+
/*
* configure the PCMCIA socket
*/
- i = pcmcia_request_configuration(link, &link->conf);
+ i = pcmcia_request_configuration(link->handle, &link->conf);
if (i != CS_SUCCESS) {
- cs_error(link, RequestConfiguration, i);
- pcmcia_disable_device(link);
+ cs_error(link->handle, RequestConfiguration, i);
+ pcmcia_release_io(link->handle, &link->io);
+ pcmcia_release_irq(link->handle, &link->irq);
break;
}
strcpy(dev->node.dev_name, "A1");
dev->node.major = 45;
dev->node.minor = 0;
- link->dev_node = &dev->node;
-
+ link->dev = &dev->node;
+
+ link->state &= ~DEV_CONFIG_PENDING;
/* If any step failed, release any partially configured state */
if (i != 0) {
avma1cs_release(link);
- return -ENODEV;
+ return;
}
printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
if (i < 0) {
printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
avma1cs_release(link);
- return -ENODEV;
+ return;
}
dev->node.minor = i;
- return 0;
} /* avma1cs_config */
/*======================================================================
======================================================================*/
-static void avma1cs_release(struct pcmcia_device *link)
+static void avma1cs_release(dev_link_t *link)
{
- local_info_t *local = link->priv;
+ local_info_t *local = link->priv;
- DEBUG(0, "avma1cs_release(0x%p)\n", link);
+ DEBUG(0, "avma1cs_release(0x%p)\n", link);
- /* now unregister function with hisax */
- HiSax_closecard(local->node.minor);
+ /* no unregister function with hisax */
+ HiSax_closecard(local->node.minor);
- pcmcia_disable_device(link);
+ /* Unlink the device chain */
+ link->dev = NULL;
+
+ /* Don't bother checking to see if these succeed or not */
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+ pcmcia_release_irq(link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
} /* avma1cs_release */
+static int avma1cs_suspend(struct pcmcia_device *dev)
+{
+ dev_link_t *link = dev_to_instance(dev);
+
+ link->state |= DEV_SUSPEND;
+ if (link->state & DEV_CONFIG)
+ pcmcia_release_configuration(link->handle);
+
+ return 0;
+}
+
+static int avma1cs_resume(struct pcmcia_device *dev)
+{
+ dev_link_t *link = dev_to_instance(dev);
+
+ link->state &= ~DEV_SUSPEND;
+ if (link->state & DEV_CONFIG)
+ pcmcia_request_configuration(link->handle, &link->conf);
+
+ return 0;
+}
+
static struct pcmcia_device_id avma1cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
.drv = {
.name = "avma1_cs",
},
- .probe = avma1cs_probe,
+ .probe = avma1cs_attach,
.remove = avma1cs_detach,
.id_table = avma1cs_ids,
+ .suspend = avma1cs_suspend,
+ .resume = avma1cs_resume,
};
-
+
/*====================================================================*/
static int __init init_avma1_cs(void)