2005-04-16 15:20:36 -07:00
/* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 kai Exp $
*
* Linux driver for HYSDN cards , init functions .
*
* Author Werner Cornelius ( werner @ titro . de ) for Hypercope GmbH
* Copyright 1999 by Werner Cornelius ( werner @ titro . de )
*
* This software may be used and distributed according to the terms
* of the GNU General Public License , incorporated herein by reference .
*
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/poll.h>
# include <linux/vmalloc.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include "hysdn_defs.h"
static struct pci_device_id hysdn_pci_tbl [ ] = {
2007-08-02 18:51:14 -04:00
{ PCI_VENDOR_ID_HYPERCOPE , PCI_DEVICE_ID_HYPERCOPE_PLX ,
PCI_ANY_ID , PCI_SUBDEVICE_ID_HYPERCOPE_METRO , 0 , 0 , BD_METRO } ,
{ PCI_VENDOR_ID_HYPERCOPE , PCI_DEVICE_ID_HYPERCOPE_PLX ,
PCI_ANY_ID , PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 , 0 , 0 , BD_CHAMP2 } ,
{ PCI_VENDOR_ID_HYPERCOPE , PCI_DEVICE_ID_HYPERCOPE_PLX ,
PCI_ANY_ID , PCI_SUBDEVICE_ID_HYPERCOPE_ERGO , 0 , 0 , BD_ERGO } ,
{ PCI_VENDOR_ID_HYPERCOPE , PCI_DEVICE_ID_HYPERCOPE_PLX ,
PCI_ANY_ID , PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO , 0 , 0 , BD_ERGO } ,
2005-04-16 15:20:36 -07:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( pci , hysdn_pci_tbl ) ;
MODULE_DESCRIPTION ( " ISDN4Linux: Driver for HYSDN cards " ) ;
MODULE_AUTHOR ( " Werner Cornelius " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-06-28 20:44:56 -07:00
static int cardmax ; /* number of found cards */
2005-04-16 15:20:36 -07:00
hysdn_card * card_root = NULL ; /* pointer to first card */
2007-08-02 18:51:14 -04:00
static hysdn_card * card_last = NULL ; /* pointer to first card */
2005-04-16 15:20:36 -07:00
/****************************************************************************/
/* The module startup and shutdown code. Only compiled when used as module. */
/* Using the driver as module is always advisable, because the booting */
/* image becomes smaller and the driver code is only loaded when needed. */
/* Additionally newer versions may be activated without rebooting. */
/****************************************************************************/
/****************************************************************************/
/* init_module is called once when the module is loaded to do all necessary */
/* things like autodetect... */
/* If the return value of this function is 0 the init has been successful */
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
2007-08-02 18:51:14 -04:00
2012-12-21 13:13:05 -08:00
static int hysdn_pci_init_one ( struct pci_dev * akt_pcidev ,
const struct pci_device_id * ent )
2007-08-02 18:51:14 -04:00
{
hysdn_card * card ;
int rc ;
rc = pci_enable_device ( akt_pcidev ) ;
if ( rc )
return rc ;
if ( ! ( card = kzalloc ( sizeof ( hysdn_card ) , GFP_KERNEL ) ) ) {
printk ( KERN_ERR " HYSDN: unable to alloc device mem \n " ) ;
rc = - ENOMEM ;
goto err_out ;
}
card - > myid = cardmax ; /* set own id */
card - > bus = akt_pcidev - > bus - > number ;
card - > devfn = akt_pcidev - > devfn ; /* slot + function */
card - > subsysid = akt_pcidev - > subsystem_device ;
card - > irq = akt_pcidev - > irq ;
card - > iobase = pci_resource_start ( akt_pcidev , PCI_REG_PLX_IO_BASE ) ;
card - > plxbase = pci_resource_start ( akt_pcidev , PCI_REG_PLX_MEM_BASE ) ;
card - > membase = pci_resource_start ( akt_pcidev , PCI_REG_MEMORY_BASE ) ;
card - > brdtype = BD_NONE ; /* unknown */
card - > debug_flags = DEF_DEB_FLAGS ; /* set default debug */
card - > faxchans = 0 ; /* default no fax channels */
card - > bchans = 2 ; /* and 2 b-channels */
card - > brdtype = ent - > driver_data ;
if ( ergo_inithardware ( card ) ) {
printk ( KERN_WARNING " HYSDN: card at io 0x%04x already in use \n " , card - > iobase ) ;
rc = - EBUSY ;
goto err_out_card ;
}
cardmax + + ;
card - > next = NULL ; /*end of chain */
if ( card_last )
card_last - > next = card ; /* pointer to next card */
else
card_root = card ;
card_last = card ; /* new chain end */
pci_set_drvdata ( akt_pcidev , card ) ;
return 0 ;
err_out_card :
kfree ( card ) ;
err_out :
pci_disable_device ( akt_pcidev ) ;
return rc ;
}
2012-12-21 13:13:05 -08:00
static void hysdn_pci_remove_one ( struct pci_dev * akt_pcidev )
2007-08-02 18:51:14 -04:00
{
hysdn_card * card = pci_get_drvdata ( akt_pcidev ) ;
pci_set_drvdata ( akt_pcidev , NULL ) ;
if ( card - > stopcard )
card - > stopcard ( card ) ;
# ifdef CONFIG_HYSDN_CAPI
hycapi_capi_release ( card ) ;
# endif
if ( card - > releasehardware )
card - > releasehardware ( card ) ; /* free all hardware resources */
if ( card = = card_root ) {
card_root = card_root - > next ;
if ( ! card_root )
card_last = NULL ;
} else {
hysdn_card * tmp = card_root ;
while ( tmp ) {
if ( tmp - > next = = card )
tmp - > next = card - > next ;
card_last = tmp ;
tmp = tmp - > next ;
}
}
kfree ( card ) ;
pci_disable_device ( akt_pcidev ) ;
}
static struct pci_driver hysdn_pci_driver = {
. name = " hysdn " ,
. id_table = hysdn_pci_tbl ,
. probe = hysdn_pci_init_one ,
2012-12-21 13:13:05 -08:00
. remove = hysdn_pci_remove_one ,
2007-08-02 18:51:14 -04:00
} ;
static int hysdn_have_procfs ;
2005-04-16 15:20:36 -07:00
static int __init
hysdn_init ( void )
{
2007-08-02 18:51:14 -04:00
int rc ;
2005-04-16 15:20:36 -07:00
2011-02-09 13:54:26 -08:00
printk ( KERN_NOTICE " HYSDN: module loaded \n " ) ;
2007-08-02 18:51:14 -04:00
rc = pci_register_driver ( & hysdn_pci_driver ) ;
if ( rc )
return rc ;
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO " HYSDN: %d card(s) found. \n " , cardmax ) ;
2007-08-02 18:51:14 -04:00
if ( ! hysdn_procconf_init ( ) )
hysdn_have_procfs = 1 ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_HYSDN_CAPI
2012-02-19 19:52:38 -08:00
if ( cardmax > 0 ) {
if ( hycapi_init ( ) ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR " HYCAPI: init failed \n " ) ;
2007-08-02 18:51:14 -04:00
if ( hysdn_have_procfs )
hysdn_procconf_release ( ) ;
pci_unregister_driver ( & hysdn_pci_driver ) ;
return - ESPIPE ;
2005-04-16 15:20:36 -07:00
}
}
# endif /* CONFIG_HYSDN_CAPI */
2007-08-02 18:51:14 -04:00
return 0 ; /* no error */
2005-04-16 15:20:36 -07:00
} /* init_module */
/***********************************************************************/
/* cleanup_module is called when the module is released by the kernel. */
/* The routine is only called if init_module has been successful and */
/* the module counter has a value of 0. Otherwise this function will */
/* not be called. This function must release all resources still allo- */
/* cated as after the return from this function the module code will */
/* be removed from memory. */
/***********************************************************************/
static void __exit
hysdn_exit ( void )
{
2007-08-02 18:51:14 -04:00
if ( hysdn_have_procfs )
hysdn_procconf_release ( ) ;
pci_unregister_driver ( & hysdn_pci_driver ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_HYSDN_CAPI
hycapi_cleanup ( ) ;
# endif /* CONFIG_HYSDN_CAPI */
2007-08-02 18:51:14 -04:00
2005-04-16 15:20:36 -07:00
printk ( KERN_NOTICE " HYSDN: module unloaded \n " ) ;
} /* cleanup_module */
module_init ( hysdn_init ) ;
module_exit ( hysdn_exit ) ;