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