2005-04-17 02:20:36 +04:00
/*
* Telephony registration for Linux
*
* ( c ) Copyright 1999 Red Hat Software Inc .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
2008-11-11 17:51:23 +03:00
* Author : Alan Cox , < alan @ lxorguk . ukuu . org . uk >
2005-04-17 02:20:36 +04:00
*
* Fixes : Mar 01 2000 Thomas Sparr , < thomas . l . sparr @ telia . com >
* phone_register_device now works with unit ! = PHONE_UNIT_ANY
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/phonedev.h>
# include <linux/init.h>
# include <asm/uaccess.h>
# include <asm/system.h>
# include <linux/kmod.h>
# include <linux/sem.h>
2006-03-26 13:37:14 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# define PHONE_NUM_DEVICES 256
/*
* Active devices
*/
static struct phone_device * phone_device [ PHONE_NUM_DEVICES ] ;
2006-03-26 13:37:14 +04:00
static DEFINE_MUTEX ( phone_lock ) ;
2005-04-17 02:20:36 +04:00
/*
* Open a phone device .
*/
static int phone_open ( struct inode * inode , struct file * file )
{
unsigned int minor = iminor ( inode ) ;
int err = 0 ;
struct phone_device * p ;
2006-03-28 13:56:41 +04:00
const struct file_operations * old_fops , * new_fops = NULL ;
2005-04-17 02:20:36 +04:00
if ( minor > = PHONE_NUM_DEVICES )
return - ENODEV ;
2006-03-26 13:37:14 +04:00
mutex_lock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
p = phone_device [ minor ] ;
if ( p )
new_fops = fops_get ( p - > f_op ) ;
if ( ! new_fops ) {
2006-03-26 13:37:14 +04:00
mutex_unlock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
request_module ( " char-major-%d-%d " , PHONE_MAJOR , minor ) ;
2006-03-26 13:37:14 +04:00
mutex_lock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
p = phone_device [ minor ] ;
if ( p = = NULL | | ( new_fops = fops_get ( p - > f_op ) ) = = NULL )
{
err = - ENODEV ;
goto end ;
}
}
old_fops = file - > f_op ;
file - > f_op = new_fops ;
if ( p - > open )
err = p - > open ( p , file ) ; /* Tell the device it is open */
if ( err ) {
fops_put ( file - > f_op ) ;
file - > f_op = fops_get ( old_fops ) ;
}
fops_put ( old_fops ) ;
end :
2006-03-26 13:37:14 +04:00
mutex_unlock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
/*
* Telephony For Linux device drivers request registration here .
*/
int phone_register_device ( struct phone_device * p , int unit )
{
int base ;
int end ;
int i ;
base = 0 ;
end = PHONE_NUM_DEVICES - 1 ;
if ( unit ! = PHONE_UNIT_ANY ) {
base = unit ;
end = unit + 1 ; /* enter the loop at least one time */
}
2006-03-26 13:37:14 +04:00
mutex_lock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
for ( i = base ; i < end ; i + + ) {
if ( phone_device [ i ] = = NULL ) {
phone_device [ i ] = p ;
p - > minor = i ;
2006-03-26 13:37:14 +04:00
mutex_unlock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
}
2006-03-26 13:37:14 +04:00
mutex_unlock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
return - ENFILE ;
}
/*
* Unregister an unused Telephony for linux device
*/
void phone_unregister_device ( struct phone_device * pfd )
{
2006-03-26 13:37:14 +04:00
mutex_lock ( & phone_lock ) ;
2007-11-06 01:51:02 +03:00
if ( likely ( phone_device [ pfd - > minor ] = = pfd ) )
phone_device [ pfd - > minor ] = NULL ;
2006-03-26 13:37:14 +04:00
mutex_unlock ( & phone_lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:34 +03:00
static const struct file_operations phone_fops =
2005-04-17 02:20:36 +04:00
{
. owner = THIS_MODULE ,
. open = phone_open ,
} ;
/*
* Board init functions
*/
/*
* Initialise Telephony for linux
*/
static int __init telephony_init ( void )
{
printk ( KERN_INFO " Linux telephony interface: v1.00 \n " ) ;
if ( register_chrdev ( PHONE_MAJOR , " telephony " , & phone_fops ) ) {
printk ( " phonedev: unable to get major %d \n " , PHONE_MAJOR ) ;
return - EIO ;
}
return 0 ;
}
static void __exit telephony_exit ( void )
{
unregister_chrdev ( PHONE_MAJOR , " telephony " ) ;
}
module_init ( telephony_init ) ;
module_exit ( telephony_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
EXPORT_SYMBOL ( phone_register_device ) ;
EXPORT_SYMBOL ( phone_unregister_device ) ;