avm_cs.c revision cc3b4866bee996c922e875b8c8efe9f0d8803aae
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A PCMCIA client driver for AVM B1/M1/M2 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 by Carsten Paeth <calle@calle.de> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cs_types.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cs.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ciscode.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/capi.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/b1lli.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/b1pcmcia.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2"); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Carsten Paeth"); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The event() function is this driver's Card Services event handler. 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds It will be called by Card Services when an appropriate card status 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event is received. The config() and release() entry points are 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds used to configure or release a socket, in response to card insertion 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and ejection events. They are invoked from the skeleton event 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handler. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void avmcs_config(dev_link_t *link); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void avmcs_release(dev_link_t *link); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int avmcs_event(event_t event, int priority, 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event_callback_args_t *args); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The attach() and detach() entry points are used to create and destroy 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "instances" of the driver, where each instance represents everything 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds needed to manage one actual PCMCIA card. 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_link_t *avmcs_attach(void); 66cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void avmcs_detach(struct pcmcia_device *p_dev); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The dev_info variable is the "key" that is used to match up this 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device driver with appropriate cards, through the card configuration 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds database. 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_info_t dev_info = "avm_cs"; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds A linked list of "instances" of the skeleton device. Each actual 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCMCIA card corresponds to one device instance, and is described 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds by one dev_link_t structure (defined in ds.h). 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You may not want to use a linked list for this -- for example, the 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memory card driver uses an array of dev_link_t pointers, where minor 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device numbers are used to derive the corresponding array index. 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_link_t *dev_list = NULL; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds A dev_link_t structure has fields for most things that are needed 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to keep track of a socket, but there will usually be some device 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds specific information that also needs to be kept track of. The 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 'priv' pointer in a dev_link_t structure can be used to point to 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a device-specific private data structure, like this. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds A driver needs to provide a dev_node_t structure for each device 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds on a card. In some cases, there is only one device per card (for 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds example, ethernet cards, modems). In other cases, there may be 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds many actual or logical devices (SCSI adapters, memory cards with 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multiple partitions). The dev_node_t structures need to be kept 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in a linked list starting at the 'dev' field of a dev_link_t 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds structure. We allocate them in the card's private data structure, 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds because they generally can't be allocated dynamically. 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct local_info_t { 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_node_t node; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} local_info_t; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================== 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds avmcs_attach() creates an "instance" of the driver, allocating 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local data structures for one device. The device is registered 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with Card Services. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The dev_link structure is initialized, but we don't actually 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds configure the card at this point -- we wait until we receive a 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card insertion event. 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dev_link_t *avmcs_attach(void) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg_t client_reg; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t *link; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_info_t *local; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the dev_link_t structure */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!link) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(link, 0, sizeof(struct dev_link_t)); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The io structure describes IO port mapping */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.NumPorts1 = 16; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.NumPorts2 = 0; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interrupt setup */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->irq.IRQInfo1 = IRQ_LEVEL_ID; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* General socket configuration */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Attributes = CONF_ENABLE_IRQ; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Vcc = 50; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.IntType = INT_MEMORY_AND_IO; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.ConfigIndex = 1; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.Present = PRESENT_OPTION; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate space for private device-specific data */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local = kmalloc(sizeof(local_info_t), GFP_KERNEL); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!local) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_kfree; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(local, 0, sizeof(local_info_t)); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->priv = local; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register with Card Services */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->next = dev_list; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_list = link; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.dev_info = &dev_info; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.Version = 0x0210; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_reg.event_callback_args.client_data = link; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pcmcia_register_client(&link->handle, &client_reg); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 0) { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, RegisterClient, ret); 168cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski avmcs_detach(link->handle); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return link; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_kfree: 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err: 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_attach */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================== 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This deletes a driver "instance". The device is de-registered 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with Card Services. If it has been released, all local data 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds structures are freed. Otherwise, the structures will be freed 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds when the device is released. 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void avmcs_detach(struct pcmcia_device *p_dev) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 190cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski dev_link_t *link = dev_to_instance(p_dev); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t **linkp; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Locate device structure */ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*linkp == link) break; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*linkp == NULL) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 199cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski if (link->state & DEV_CONFIG) 200cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski avmcs_release(link); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unlink device structure, free pieces */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *linkp = link->next; 2043c7208f253571ee5f157b98f0e315b5172afe092Jesper Juhl kfree(link->priv); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(link); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_detach */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================== 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds avmcs_config() is scheduled to run after a CARD_INSERTION event 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is received, to configure the PCMCIA socket, and to make the 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ethernet device available to the system. 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_tuple(client_handle_t handle, tuple_t *tuple, 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cisparse_t *parse) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = pcmcia_get_tuple_data(handle, tuple); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) return i; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pcmcia_parse_tuple(handle, tuple, parse); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int first_tuple(client_handle_t handle, tuple_t *tuple, 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cisparse_t *parse) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = pcmcia_get_first_tuple(handle, tuple); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) return i; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_tuple(handle, tuple, parse); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int next_tuple(client_handle_t handle, tuple_t *tuple, 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cisparse_t *parse) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = pcmcia_get_next_tuple(handle, tuple); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) return i; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_tuple(handle, tuple, parse); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void avmcs_config(dev_link_t *link) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_handle_t handle; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple_t tuple; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cisparse_t parse; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cistpl_cftable_entry_t *cf = &parse.cftable_entry; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_info_t *dev; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char buf[64]; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char devname[128]; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cardtype; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int (*addcard)(unsigned int port, unsigned irq); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle = link->handle; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = link->priv; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This reads the card's CONFIG tuple to find its configuration 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds registers. 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.DesiredTuple = CISTPL_CONFIG; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pcmcia_get_first_tuple(handle, &tuple); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) break; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleData = buf; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleDataMax = 64; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleOffset = 0; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pcmcia_get_tuple_data(handle, &tuple); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) break; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pcmcia_parse_tuple(handle, &tuple, &parse); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) break; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.ConfigBase = parse.config.base; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) { 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, ParseTuple, i); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_CONFIG_PENDING; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Configure card */ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state |= DEV_CONFIG; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.Attributes = 0; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleData = buf; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleDataMax = 254; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleOffset = 0; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.DesiredTuple = CISTPL_VERS_1; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devname[0] = 0; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(devname)); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * find IO port 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleData = (cisdata_t *)buf; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.TupleOffset = 0; tuple.TupleDataMax = 255; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.Attributes = 0; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = first_tuple(handle, &tuple, &parse); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i == CS_SUCCESS) { 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cf->io.nwin > 0) { 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->conf.ConfigIndex = cf->index; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.BasePort1 = cf->io.win[0].base; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.NumPorts1 = cf->io.win[0].len; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.NumPorts2 = 0; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.BasePort1, 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->io.BasePort1+link->io.NumPorts1-1); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pcmcia_request_io(link->handle, &link->io); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == CS_SUCCESS) goto found_port; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = next_tuple(handle, &tuple, &parse); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound_port: 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) { 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, RequestIO, i); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocate an interrupt line 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pcmcia_request_irq(link->handle, &link->irq); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, RequestIRQ, i); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_io(link->handle, &link->io); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configure the PCMCIA socket 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pcmcia_request_configuration(link->handle, &link->conf); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != CS_SUCCESS) { 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs_error(link->handle, RequestConfiguration, i); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_io(link->handle, &link->io); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_irq(link->handle, &link->irq); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* At this point, the dev_node_t structure(s) should be 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initialized and arranged in a linked list at link->dev. */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devname[0]) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *s = strrchr(devname, ' '); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = devname; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else s++; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(dev->node.dev_name, s); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strcmp("M1", s) == 0) { 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardtype = AVM_CARDTYPE_M1; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strcmp("M2", s) == 0) { 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardtype = AVM_CARDTYPE_M2; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardtype = AVM_CARDTYPE_B1; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(dev->node.dev_name, "b1"); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardtype = AVM_CARDTYPE_B1; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->node.major = 64; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->node.minor = 0; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->dev = &dev->node; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_CONFIG_PENDING; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If any step failed, release any partially configured state */ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != 0) { 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds avmcs_release(link); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cardtype) { 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) { 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds avmcs_release(link); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->node.minor = i; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_config */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================== 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds After a card is removed, avmcs_release() will unregister the net 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device, and release the PCMCIA configuration. If the device is 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds still open, this will be postponed until it is closed. 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void avmcs_release(dev_link_t *link) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unlink the device chain */ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->dev = NULL; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't bother checking to see if these succeed or not */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_configuration(link->handle); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_io(link->handle, &link->io); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_release_irq(link->handle, &link->irq); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state &= ~DEV_CONFIG; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_release */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowskistatic int avmcs_suspend(struct pcmcia_device *dev) 41998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 42098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski dev_link_t *link = dev_to_instance(dev); 42198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 42298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski link->state |= DEV_SUSPEND; 42398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski if (link->state & DEV_CONFIG) 42498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski pcmcia_release_configuration(link->handle); 42598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 42698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 42798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 42898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 42998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowskistatic int avmcs_resume(struct pcmcia_device *dev) 43098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 43198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski dev_link_t *link = dev_to_instance(dev); 43298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 43398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski link->state &= ~DEV_SUSPEND; 43498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski if (link->state & DEV_CONFIG) 43598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski pcmcia_request_configuration(link->handle, &link->conf); 43698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 43798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 43898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 43998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================== 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The card status event handler. Mostly, this schedules other 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stuff to run after an event is received. A CARD_REMOVAL event 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds also sets some flags to discourage the net drivers from trying 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to talk to the card any more. 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds When a CARD_REMOVAL event is received, we immediately set a flag 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to block future accesses to this device. All the functions that 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actually access the device should check this flag to make sure 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the card is still present. 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int avmcs_event(event_t event, int priority, 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event_callback_args_t *args) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_link_t *link = args->client_data; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (event) { 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS_EVENT_CARD_INSERTION: 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds avmcs_config(link); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* avmcs_event */ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 468a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowskistatic struct pcmcia_device_id avmcs_ids[] = { 469a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), 470a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430), 471a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a), 472a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski PCMCIA_DEVICE_NULL 473a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski}; 474a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, avmcs_ids); 475a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver avmcs_driver = { 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "avm_cs", 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = avmcs_attach, 4821e212f3645a6b355de8c43a23376bc0e2ac49a63Dominik Brodowski .event = avmcs_event, 483cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski .remove = avmcs_detach, 484a13bcf0d5abaf21a1eb7a988915ab97152f57f78Dominik Brodowski .id_table = avmcs_ids, 48598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .suspend= avmcs_suspend, 48698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .resume = avmcs_resume, 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init avmcs_init(void) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pcmcia_register_driver(&avmcs_driver); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit avmcs_exit(void) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_unregister_driver(&avmcs_driver); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(dev_list != NULL); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(avmcs_init); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(avmcs_exit); 502