2005-04-17 02:20:36 +04:00
/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
/*======================================================================
2012-02-20 07:52:38 +04:00
A teles S0 PCMCIA client driver
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
Based on skeleton by David Hinds , dhinds @ allegro . stanford . edu
Written by Christof Petig , christof . petig @ wtal . de
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
Also inspired by ELSA PCMCIA driver
by Klaus Lichtenwalder < Lichtenwalder @ ACM . org >
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
Extensions to new hisax_pcmcia by Karsten Keil
minor changes to be compatible with kernel 2.4 . x
by Jan . Schubert @ GMX . li
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/ioport.h>
# include <asm/io.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/cisreg.h>
# include <pcmcia/ds.h>
# include "hisax_cfg.h"
MODULE_DESCRIPTION ( " ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards " ) ;
MODULE_AUTHOR ( " Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de " ) ;
MODULE_LICENSE ( " GPL " ) ;
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int protocol = 2 ; /* EURO-ISDN Default */
module_param ( protocol , int , 0 ) ;
2012-12-22 01:13:05 +04:00
static int teles_cs_config ( struct pcmcia_device * link ) ;
2006-03-31 19:21:06 +04:00
static void teles_cs_release ( struct pcmcia_device * link ) ;
2012-12-22 01:13:05 +04:00
static void teles_detach ( struct pcmcia_device * p_dev ) ;
2005-04-17 02:20:36 +04:00
typedef struct local_info_t {
2006-03-05 12:45:09 +03:00
struct pcmcia_device * p_dev ;
2012-02-20 07:52:38 +04:00
int busy ;
int cardnr ;
2005-04-17 02:20:36 +04:00
} local_info_t ;
2012-12-22 01:13:05 +04:00
static int teles_probe ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2012-02-20 07:52:38 +04:00
local_info_t * local ;
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
dev_dbg ( & link - > dev , " teles_attach() \n " ) ;
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
/* Allocate space for private device-specific data */
local = kzalloc ( sizeof ( local_info_t ) , GFP_KERNEL ) ;
if ( ! local ) return - ENOMEM ;
local - > cardnr = - 1 ;
2006-03-05 12:45:09 +03:00
2012-02-20 07:52:38 +04:00
local - > p_dev = link ;
link - > priv = local ;
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
link - > config_flags | = CONF_ENABLE_IRQ | CONF_AUTO_SET_IO ;
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
return teles_cs_config ( link ) ;
2005-04-17 02:20:36 +04:00
} /* teles_attach */
2012-12-22 01:13:05 +04:00
static void teles_detach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2006-03-02 02:09:29 +03:00
local_info_t * info = link - > priv ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:50:13 +04:00
dev_dbg ( & link - > dev , " teles_detach(0x%p) \n " , link ) ;
2005-04-17 02:20:36 +04:00
2006-03-02 02:09:29 +03:00
info - > busy = 1 ;
teles_cs_release ( link ) ;
2005-04-17 02:20:36 +04:00
2006-03-02 02:09:29 +03:00
kfree ( info ) ;
2005-04-17 02:20:36 +04:00
} /* teles_detach */
2010-07-30 15:13:46 +04:00
static int teles_cs_configcheck ( struct pcmcia_device * p_dev , void * priv_data )
2005-04-17 02:20:36 +04:00
{
2008-07-29 10:38:55 +04:00
int j ;
2010-07-24 19:23:51 +04:00
p_dev - > io_lines = 5 ;
2010-07-30 15:13:46 +04:00
p_dev - > resource [ 0 ] - > end = 96 ;
p_dev - > resource [ 0 ] - > flags & = IO_DATA_PATH_WIDTH ;
p_dev - > resource [ 0 ] - > flags | = IO_DATA_PATH_WIDTH_AUTO ;
2010-07-24 19:23:51 +04:00
2010-07-30 15:13:46 +04:00
if ( ( p_dev - > resource [ 0 ] - > end ) & & p_dev - > resource [ 0 ] - > start ) {
2008-07-29 10:38:55 +04:00
printk ( KERN_INFO " (teles_cs: looks like the 96 model) \n " ) ;
2010-07-24 19:23:51 +04:00
if ( ! pcmcia_request_io ( p_dev ) )
2008-07-29 10:38:55 +04:00
return 0 ;
} else {
printk ( KERN_INFO " (teles_cs: looks like the 97 model) \n " ) ;
for ( j = 0x2f0 ; j > 0x100 ; j - = 0x10 ) {
2010-07-24 19:23:51 +04:00
p_dev - > resource [ 0 ] - > start = j ;
if ( ! pcmcia_request_io ( p_dev ) )
2008-07-29 10:38:55 +04:00
return 0 ;
}
}
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:13:05 +04:00
static int teles_cs_config ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2012-02-20 07:52:38 +04:00
int i ;
IsdnCard_t icard ;
dev_dbg ( & link - > dev , " teles_config(0x%p) \n " , link ) ;
i = pcmcia_loop_config ( link , teles_cs_configcheck , NULL ) ;
if ( i ! = 0 )
goto cs_failed ;
if ( ! link - > irq )
goto cs_failed ;
i = pcmcia_enable_device ( link ) ;
if ( i ! = 0 )
goto cs_failed ;
2006-03-31 19:26:06 +04:00
2012-02-20 07:52:38 +04:00
icard . para [ 0 ] = link - > irq ;
icard . para [ 1 ] = link - > resource [ 0 ] - > start ;
icard . protocol = protocol ;
icard . typ = ISDN_CTYPE_TELESPCMCIA ;
i = hisax_init_pcmcia ( link , & ( ( ( local_info_t * ) link - > priv ) - > busy ) , & icard ) ;
if ( i < 0 ) {
printk ( KERN_ERR " teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x \n " ,
i , ( unsigned int ) link - > resource [ 0 ] - > start ) ;
teles_cs_release ( link ) ;
return - ENODEV ;
}
( ( local_info_t * ) link - > priv ) - > cardnr = i ;
return 0 ;
2005-04-17 02:20:36 +04:00
cs_failed :
2012-02-20 07:52:38 +04:00
teles_cs_release ( link ) ;
return - ENODEV ;
2005-04-17 02:20:36 +04:00
} /* teles_cs_config */
2006-03-31 19:21:06 +04:00
static void teles_cs_release ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2012-02-20 07:52:38 +04:00
local_info_t * local = link - > priv ;
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
dev_dbg ( & link - > dev , " teles_cs_release(0x%p) \n " , link ) ;
2005-04-17 02:20:36 +04:00
2012-02-20 07:52:38 +04:00
if ( local ) {
if ( local - > cardnr > = 0 ) {
/* no unregister function with hisax */
HiSax_closecard ( local - > cardnr ) ;
}
2005-04-17 02:20:36 +04:00
}
2006-01-15 11:32:39 +03:00
2012-02-20 07:52:38 +04:00
pcmcia_disable_device ( link ) ;
2005-04-17 02:20:36 +04:00
} /* teles_cs_release */
2006-03-31 19:21:06 +04:00
static int teles_suspend ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
local_info_t * dev = link - > priv ;
2012-02-20 07:52:38 +04:00
dev - > busy = 1 ;
2005-11-14 23:21:18 +03:00
return 0 ;
}
2006-03-31 19:21:06 +04:00
static int teles_resume ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
local_info_t * dev = link - > priv ;
2012-02-20 07:52:38 +04:00
dev - > busy = 0 ;
2005-11-14 23:21:18 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2011-05-04 06:29:01 +04:00
static const struct pcmcia_device_id teles_ids [ ] = {
2005-06-28 03:28:24 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " TELES " , " S0/PC " , 0x67b50eae , 0xe9e70119 ) ,
PCMCIA_DEVICE_NULL ,
} ;
MODULE_DEVICE_TABLE ( pcmcia , teles_ids ) ;
2005-04-17 02:20:36 +04:00
static struct pcmcia_driver teles_cs_driver = {
. owner = THIS_MODULE ,
2010-08-08 13:36:26 +04:00
. name = " teles_cs " ,
2006-03-31 19:26:06 +04:00
. probe = teles_probe ,
2012-12-22 01:13:05 +04:00
. remove = teles_detach ,
2005-06-28 03:28:24 +04:00
. id_table = teles_ids ,
2005-11-14 23:21:18 +03:00
. suspend = teles_suspend ,
. resume = teles_resume ,
2005-04-17 02:20:36 +04:00
} ;
2013-03-06 22:26:50 +04:00
module_pcmcia_driver ( teles_cs_driver ) ;