summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi_transcode.c
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2008-08-06 18:09:58 +0000
committerShaun Ruffell <sruffell@digium.com>2008-08-06 18:09:58 +0000
commitcd4763bcfad087a8e2e33464e79b4f69a5f31094 (patch)
treed83edd7008142c8d6c7625b7dde044277925a84f /drivers/dahdi/dahdi_transcode.c
parent44ff5a846de3b86f60ae420e3e67a2827fb68f11 (diff)
A significant change to the DAHDI transcoder interface and the wctc4xxp
driver which breaks backwards compatibility. Basically, I've replaced the memory mapped interface with a read/write interface that allows codec_dahdi to communicate with the hardware transcoder the exact size of the packet to be transcoded. This eliminates issues with remote devices that send G729.B CNG packets even though asterisk does not support them. From a user standpoint: - The transcoder drivers are much more robust in light of system / external conditions. From a developer standpoint: - DAHDI_TRANSCODE_OP is no longer supported, instead use DAHDI_TC_ALLOCATE, DAHDI_TC_GETINFO, and write/read. - Memory and stack usage is reduced (stack usage could still be reduced some more by continuing the process of getting rid of the users of wctc4xxp_send_cmd and wctc4xxp_create_cmd). - If more than one card is in the system channels will be allocated in a round-robin fashion from all available cards, reducing contention for the supervisor channel. - There is no longer a tc400b workqueue created that will not show up in the process list. - Commands and their responses are now explicitly matched up which elimated certain errors caused by unsolicited messages from the transcoder confusing the driver. - There is now an option to export a network interface for capturing traffic to/from the hardware transcoder. - codec_test has been removed from the dadhi/linux package. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@4717 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/dahdi_transcode.c')
-rw-r--r--drivers/dahdi/dahdi_transcode.c554
1 files changed, 274 insertions, 280 deletions
diff --git a/drivers/dahdi/dahdi_transcode.c b/drivers/dahdi/dahdi_transcode.c
index ad222bc..d7c1d66 100644
--- a/drivers/dahdi/dahdi_transcode.c
+++ b/drivers/dahdi/dahdi_transcode.c
@@ -3,7 +3,7 @@
*
* Written by Mark Spencer <markster@digium.com>
*
- * Copyright (C) 2006-2007, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
*
* All rights reserved.
*
@@ -21,6 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ *
*/
#include <linux/kernel.h>
@@ -35,13 +36,18 @@
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/page-flags.h>
-#include <linux/moduleparam.h>
#include <asm/io.h>
-
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "dahdi/kernel.h"
+#else
#include <dahdi/kernel.h>
+#endif
-static int debug = 0;
-static struct dahdi_transcoder *trans;
+static int debug;
+LIST_HEAD(trans);
static spinlock_t translock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(dahdi_transcoder_register);
@@ -52,387 +58,375 @@ EXPORT_SYMBOL(dahdi_transcoder_free);
struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans)
{
- struct dahdi_transcoder *ztc;
+ struct dahdi_transcoder *tc;
unsigned int x;
- size_t size = sizeof(*ztc) + (sizeof(ztc->channels[0]) * numchans);
+ size_t size = sizeof(*tc) + (sizeof(tc->channels[0]) * numchans);
- if (!(ztc = kmalloc(size, GFP_KERNEL)))
+ if (!(tc = kmalloc(size, GFP_KERNEL)))
return NULL;
- memset(ztc, 0, size);
- strcpy(ztc->name, "<unspecified>");
- ztc->numchannels = numchans;
- for (x=0;x<ztc->numchannels;x++) {
- init_waitqueue_head(&ztc->channels[x].ready);
- ztc->channels[x].parent = ztc;
- ztc->channels[x].offset = x;
- ztc->channels[x].chan_built = 0;
- ztc->channels[x].built_fmts = 0;
+ memset(tc, 0, size);
+ strcpy(tc->name, "<unspecified>");
+ tc->numchannels = numchans;
+ for (x=0;x<tc->numchannels;x++) {
+ init_waitqueue_head(&tc->channels[x].ready);
+ INIT_LIST_HEAD(&tc->node);
+ tc->channels[x].parent = tc;
}
- return ztc;
+ WARN_ON(!dahdi_transcode_fops);
+ /* Individual transcoders should supply their own file_operations for
+ * write and read. But they will by default use the file_operations
+ * provided by the dahdi_transcode layer. */
+ memcpy(&tc->fops, dahdi_transcode_fops, sizeof(*dahdi_transcode_fops));
+ return tc;
}
-static int schluffen(wait_queue_head_t *q)
+void dahdi_transcoder_free(struct dahdi_transcoder *tc)
{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(q, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- if (!signal_pending(current))
- schedule();
-
- current->state = TASK_RUNNING;
- remove_wait_queue(q, &wait);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- return 0;
+ kfree(tc);
}
-void dahdi_transcoder_free(struct dahdi_transcoder *ztc)
+/* Returns 1 if the item is on the list pointed to by head, otherwise, returns
+ * 0 */
+static int is_on_list(struct list_head *entry, struct list_head *head)
{
- kfree(ztc);
+ struct list_head *cur;
+ list_for_each(cur, head) {
+ if (cur == entry) return 1;
+ }
+ return 0;
}
/* Register a transcoder */
int dahdi_transcoder_register(struct dahdi_transcoder *tc)
{
- struct dahdi_transcoder *cur;
- int res = -EBUSY;
-
spin_lock(&translock);
- for (cur = trans; cur; cur = cur->next) {
- if (cur == tc) {
- spin_unlock(&translock);
- return res;
- }
- }
-
- tc->next = trans;
- trans = tc;
- printk(KERN_INFO "Registered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n",
- tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts);
- res = 0;
+ BUG_ON(is_on_list(&tc->node, &trans));
+ list_add_tail(&tc->node, &trans);
spin_unlock(&translock);
- return res;
+ printk(KERN_INFO "%s: Registered codec translator '%s' " \
+ "with %d transcoders (srcs=%08x, dsts=%08x)\n",
+ THIS_MODULE->name, tc->name, tc->numchannels,
+ tc->srcfmts, tc->dstfmts);
+
+ return 0;
}
/* Unregister a transcoder */
int dahdi_transcoder_unregister(struct dahdi_transcoder *tc)
{
- struct dahdi_transcoder *cur, *prev;
int res = -EINVAL;
- spin_lock(&translock);
- for (cur = trans, prev = NULL; cur; prev = cur, cur = cur->next) {
- if (cur == tc)
- break;
- }
+ /* \todo Perhaps we should check to make sure there isn't a channel
+ * that is still in use? */
- if (!cur) {
+ spin_lock(&translock);
+ if (!is_on_list(&tc->node, &trans)) {
spin_unlock(&translock);
- return res;
+ printk(KERN_WARNING "%s: Failed to unregister %s, which is " \
+ "not currently registerd.\n", THIS_MODULE->name, tc->name);
+ return -EINVAL;
}
+ list_del_init(&tc->node);
+ spin_unlock(&translock);
- if (prev)
- prev->next = tc->next;
- else
- trans = tc->next;
- tc->next = NULL;
- printk(KERN_INFO "Unregistered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n",
+ printk(KERN_INFO "Unregistered codec translator '%s' with %d " \
+ "transcoders (srcs=%08x, dsts=%08x)\n",
tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts);
res = 0;
- spin_unlock(&translock);
return res;
}
/* Alert a transcoder */
-int dahdi_transcoder_alert(struct dahdi_transcoder_channel *ztc)
+int dahdi_transcoder_alert(struct dahdi_transcoder_channel *chan)
{
- if (debug)
- printk(KERN_DEBUG "DAHDI Transcoder Alert!\n");
- if (ztc->tch)
- ztc->tch->status &= ~DAHDI_TC_FLAG_BUSY;
- wake_up_interruptible(&ztc->ready);
-
+ wake_up_interruptible(&chan->ready);
return 0;
}
static int dahdi_tc_open(struct inode *inode, struct file *file)
{
- struct dahdi_transcoder_channel *ztc;
- struct dahdi_transcode_header *zth;
- struct page *page;
-
- if (!(ztc = kmalloc(sizeof(*ztc), GFP_KERNEL)))
- return -ENOMEM;
-
- if (!(zth = kmalloc(sizeof(*zth), GFP_KERNEL | GFP_DMA))) {
- kfree(ztc);
- return -ENOMEM;
- }
-
- memset(ztc, 0, sizeof(*ztc));
- memset(zth, 0, sizeof(*zth));
- ztc->flags = DAHDI_TC_FLAG_TRANSIENT | DAHDI_TC_FLAG_BUSY;
- ztc->tch = zth;
- if (debug)
- printk(KERN_DEBUG "Allocated Transcoder Channel, header is at %p!\n", zth);
- zth->magic = DAHDI_TRANSCODE_MAGIC;
- file->private_data = ztc;
- for (page = virt_to_page(zth);
- page < virt_to_page((unsigned long) zth + sizeof(*zth));
- page++)
- SetPageReserved(page);
-
+ const struct file_operations *original_fops;
+ BUG_ON(!dahdi_transcode_fops);
+ original_fops = file->f_op;
+ file->f_op = dahdi_transcode_fops;
+ file->private_data = NULL;
+ /* Under normal operation, this releases the reference on the DAHDI
+ * module that was created when the file was opened. dahdi_open is
+ * responsible for taking a reference out on this module before
+ * calling this function. */
+ module_put(original_fops->owner);
return 0;
}
-static void ztc_release(struct dahdi_transcoder_channel *ztc)
+static void dtc_release(struct dahdi_transcoder_channel *chan)
{
- struct dahdi_transcode_header *zth = ztc->tch;
- struct page *page;
-
- if (!ztc)
- return;
-
- ztc->flags &= ~(DAHDI_TC_FLAG_BUSY);
-
- if(ztc->tch) {
- for (page = virt_to_page(zth);
- page < virt_to_page((unsigned long) zth + sizeof(*zth));
- page++)
- ClearPageReserved(page);
- kfree(ztc->tch);
+ BUG_ON(!chan);
+ if (chan->parent && chan->parent->release) {
+ chan->parent->release(chan);
}
-
- ztc->tch = NULL;
- /* Actually reset the transcoder channel */
- if (ztc->flags & DAHDI_TC_FLAG_TRANSIENT)
- kfree(ztc);
- if (debug)
- printk(KERN_DEBUG "Released Transcoder!\n");
+ dahdi_tc_clear_busy(chan);
}
static int dahdi_tc_release(struct inode *inode, struct file *file)
{
- ztc_release(file->private_data);
-
+ struct dahdi_transcoder_channel *chan = file->private_data;
+ /* There will not be a transcoder channel associated with this file if
+ * the ALLOCATE ioctl never succeeded.
+ */
+ if (chan) {
+ dtc_release(chan);
+ }
return 0;
}
-static int do_reset(struct dahdi_transcoder_channel **ztc)
+/* Find a free channel on the transcoder and mark it busy. */
+static inline struct dahdi_transcoder_channel *
+get_free_channel(struct dahdi_transcoder *tc)
+
+{
+ struct dahdi_transcoder_channel *chan;
+ int i;
+ /* Should be called with the translock held. */
+ WARN_ON(!spin_is_locked(&translock));
+
+ for (i = 0; i < tc->numchannels; i++) {
+ chan = &tc->channels[i];
+ if (!dahdi_tc_is_busy(chan)) {
+ dahdi_tc_set_busy(chan);
+ return chan;
+ }
+ }
+ return NULL;
+}
+
+/* Search the list for a transcoder that supports the specified format, and
+ * allocate and return an available channel on it.
+ *
+ * Returns either a pointer to the allocated channel, -EBUSY if the format is
+ * supported but all the channels are busy, or -ENODEV if there are not any
+ * transcoders that support the formats.
+ */
+static struct dahdi_transcoder_channel *
+__find_free_channel(struct list_head *list, const struct dahdi_transcoder_formats *fmts)
{
- struct dahdi_transcoder_channel *newztc = NULL, *origztc = NULL;
- struct dahdi_transcode_header *zth = (*ztc)->tch;
struct dahdi_transcoder *tc;
- unsigned int x;
+ struct dahdi_transcoder_channel *chan = NULL;
unsigned int match = 0;
- if (((*ztc)->srcfmt != zth->srcfmt) ||
- ((*ztc)->dstfmt != zth->dstfmt)) {
- /* Find new transcoder */
- spin_lock(&translock);
- for (tc = trans; tc && !newztc; tc = tc->next) {
- if (!(tc->srcfmts & zth->srcfmt))
- continue;
-
- if (!(tc->dstfmts & zth->dstfmt))
- continue;
-
- match = 1;
- for (x = 0; x < tc->numchannels; x++) {
- if (tc->channels[x].flags & DAHDI_TC_FLAG_BUSY)
- continue;
- if ((tc->channels[x].chan_built) && ((zth->srcfmt | zth->dstfmt) != tc->channels[x].built_fmts))
- continue;
-
- newztc = &tc->channels[x];
- newztc->flags = DAHDI_TC_FLAG_BUSY;
- break;
+ list_for_each_entry(tc, list, node) {
+ if ((tc->dstfmts & fmts->dstfmt)) {
+ /* We found a transcoder that can handle our formats.
+ * Now look for an available channel. */
+ match = 1;
+ if ((chan = get_free_channel(tc))) {
+ /* transcoder tc has a free channel. In order
+ * to spread the load among available
+ * transcoders (when there are more than one
+ * transcoder in the system) we'll move tc
+ * to the end of the list. */
+ list_move_tail(&tc->node, list);
+ return chan;
}
}
- spin_unlock(&translock);
+ }
+ return (void*)((match) ? -EBUSY : -ENODEV);
+}
+
+static long dahdi_tc_allocate(struct file *file, unsigned long data)
+{
+ struct dahdi_transcoder_channel *chan = NULL;
+ struct dahdi_transcoder_formats fmts;
+
+ if (copy_from_user(&fmts,
+ (struct dahdi_transcoder_formats*) data, sizeof(fmts))) {
+ return -EFAULT;
+ }
- if (!newztc)
- return match ? -EBUSY : -ENOSYS;
+ spin_lock(&translock);
+ chan = __find_free_channel(&trans, &fmts);
+ spin_unlock(&translock);
- /* Move transcoder header over */
- origztc = (*ztc);
- (*ztc) = newztc;
- (*ztc)->tch = origztc->tch;
- origztc->tch = NULL;
- (*ztc)->flags |= (origztc->flags & ~(DAHDI_TC_FLAG_TRANSIENT));
- ztc_release(origztc);
+ if (IS_ERR(chan)) {
+ return PTR_ERR(chan);
}
- /* Actually reset the transcoder channel */
- if ((*ztc)->parent && ((*ztc)->parent->operation))
- return (*ztc)->parent->operation((*ztc), DAHDI_TCOP_ALLOCATE);
+ /* Every transcoder channel must be associated with a parent
+ * transcoder. */
+ BUG_ON(!chan->parent);
- return -EINVAL;
-}
+ chan->srcfmt = fmts.srcfmt;
+ chan->dstfmt = fmts.dstfmt;
-static int wait_busy(struct dahdi_transcoder_channel *ztc)
-{
- int ret;
+ if (file->private_data) {
+ /* This open file is moving to a new channel. Cleanup and
+ * close the old channel here. */
+ dtc_release(file->private_data);
+ }
+
+ file->private_data = chan;
+ if (chan->parent->fops.owner != file->f_op->owner) {
+ if (!try_module_get(chan->parent->fops.owner)) {
+ /* Failed to get a reference on the driver for the
+ * actual transcoding hardware. */
+ return -EINVAL;
+ }
+ /* Release the reference on the existing driver. */
+ module_put(file->f_op->owner);
+ file->f_op = &chan->parent->fops;
+ }
- for (;;) {
- if (!(ztc->tch->status & DAHDI_TC_FLAG_BUSY))
- return 0;
- if ((ret = schluffen(&ztc->ready)))
- return ret;
+ if (file->f_flags & O_NONBLOCK) {
+ dahdi_tc_set_nonblock(chan);
+ } else {
+ dahdi_tc_clear_nonblock(chan);
}
+
+ /* Actually reset the transcoder channel */
+ if (chan->parent->allocate)
+ return chan->parent->allocate(chan);
+
+ return -EINVAL;
}
-static int dahdi_tc_getinfo(unsigned long data)
+static long dahdi_tc_getinfo(unsigned long data)
{
- struct dahdi_transcode_info info;
+ struct dahdi_transcoder_info info;
unsigned int x;
- struct dahdi_transcoder *tc;
+ struct dahdi_transcoder *cur;
+ struct dahdi_transcoder *tc = NULL;
- if (copy_from_user(&info, (struct dahdi_transcode_info *) data, sizeof(info)))
+ if (copy_from_user(&info, (const void *) data, sizeof(info))) {
return -EFAULT;
+ }
+ x = 0;
spin_lock(&translock);
- for (tc = trans, x = info.tcnum; tc && x; tc = tc->next, x--);
+ list_for_each_entry(cur, &trans, node) {
+ if (x++ == info.tcnum) {
+ tc = cur;
+ break;
+ }
+ }
spin_unlock(&translock);
- if (!tc)
+ if (!tc) {
return -ENOSYS;
+ }
dahdi_copy_string(info.name, tc->name, sizeof(info.name));
info.numchannels = tc->numchannels;
info.srcfmts = tc->srcfmts;
info.dstfmts = tc->dstfmts;
- return copy_to_user((struct dahdi_transcode_info *) data, &info, sizeof(info)) ? -EFAULT : 0;
+ return copy_to_user((void *) data, &info, sizeof(info)) ? -EFAULT : 0;
}
-static int dahdi_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+static ssize_t dahdi_tc_write(struct file *file, __user const char *usrbuf, size_t count, loff_t *ppos)
{
- int op;
- int ret;
- struct dahdi_transcoder_channel *ztc = file->private_data;
-
- if (cmd != DAHDI_TRANSCODE_OP)
+ if (file->private_data) {
+ /* file->private_data will not be NULL if DAHDI_TC_ALLOCATE was
+ * called, and therefore indicates that the transcoder driver
+ * did not export a read function. */
+ WARN_ON(1);
return -ENOSYS;
-
- if (get_user(op, (int *) data))
- return -EFAULT;
-
- if (debug)
- printk(KERN_DEBUG "DAHDI Transcode ioctl op = %d!\n", op);
-
- switch(op) {
- case DAHDI_TCOP_GETINFO:
- ret = dahdi_tc_getinfo(data);
- break;
- case DAHDI_TCOP_ALLOCATE:
- /* Reset transcoder, possibly changing who we point to */
- ret = do_reset(&ztc);
- file->private_data = ztc;
- break;
- case DAHDI_TCOP_RELEASE:
- ret = ztc->parent->operation(ztc, DAHDI_TCOP_RELEASE);
- break;
- case DAHDI_TCOP_TEST:
- ret = ztc->parent->operation(ztc, DAHDI_TCOP_TEST);
- break;
- case DAHDI_TCOP_TRANSCODE:
- if (!ztc->parent->operation)
- return -EINVAL;
-
- ztc->tch->status |= DAHDI_TC_FLAG_BUSY;
- if (!(ret = ztc->parent->operation(ztc, DAHDI_TCOP_TRANSCODE))) {
- /* Wait for busy to go away if we're not non-blocking */
- if (!(file->f_flags & O_NONBLOCK)) {
- if (!(ret = wait_busy(ztc)))
- ret = ztc->errorstatus;
- }
- } else
- ztc->tch->status &= ~DAHDI_TC_FLAG_BUSY;
- break;
- default:
- ret = -ENOSYS;
+ } else {
+ printk(KERN_INFO "%s: Attempt to write to unallocated " \
+ "channel.\n", THIS_MODULE->name);
+ return -EINVAL;
}
-
- return ret;
}
-static int dahdi_tc_mmap(struct file *file, struct vm_area_struct *vma)
+static ssize_t dahdi_tc_read(struct file *file, __user char *usrbuf, size_t count, loff_t *ppos)
{
- struct dahdi_transcoder_channel *ztc = file->private_data;
- unsigned long physical;
- int res;
-
- if (!ztc)
- return -EINVAL;
-
- /* Do not allow an offset */
- if (vma->vm_pgoff) {
- if (debug)
- printk(KERN_DEBUG "zttranscode: Attempted to mmap with offset!\n");
+ if (file->private_data) {
+ /* file->private_data will not be NULL if DAHDI_TC_ALLOCATE was
+ * called, and therefore indicates that the transcoder driver
+ * did not export a write function. */
+ WARN_ON(1);
+ return -ENOSYS;
+ } else {
+ printk(KERN_INFO "%s: Attempt to read from unallocated " \
+ "channel.\n", THIS_MODULE->name);
return -EINVAL;
}
+}
- if ((vma->vm_end - vma->vm_start) != sizeof(struct dahdi_transcode_header)) {
- if (debug)
- printk(KERN_DEBUG "zttranscode: Attempted to mmap with size %d != %zd!\n", (int) (vma->vm_end - vma->vm_start), sizeof(struct dahdi_transcode_header));
+static long dahdi_tc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data)
+{
+ switch (cmd) {
+ case DAHDI_TC_ALLOCATE:
+ return dahdi_tc_allocate(file, data);
+ case DAHDI_TC_GETINFO:
+ return dahdi_tc_getinfo(data);
+ case DAHDI_TRANSCODE_OP:
+ /* This is a deprecated call from the previous transcoder
+ * interface, which was all routed through the dahdi_ioctl in
+ * dahdi-base.c, and this ioctl request was used to indicate
+ * that the call should be forwarded to this function. Now
+ * when the file is opened, the f_ops pointer is updated to
+ * point directly to this function, and we don't need a
+ * general indication that the ioctl is destined for the
+ * transcoder.
+ *
+ * I'm keeping this ioctl here in order to explain why there
+ * might be a hole in the ioctl numbering scheme in the header
+ * files.
+ */
+ printk(KERN_WARNING "%s: DAHDI_TRANSCODE_OP is no longer " \
+ "supported. Please call DAHDI_TC ioctls directly.\n",
+ THIS_MODULE->name);
return -EINVAL;
- }
-
- physical = (unsigned long) virt_to_phys(ztc->tch);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
- res = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, sizeof(struct dahdi_transcode_header), PAGE_SHARED);
-#else
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- res = remap_page_range(vma->vm_start, physical, sizeof(struct dahdi_transcode_header), PAGE_SHARED);
- #else
- res = remap_page_range(vma, vma->vm_start, physical, sizeof(struct dahdi_transcode_header), PAGE_SHARED);
- #endif
-#endif
- if (res) {
- if (debug)
- printk(KERN_DEBUG "zttranscode: remap failed!\n");
- return -EAGAIN;
- }
+ default:
+ return -EINVAL;
+ };
+}
- if (debug)
- printk(KERN_DEBUG "zttranscode: successfully mapped transcoder!\n");
+static int dahdi_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+{
+ return (int)dahdi_tc_unlocked_ioctl(file, cmd, data);
+}
- return 0;
+static int dahdi_tc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ printk(KERN_ERR "%s: mmap interface deprecated.\n", THIS_MODULE->name);
+ return -ENOSYS;
}
static unsigned int dahdi_tc_poll(struct file *file, struct poll_table_struct *wait_table)
{
- struct dahdi_transcoder_channel *ztc = file->private_data;
+ int ret;
+ struct dahdi_transcoder_channel *chan = file->private_data;
- if (!ztc)
+ if (!chan) {
+ /* This is because the DAHDI_TC_ALLOCATE ioctl was not called
+ * before calling poll, which is invalid. */
return -EINVAL;
+ }
+
+ poll_wait(file, &chan->ready, wait_table);
- poll_wait(file, &ztc->ready, wait_table);
- return ztc->tch->status & DAHDI_TC_FLAG_BUSY ? 0 : POLLPRI;
+ ret = dahdi_tc_is_busy(chan) ? 0 : POLLPRI;
+ ret |= dahdi_tc_is_built(chan) ? POLLOUT : 0;
+ ret |= dahdi_tc_is_data_waiting(chan) ? POLLIN : 0;
+ return ret;
}
static struct file_operations __dahdi_transcode_fops = {
- owner: THIS_MODULE,
- llseek: NULL,
- open: dahdi_tc_open,
+ owner: THIS_MODULE,
+ open: dahdi_tc_open,
release: dahdi_tc_release,
- ioctl: dahdi_tc_ioctl,
- read: NULL,
- write: NULL,
- poll: dahdi_tc_poll,
- mmap: dahdi_tc_mmap,
- flush: NULL,
- fsync: NULL,
- fasync: NULL,
+ ioctl: dahdi_tc_ioctl,
+ read: dahdi_tc_read,
+ write: dahdi_tc_write,
+ poll: dahdi_tc_poll,
+ mmap: dahdi_tc_mmap,
+#if HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: dahdi_tc_unlocked_ioctl,
+#endif
};
static struct dahdi_chardev transcode_chardev = {
@@ -445,7 +439,7 @@ int dahdi_transcode_init(void)
int res;
if (dahdi_transcode_fops) {
- printk(KERN_NOTICE "Whoa, dahdi_transcode_fops already set?!\n");
+ printk(KERN_WARNING "dahdi_transcode_fops already set.\n");
return -EBUSY;
}
@@ -454,8 +448,7 @@ int dahdi_transcode_init(void)
if ((res = dahdi_register_chardev(&transcode_chardev)))
return res;
- printk(KERN_INFO "DAHDI Transcoder support loaded\n");
-
+ printk(KERN_INFO "%s: Loaded.\n", THIS_MODULE->name);
return 0;
}
@@ -465,14 +458,15 @@ void dahdi_transcode_cleanup(void)
dahdi_transcode_fops = NULL;
- printk(KERN_INFO "DAHDI Transcoder support unloaded\n");
+ printk(KERN_DEBUG "%s: Unloaded.\n", THIS_MODULE->name);
}
module_param(debug, int, S_IRUGO | S_IWUSR);
-
MODULE_DESCRIPTION("DAHDI Transcoder Support");
MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
-MODULE_LICENSE("GPL v2");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
module_init(dahdi_transcode_init);
module_exit(dahdi_transcode_cleanup);