Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
Note: File does not exist in v6.8.
  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	.llseek		= noop_llseek,
134};
135
136/*
137 *	Board init functions
138 */
139 
140
141/*
142 *    Initialise Telephony for linux
143 */
144
145static int __init telephony_init(void)
146{
147	printk(KERN_INFO "Linux telephony interface: v1.00\n");
148	if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
149		printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
150		return -EIO;
151	}
152
153	return 0;
154}
155
156static void __exit telephony_exit(void)
157{
158	unregister_chrdev(PHONE_MAJOR, "telephony");
159}
160
161module_init(telephony_init);
162module_exit(telephony_exit);
163
164MODULE_LICENSE("GPL");
165
166EXPORT_SYMBOL(phone_register_device);
167EXPORT_SYMBOL(phone_unregister_device);