Path: blob/master/drivers/isdn/hardware/avm/avm_cs.c
15111 views
/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $1*2* A PCMCIA client driver for AVM B1/M1/M23*4* Copyright 1999 by Carsten Paeth <[email protected]>5*6* This software may be used and distributed according to the terms7* of the GNU General Public License, incorporated herein by reference.8*9*/1011#include <linux/module.h>12#include <linux/kernel.h>13#include <linux/init.h>14#include <linux/ptrace.h>15#include <linux/string.h>16#include <linux/tty.h>17#include <linux/serial.h>18#include <linux/major.h>19#include <asm/io.h>20#include <asm/system.h>2122#include <pcmcia/cistpl.h>23#include <pcmcia/ciscode.h>24#include <pcmcia/ds.h>25#include <pcmcia/cisreg.h>2627#include <linux/skbuff.h>28#include <linux/capi.h>29#include <linux/b1lli.h>30#include <linux/b1pcmcia.h>3132/*====================================================================*/3334MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");35MODULE_AUTHOR("Carsten Paeth");36MODULE_LICENSE("GPL");3738/*====================================================================*/3940static int avmcs_config(struct pcmcia_device *link);41static void avmcs_release(struct pcmcia_device *link);42static void avmcs_detach(struct pcmcia_device *p_dev);4344static int avmcs_probe(struct pcmcia_device *p_dev)45{46/* General socket configuration */47p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;48p_dev->config_index = 1;49p_dev->config_regs = PRESENT_OPTION;5051return avmcs_config(p_dev);52} /* avmcs_attach */535455static void avmcs_detach(struct pcmcia_device *link)56{57avmcs_release(link);58} /* avmcs_detach */5960static int avmcs_configcheck(struct pcmcia_device *p_dev, void *priv_data)61{62p_dev->resource[0]->end = 16;63p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;64p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;6566return pcmcia_request_io(p_dev);67}6869static int avmcs_config(struct pcmcia_device *link)70{71int i = -1;72char devname[128];73int cardtype;74int (*addcard)(unsigned int port, unsigned irq);7576devname[0] = 0;77if (link->prod_id[1])78strlcpy(devname, link->prod_id[1], sizeof(devname));7980/*81* find IO port82*/83if (pcmcia_loop_config(link, avmcs_configcheck, NULL))84return -ENODEV;8586do {87if (!link->irq) {88/* undo */89pcmcia_disable_device(link);90break;91}9293/*94* configure the PCMCIA socket95*/96i = pcmcia_enable_device(link);97if (i != 0) {98pcmcia_disable_device(link);99break;100}101102} while (0);103104if (devname[0]) {105char *s = strrchr(devname, ' ');106if (!s)107s = devname;108else s++;109if (strcmp("M1", s) == 0) {110cardtype = AVM_CARDTYPE_M1;111} else if (strcmp("M2", s) == 0) {112cardtype = AVM_CARDTYPE_M2;113} else {114cardtype = AVM_CARDTYPE_B1;115}116} else117cardtype = AVM_CARDTYPE_B1;118119/* If any step failed, release any partially configured state */120if (i != 0) {121avmcs_release(link);122return -ENODEV;123}124125126switch (cardtype) {127case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;128case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;129default:130case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;131}132if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) {133dev_err(&link->dev,134"avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",135(unsigned int) link->resource[0]->start, link->irq);136avmcs_release(link);137return -ENODEV;138}139return 0;140141} /* avmcs_config */142143144static void avmcs_release(struct pcmcia_device *link)145{146b1pcmcia_delcard(link->resource[0]->start, link->irq);147pcmcia_disable_device(link);148} /* avmcs_release */149150151static const struct pcmcia_device_id avmcs_ids[] = {152PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),153PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),154PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),155PCMCIA_DEVICE_NULL156};157MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);158159static struct pcmcia_driver avmcs_driver = {160.owner = THIS_MODULE,161.name = "avm_cs",162.probe = avmcs_probe,163.remove = avmcs_detach,164.id_table = avmcs_ids,165};166167static int __init avmcs_init(void)168{169return pcmcia_register_driver(&avmcs_driver);170}171172static void __exit avmcs_exit(void)173{174pcmcia_unregister_driver(&avmcs_driver);175}176177module_init(avmcs_init);178module_exit(avmcs_exit);179180181