linux/drivers/telephony/phonedev.c
<<
>>
Prefs
   1/*
   2 *            Telephony registration for Linux
   3 *
   4 *              (c) Copyright 1999 Red Hat Software Inc.
   5 *
   6 *              This program is free software; you can redistribute it and/or
   7 *              modify it under the terms of the GNU General Public License
   8 *              as published by the Free Software Foundation; either version
   9 *              2 of the License, or (at your option) any later version.
  10 *
  11 * Author:      Alan Cox, <alan@lxorguk.ukuu.org.uk>
  12 *
  13 * Fixes:       Mar 01 2000 Thomas Sparr, <thomas.l.sparr@telia.com>
  14 *              phone_register_device now works with unit!=PHONE_UNIT_ANY
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/types.h>
  19#include <linux/kernel.h>
  20#include <linux/fs.h>
  21#include <linux/mm.h>
  22#include <linux/string.h>
  23#include <linux/errno.h>
  24#include <linux/phonedev.h>
  25#include <linux/init.h>
  26#include <asm/uaccess.h>
  27#include <asm/system.h>
  28
  29#include <linux/kmod.h>
  30#include <linux/sem.h>
  31#include <linux/mutex.h>
  32
  33#define PHONE_NUM_DEVICES       256
  34
  35/*
  36 *    Active devices 
  37 */
  38
  39static struct phone_device *phone_device[PHONE_NUM_DEVICES];
  40static DEFINE_MUTEX(phone_lock);
  41
  42/*
  43 *    Open a phone device.
  44 */
  45
  46static int phone_open(struct inode *inode, struct file *file)
  47{
  48        unsigned int minor = iminor(inode);
  49        int err = 0;
  50        struct phone_device *p;
  51        const struct file_operations *old_fops, *new_fops = NULL;
  52
  53        if (minor >= PHONE_NUM_DEVICES)
  54                return -ENODEV;
  55
  56        mutex_lock(&phone_lock);
  57        p = phone_device[minor];
  58        if (p)
  59                new_fops = fops_get(p->f_op);
  60        if (!new_fops) {
  61                mutex_unlock(&phone_lock);
  62                request_module("char-major-%d-%d", PHONE_MAJOR, minor);
  63                mutex_lock(&phone_lock);
  64                p = phone_device[minor];
  65                if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
  66                {
  67                        err=-ENODEV;
  68                        goto end;
  69                }
  70        }
  71        old_fops = file->f_op;
  72        file->f_op = new_fops;
  73        if (p->open)
  74                err = p->open(p, file); /* Tell the device it is open */
  75        if (err) {
  76                fops_put(file->f_op);
  77                file->f_op = fops_get(old_fops);
  78        }
  79        fops_put(old_fops);
  80end:
  81        mutex_unlock(&phone_lock);
  82        return err;
  83}
  84
  85/*
  86 *    Telephony For Linux device drivers request registration here.
  87 */
  88
  89int phone_register_device(struct phone_device *p, int unit)
  90{
  91        int base;
  92        int end;
  93        int i;
  94
  95        base = 0;
  96        end = PHONE_NUM_DEVICES - 1;
  97
  98        if (unit != PHONE_UNIT_ANY) {
  99                base = unit;
 100                end = unit + 1;  /* enter the loop at least one time */
 101        }
 102        
 103        mutex_lock(&phone_lock);
 104        for (i = base; i < end; i++) {
 105                if (phone_device[i] == NULL) {
 106                        phone_device[i] = p;
 107                        p->minor = i;
 108                        mutex_unlock(&phone_lock);
 109                        return 0;
 110                }
 111        }
 112        mutex_unlock(&phone_lock);
 113        return -ENFILE;
 114}
 115
 116/*
 117 *    Unregister an unused Telephony for linux device
 118 */
 119
 120void phone_unregister_device(struct phone_device *pfd)
 121{
 122        mutex_lock(&phone_lock);
 123        if (likely(phone_device[pfd->minor] == pfd))
 124                phone_device[pfd->minor] = NULL;
 125        mutex_unlock(&phone_lock);
 126}
 127
 128
 129static const struct file_operations phone_fops =
 130{
 131        .owner          = THIS_MODULE,
 132        .open           = phone_open,
 133};
 134
 135/*
 136 *      Board init functions
 137 */
 138 
 139
 140/*
 141 *    Initialise Telephony for linux
 142 */
 143
 144static int __init telephony_init(void)
 145{
 146        printk(KERN_INFO "Linux telephony interface: v1.00\n");
 147        if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
 148                printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
 149                return -EIO;
 150        }
 151
 152        return 0;
 153}
 154
 155static void __exit telephony_exit(void)
 156{
 157        unregister_chrdev(PHONE_MAJOR, "telephony");
 158}
 159
 160module_init(telephony_init);
 161module_exit(telephony_exit);
 162
 163MODULE_LICENSE("GPL");
 164
 165EXPORT_SYMBOL(phone_register_device);
 166EXPORT_SYMBOL(phone_unregister_device);
 167