No subject
Thu Jul 12 09:23:04 CDT 2007
- 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.
Removed:
linux/trunk/drivers/dahdi/wctc4xxp/codec_test.c
Modified:
linux/trunk/drivers/dahdi/dahdi-base.c
linux/trunk/drivers/dahdi/dahdi_transcode.c
linux/trunk/drivers/dahdi/wctc4xxp/Kbuild
linux/trunk/drivers/dahdi/wctc4xxp/Makefile
linux/trunk/drivers/dahdi/wctc4xxp/base.c
linux/trunk/include/dahdi/kernel.h
linux/trunk/include/dahdi/user.h
Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svn.digium.com/view/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=4717&r1=4716&r2=4717
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Wed Aug 6 13:09:58 2008
@@ -2620,30 +2620,29 @@
static int dahdi_open(struct inode *inode, struct file *file)
{
int unit = UNIT(file);
- int ret = -ENXIO;
struct dahdi_chan *chan;
/* Minor 0: Special "control" descriptor */
if (!unit)
return dahdi_ctl_open(inode, file);
if (unit == 250) {
- if (!dahdi_transcode_fops)
- request_module("dahdi_transcode");
+ if (!dahdi_transcode_fops) {
+ if (request_module("dahdi_transcode")) {
+ return -ENXIO;
+ }
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ __MOD_INC_USE_COUNT (dahdi_transcode_fops->owner);
+#else
+ if (!try_module_get(dahdi_transcode_fops->owner)) {
+ return -ENXIO;
+ }
+#endif
if (dahdi_transcode_fops && dahdi_transcode_fops->open) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- if (dahdi_transcode_fops->owner) {
- __MOD_INC_USE_COUNT (dahdi_transcode_fops->owner);
-#else
- if (try_module_get(dahdi_transcode_fops->owner)) {
-#endif
- ret = dahdi_transcode_fops->open(inode, file);
- if (ret)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- __MOD_DEC_USE_COUNT (dahdi_transcode_fops->owner);
-#else
- module_put(dahdi_transcode_fops->owner);
-#endif
- }
- return ret;
+ return dahdi_transcode_fops->open(inode, file);
+ } else {
+ /* dahdi_transcode module should have exported a
+ * file_operations table. */
+ WARN_ON(1);
}
return -ENXIO;
}
@@ -3163,14 +3162,11 @@
return dahdi_timer_release(inode, file);
}
if (unit == 250) {
- res = dahdi_transcode_fops->release(inode, file);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- if (dahdi_transcode_fops->owner)
- __MOD_DEC_USE_COUNT (dahdi_transcode_fops->owner);
-#else
- module_put(dahdi_transcode_fops->owner);
-#endif
- return res;
+ /* We should not be here because the dahdi_transcode.ko module
+ * should have updated the file_operations for this file
+ * handle when the file was opened. */
+ WARN_ON(1);
+ return -EFAULT;
}
if (unit == 254) {
chan = file->private_data;
@@ -5249,8 +5245,12 @@
if (!unit)
return dahdi_ctl_ioctl(inode, file, cmd, data);
- if (unit == 250)
- return dahdi_transcode_fops->ioctl(inode, file, cmd, data);
+ if (unit == 250) {
+ /* dahdi_transcode should have updated the file_operations on
+ * this file object on open, so we shouldn't be here. */
+ WARN_ON(1);
+ return -EFAULT;
+ }
if (unit == 253) {
timer = file->private_data;
Modified: linux/trunk/drivers/dahdi/dahdi_transcode.c
URL: http://svn.digium.com/view/dahdi/linux/trunk/drivers/dahdi/dahdi_transcode.c?view=diff&rev=4717&r1=4716&r2=4717
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_transcode.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_transcode.c Wed Aug 6 13:09:58 2008
@@ -3,7 +3,7 @@
*
* Written by Mark Spencer <markster at 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>
-
-static int debug = 0;
-static struct dahdi_transcoder *trans;
+#endif
+
+static int debug;
+LIST_HEAD(trans);
static spinlock_t translock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(dahdi_transcoder_register);
@@ -52,387 +58,375 @@
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);
-
- if (!(ztc = kmalloc(size, GFP_KERNEL)))
+ size_t size = sizeof(*tc) + (sizeof(tc->channels[0]) * numchans);
+
+ 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;
- }
-
- return ztc;
-}
-
-static int schluffen(wait_queue_head_t *q)
-{
- 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;
-}
-
-void dahdi_transcoder_free(struct dahdi_transcoder *ztc)
-{
- kfree(ztc);
+ 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;
+ }
+
+ 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;
+}
+
+void dahdi_transcoder_free(struct dahdi_transcoder *tc)
+{
+ kfree(tc);
+}
+
+/* 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)
+{
+ 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",
+ BUG_ON(is_on_list(&tc->node, &trans));
+ list_add_tail(&tc->node, &trans);
+ spin_unlock(&translock);
+
+ 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)
+{
+ int res = -EINVAL;
+
+ /* \todo Perhaps we should check to make sure there isn't a channel
+ * that is still in use? */
+
+ spin_lock(&translock);
+ if (!is_on_list(&tc->node, &trans)) {
+ spin_unlock(&translock);
+ 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);
+
+ 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;
}
-/* 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;
- }
-
- if (!cur) {
- spin_unlock(&translock);
- return res;
- }
-
- 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",
- 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)
-{
- if (debug)
- printk(KERN_DEBUG "DAHDI Transcoder Alert!\n");
- if (ztc->tch)
- ztc->tch->status &= ~DAHDI_TC_FLAG_BUSY;
- wake_up_interruptible(&ztc->ready);
-
+int dahdi_transcoder_alert(struct dahdi_transcoder_channel *chan)
+{
+ 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);
-
- return 0;
-}
-
-static void ztc_release(struct dahdi_transcoder_channel *ztc)
-{
- 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);
- }
-
- 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");
+ 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 dtc_release(struct dahdi_transcoder_channel *chan)
+{
+ BUG_ON(!chan);
+ if (chan->parent && chan->parent->release) {
+ chan->parent->release(chan);
+ }
+ dahdi_tc_clear_busy(chan);
}
static int dahdi_tc_release(struct inode *inode, struct file *file)
{
- ztc_release(file->private_data);
-
- return 0;
-}
-
-static int do_reset(struct dahdi_transcoder_channel **ztc)
-{
- struct dahdi_transcoder_channel *newztc = NULL, *origztc = NULL;
- struct dahdi_transcode_header *zth = (*ztc)->tch;
+ 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;
+}
+
+/* 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 *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);
-
- if (!newztc)
- return match ? -EBUSY : -ENOSYS;
-
- /* 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);
+ }
+ 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;
+ }
+
+ spin_lock(&translock);
+ chan = __find_free_channel(&trans, &fmts);
+ spin_unlock(&translock);
+
+ if (IS_ERR(chan)) {
+ return PTR_ERR(chan);
+ }
+
+ /* Every transcoder channel must be associated with a parent
+ * transcoder. */
+ BUG_ON(!chan->parent);
+
+ chan->srcfmt = fmts.srcfmt;
+ chan->dstfmt = fmts.dstfmt;
+
+ 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;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+ dahdi_tc_set_nonblock(chan);
+ } else {
+ dahdi_tc_clear_nonblock(chan);
}
/* Actually reset the transcoder channel */
- if ((*ztc)->parent && ((*ztc)->parent->operation))
- return (*ztc)->parent->operation((*ztc), DAHDI_TCOP_ALLOCATE);
+ if (chan->parent->allocate)
+ return chan->parent->allocate(chan);
return -EINVAL;
}
-static int wait_busy(struct dahdi_transcoder_channel *ztc)
-{
- int ret;
-
- for (;;) {
- if (!(ztc->tch->status & DAHDI_TC_FLAG_BUSY))
- return 0;
- if ((ret = schluffen(&ztc->ready)))
- return ret;
- }
-}
-
-static int dahdi_tc_getinfo(unsigned long data)
-{
- struct dahdi_transcode_info info;
+static long dahdi_tc_getinfo(unsigned long data)
+{
+ 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 ssize_t dahdi_tc_write(struct file *file, __user const char *usrbuf, size_t count, loff_t *ppos)
+{
+ 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;
+ } else {
+ printk(KERN_INFO "%s: Attempt to write to unallocated " \
+ "channel.\n", THIS_MODULE->name);
+ return -EINVAL;
+ }
+}
+
+static ssize_t dahdi_tc_read(struct file *file, __user char *usrbuf, size_t count, loff_t *ppos)
+{
+ 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;
+ }
+}
+
+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;
+ default:
+ return -EINVAL;
+ };
}
static int dahdi_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
{
- int op;
+ return (int)dahdi_tc_unlocked_ioctl(file, cmd, data);
+}
+
+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)
+{
int ret;
- struct dahdi_transcoder_channel *ztc = file->private_data;
-
- if (cmd != DAHDI_TRANSCODE_OP)
- 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;
- }
-
+ struct dahdi_transcoder_channel *chan = file->private_data;
+
+ 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);
+
+ 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 int dahdi_tc_mmap(struct file *file, struct vm_area_struct *vma)
-{
- 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");
- 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));
- 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
+static struct file_operations __dahdi_transcode_fops = {
+ owner: THIS_MODULE,
+ open: dahdi_tc_open,
+ release: dahdi_tc_release,
+ 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
- if (res) {
- if (debug)
- printk(KERN_DEBUG "zttranscode: remap failed!\n");
- return -EAGAIN;
- }
-
- if (debug)
- printk(KERN_DEBUG "zttranscode: successfully mapped transcoder!\n");
-
- return 0;
-}
-
-static unsigned int dahdi_tc_poll(struct file *file, struct poll_table_struct *wait_table)
-{
- struct dahdi_transcoder_channel *ztc = file->private_data;
-
- if (!ztc)
- return -EINVAL;
-
- poll_wait(file, &ztc->ready, wait_table);
- return ztc->tch->status & DAHDI_TC_FLAG_BUSY ? 0 : POLLPRI;
-}
-
-static struct file_operations __dahdi_transcode_fops = {
- owner: THIS_MODULE,
- llseek: NULL,
- 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,
};
static struct dahdi_chardev transcode_chardev = {
@@ -445,7 +439,7 @@
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 @@
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 @@
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 at digium.com>");
-MODULE_LICENSE("GPL v2");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
module_init(dahdi_transcode_init);
module_exit(dahdi_transcode_cleanup);
Modified: linux/trunk/drivers/dahdi/wctc4xxp/Kbuild
URL: http://svn.digium.com/view/dahdi/linux/trunk/drivers/dahdi/wctc4xxp/Kbuild?view=diff&rev=4717&r1=4716&r2=4717
==============================================================================
--- linux/trunk/drivers/dahdi/wctc4xxp/Kbuild (original)
+++ linux/trunk/drivers/dahdi/wctc4xxp/Kbuild Wed Aug 6 13:09:58 2008
@@ -8,7 +8,7 @@
EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
endif
-wctc4xxp-objs := base.o
+wctc4xxp-objs := base.o
ifneq ($(HOTPLUG_FIRMWARE),yes)
wctc4xxp-objs += $(FIRM_DIR)/dahdi-fw-tc400m.o
Modified: linux/trunk/drivers/dahdi/wctc4xxp/Makefile
URL: http://svn.digium.com/view/dahdi/linux/trunk/drivers/dahdi/wctc4xxp/Makefile?view=diff&rev=4717&r1=4716&r2=4717
==============================================================================
--- linux/trunk/drivers/dahdi/wctc4xxp/Makefile (original)
+++ linux/trunk/drivers/dahdi/wctc4xxp/Makefile Wed Aug 6 13:09:58 2008
@@ -3,14 +3,5 @@
# For newer kernels, Kbuild will be included directly by the kernel
# build system.
include $(src)/Kbuild
-
else
-
-tests: codec_test
-
-codec_test: codec_test.c ../../include/dahdi/kernel.h ../../include/dahdi/user.h
- $(CC) -o $@ $< $(CFLAGS)
-
-clean:
- rm -rf codec_test
endif
Modified: linux/trunk/drivers/dahdi/wctc4xxp/base.c
URL: http://svn.digium.com/view/dahdi/linux/trunk/drivers/dahdi/wctc4xxp/base.c?view=diff&rev=4717&r1=4716&r2=4717
==============================================================================
--- linux/trunk/drivers/dahdi/wctc4xxp/base.c (original)
+++ linux/trunk/drivers/dahdi/wctc4xxp/base.c Wed Aug 6 13:09:58 2008
@@ -1,9 +1,7 @@
/*
* Wildcard TC400B Driver
*
- * Written by John Sloan <jsloan at digium.com>
- *
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
*
* All rights reserved.
*
@@ -23,90 +21,158 @@
*
*/
-
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/mman.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/semaphore.h>
#include <linux/jiffies.h>
-#include <linux/workqueue.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
-
-#include <dahdi/kernel.h>
-
-
-/* #define USE_TEST_HW */
-#define USE_TDM_CONFIG
-#define QUIET_DSP
-
-#define WC_MAX_IFACES 128
-
-#define NUM_CARDS 24
-#define NUM_EC 4
-
-/* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */
-#define NUM_CHANNELS 120
-
-#define DTE_FORMAT_ULAW 0x00
-#define DTE_FORMAT_G723_1 0x04
-#define DTE_FORMAT_ALAW 0x08
-#define DTE_FORMAT_G729A 0x12
-#define DTE_FORMAT_UNDEF 0xFF
-
-#define G729_LENGTH 20
-#define G723_LENGTH 30
-
-#define G729_SAMPLES 160 /* G.729 */
-#define G723_SAMPLES 240 /* G.723.1 */
-
-#define G729_BYTES 20 /* G.729 */
-#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
-#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
-#define G723_SID_BYTES 4 /* G.723.1 SID frame */
-
-#define ACK_SPACE 20
-
-#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE)
-#define MAX_RCV_COMMANDS 16
-
-/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */
-#define BOOT_CMD_LEN 1500
-#define OTHER_CMD_LEN 300
-
-#define MAX_COMMAND_LEN BOOT_CMD_LEN /* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */
-
-#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */
-
-#define SFRAME_SIZE MAX_COMMAND_LEN
-
-#define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
-
-#define MDIO_SHIFT_CLK 0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB 0x00000
-#define MDIO_ENB_IN 0x40000
-#define MDIO_DATA_READ 0x80000
-
-#define RCV_CSMENCAPS 1
-#define RCV_RTP 2
-#define RCV_CSMENCAPS_ACK 3
-#define RCV_OTHER 99
-
-
-/* TDM Commands */
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/etherdevice.h>
+#include <linux/timer.h>
+
+#include "dahdi/kernel.h"
+
+/* COMPILE TIME OPTIONS =================================================== */
+
+#define INTERRUPT 0
+#define WORKQUEUE 1
+#define TASKLET 2
+
+#ifndef DEFERRED_PROCESSING
+# define DEFERRED_PROCESSING WORKQUEUE
+#endif
+
+#if DEFERRED_PROCESSING == INTERRUPT
+# define ALLOC_FLAGS GFP_ATOMIC
+#elif DEFERRED_PROCESSING == TASKLET
+# define ALLOC_FLAGS GFP_ATOMIC
+#else
+# define ALLOC_FLAGS GFP_KERNEL
+#endif
+
+#define WARN() WARN_ON(1)
+
+#define DTE_PRINTK(_lvl, _fmt, _args...) \
+ printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \
+ (wc)->board_name, ## _args)
+
+#define DTE_DEBUG(_dbgmask, _fmt, _args...) \
+ if ((debug & _dbgmask) == (_dbgmask)) { \
+ printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name, \
+ (wc)->board_name, ## _args); \
+ } \
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define WARN_ON_ONCE(__condition) do { \
+ static int __once = 1; \
+ if (unlikely(__condition)) { \
+ if (__once) { \
+ __once = 0; \
+ WARN_ON(0); \
+ } \
+ } \
+} while(0)
+#endif
+
+#define INVALID 999 /* Used to mark invalid channels, commands, etc.. */
+#define MAX_CHANNEL_PACKETS 5 /* Never let more than 5 outstanding packets exist for any channel. */
+
+#define G729_LENGTH 20
+#define G723_LENGTH 30
+
+#define G729_SAMPLES 160 /* G.729 */
+#define G723_SAMPLES 240 /* G.723.1 */
+
+#define G729_BYTES 20 /* G.729 */
+#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
+#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
+#define G723_SID_BYTES 4 /* G.723.1 SID frame */
+
+#define MAX_CAPTURED_PACKETS 5000
+
+/* The following bit fields are used to set the various debug levels. */
+#define DTE_DEBUG_GENERAL (1 << 0) /* 1 */
+#define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */
+#define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */
+#define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */
+#define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */
+#define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */
+#define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */
+
+int debug;
+char *mode;
+
+static spinlock_t wctc4xxp_list_lock;
+static struct list_head wctc4xxp_list;
+
+#define ETH_P_CSM_ENCAPS 0x889B
+
+struct rtphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 csrc_count:4;
+ __u8 extension:1;
+ __u8 padding:1;
+ __u8 ver:2;
+ __u8 type:7;
+ __u8 marker:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 ver:2;
+ __u8 padding:1;
+ __u8 extension:1;
+ __u8 csrc_count:4;
+ __u8 marker:1;
+ __u8 type:7;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __be16 seqno;
+ __be32 timestamp;
+ __be32 ssrc;
+} __attribute__((packed));
+
+struct rtp_packet {
+ struct ethhdr ethhdr;
+ struct iphdr iphdr;
+ struct udphdr udphdr;
+ struct rtphdr rtphdr;
+ __u8 payload[0];
+}__attribute__((packed));
+
+/* Ethernet packet type for communication control information to the DTE. */
+struct csm_encaps_hdr {
+ struct ethhdr ethhdr;
+ /* CSM_ENCAPS HEADER */
+ __be16 op_code;
+ __u8 seq_num;
+ __u8 control;
+ __be16 channel;
+ /* COMMON PART OF PAYLOAD HEADER */
+ __u8 length;
+ __u8 index;
+ __u8 type;
+ __u8 class;
+ __le16 function;
+ __le16 reserved;
+ __le16 params[0];
+} __attribute__((packed));
+
+struct csm_create_channel_cmd {
+ struct csm_encaps_hdr hdr;
+ __le16 channel_type;
+ __le16 timeslot;
+} __attribute__((packed));
+
#define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30
#define CMD_MSG_TDM_SELECT_BUS_MODE(s) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
@@ -182,17 +248,26 @@
0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \
0x02,0x00 }
-/* Supervisor channel commands */
-#define CMD_MSG_CREATE_CHANNEL_LEN 32
-#define CMD_MSG_CREATE_CHANNEL(s,t) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, \
- 0x02,0x00, (t&0x00FF), ((t&0xFF00) >> 8) }
+#define CONTROL_PACKET_OPCODE 0x0001
+/* Control bits */
+#define LITTLE_ENDIAN 0x01
+#define SUPPRESS_ACK 0x40
+#define MESSAGE_PACKET 0x80
+
+#define SUPERVISOR_CHANNEL 0xffff
+
+/* Supervisor function codes */
+#define SUPVSR_CREATE_CHANNEL 0x0010
+
+#define CONFIG_CHANGE_TYPE 0x00
+#define CONFIG_DEVICE_CLASS 0x06
+
#define CMD_MSG_QUERY_CHANNEL_LEN 30
#define CMD_MSG_QUERY_CHANNEL(s,t) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x01,0x06,0x10,0x00, 0x00,0x00, \
(t&0x00FF), ((t&0xFF00) >> 8) }
+
#define CMD_MSG_TRANS_CONNECT_LEN 38
#define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \
0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
@@ -243,303 +318,227 @@
0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x5B,0x80, 0x00,0x00, \
0x00,0x00, 0x00,0x00 }
-/* CPU ACK command */
-#define CMD_MSG_ACK_LEN 20
-#define CMD_MSG_ACK(s,c) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s, 0xE0, (c&0x00FF), ((c>>8)&0x00FF) }
-
-/* Wrapper for RTP packets */
-#define CMD_MSG_IP_UDP_RTP_LEN 54
-#define CMD_MSG_IP_UDP_RTP(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,s) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x08,0x00, \
- 0x45,0x00, p1,p2, 0x00,p3, 0x40,0x00, 0x80,0x11, p4,p5, \
- 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, p6,p7, p8,p9, p10,p11, p12,p13, \
- 0x80,p14, p15,p16, p17,p18,p19,p20, 0x12,0x34,0x56,(s&0xFF)}
-
-#define CMD_MSG_DW_WRITE_LEN 38
-#define CMD_MSG_DW_WRITE(s,a,d) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01,s&0x0F,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x00,0x00, \
- ((a>>24)&0x00FF),((a>>16)&0x00FF), ((a>>8)&0x00FF),(a&0x00FF), \
- ((d>>24)&0x00FF),((d>>16)&0x00FF), ((d>>8)&0x00FF),(d&0x00FF) }
-
-#define CMD_MSG_FORCE_ALERT_LEN 32
-#define CMD_MSG_FORCE_ALERT(s) { \
- 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
- 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x09,0x04, 0x00,0x00, \
- 0x24,0x00, 0x00,0x00 }
-
-#define dahdi_send_cmd(wc, command, length, hex) \
- ({ \
- int ret = 0; \
- do { \
- if (ret == 2) \
- { \
- wc->ztsnd_rtx++; \
- if (hex == 0x0010) \
- wc->ztsnd_0010_rtx++; \
- } \
- down(&wc->cmdqsem); \
- wc->last_command_sent = hex; \
- if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) \
- printk(KERN_NOTICE "wcdte error: cmdq is full.\n"); \
- else { \
- unsigned char fifo[OTHER_CMD_LEN] = command; \
- int i; \
- wc->cmdq[wc->cmdq_wndx].cmdlen = length; \
- for (i = 0; i < length; i++) \
- wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \
- wc->last_seqno = fifo[16]; \
- wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \
- } \
- __transmit_demand(wc); \
- up(&wc->cmdqsem); \
- if (hex == 0x0000) \
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 2); \
- else { \
- ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
- if (wc->dsp_crashed) \
- return 1; \
- } \
- if (ret == 1) \
- return(1); \
- } while (ret == 2); \
- })
-
-
-struct cmdq {
- unsigned int cmdlen;
- unsigned char cmd[MAX_COMMAND_LEN];
+#define SFRAME_SIZE 320
+
+/* Transcoder buffer (tcb) */
+struct tcb {
+ /* First field so that is aligned by default. */
+ u8 cmd[SFRAME_SIZE];
+ struct list_head node;
+ unsigned long timeout;
+ unsigned long retries;
+ /* NOTE: these flags aren't bit fields because some of the flags are
+ * combinations of the other ones. */
+#define DO_NOT_AUTO_FREE (1 << 0)
+#define TX_COMPLETE (1 << 1)
+#define DO_NOT_CAPTURE (1 << 2)
+#define __WAIT_FOR_ACK (1 << 3)
+#define __WAIT_FOR_RESPONSE (1 << 4)
+#define DTE_CMD_TIMEOUT (1 << 5)
+#define WAIT_FOR_ACK (__WAIT_FOR_ACK | DO_NOT_AUTO_FREE)
+#define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE)
+ unsigned long flags;
+ struct tcb *response;
+ struct completion complete;
+ struct timer_list timer;
+ void *data;
+ /* The number of bytes available in data. */
+ int data_len;
};
+static inline void *hdr_from_cmd(struct tcb *cmd) {
+ return cmd->data;
+}
+
+static inline void
+initialize_cmd(struct tcb *cmd, unsigned long cmd_flags)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ INIT_LIST_HEAD(&cmd->node);
+ init_completion(&cmd->complete);
+ cmd->flags = cmd_flags;
+ cmd->data = &cmd->cmd[0];
+ cmd->data_len = SFRAME_SIZE;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/*! Used to allocate commands to submit to the dte. */
+kmem_cache_t *cmd_cache;
+#else
+/*! Used to allocate commands to submit to the dte. */
+struct kmem_cache *cmd_cache;
+#endif
+
+static inline struct tcb *
+__alloc_cmd(unsigned alloc_flags, unsigned long cmd_flags)
+{
+ struct tcb *cmd;
+
+ cmd = kmem_cache_alloc(cmd_cache, alloc_flags);
+ if (likely(cmd)) {
+ initialize_cmd(cmd, cmd_flags);
+ }
+ return cmd;
+}
+
+static struct tcb *
+alloc_cmd(void)
+{
+ return __alloc_cmd(GFP_KERNEL, 0);
+}
+
+static void
+__free_cmd(struct tcb *cmd)
+{
+ if (cmd->data != &cmd->cmd[0]) {
+ kfree(cmd->data);
+ }
+ kmem_cache_free(cmd_cache, cmd);
+ return;
+}
+
+static void
+free_cmd(struct tcb *cmd)
+{
+ if (cmd->response) {
+ __free_cmd(cmd->response);
[... 4605 lines stripped ...]
More information about the dahdi-commits
mailing list