[zaptel-commits] trunk r1162 - in /trunk: ./ build_tools/

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Fri Jun 23 08:11:45 MST 2006


Author: kpfleming
Date: Fri Jun 23 10:11:45 2006
New Revision: 1162

URL: http://svn.digium.com/view/zaptel?rev=1162&view=rev
Log:
add infrastructure for zaptel transcoders

Added:
    trunk/zttranscode.c   (with props)
Modified:
    trunk/Makefile
    trunk/build_tools/genudevrules
    trunk/zaptel.c
    trunk/zaptel.h

Modified: trunk/Makefile
URL: http://svn.digium.com/view/zaptel/trunk/Makefile?rev=1162&r1=1161&r2=1162&view=diff
==============================================================================
--- trunk/Makefile (original)
+++ trunk/Makefile Fri Jun 23 10:11:45 2006
@@ -109,7 +109,7 @@
 
 MODULES:=zaptel tor2 torisa wcusb wcfxo wctdm wctdm24xxp \
 	 ztdynamic ztd-eth wct1xxp wct4xxp wcte11xp pciradio \
-         ztd-loc # ztdummy
+         ztd-loc zttranscode
 #MODULES+=wcfxsusb
 # build ztdummy by default for 2.6 kernels
 ifeq ($(BUILDVER),linux26)
@@ -317,6 +317,7 @@
 	rm -f $(INSTALL_PREFIX)/dev/zap/251
 	rm -f $(INSTALL_PREFIX)/dev/zap/250
 	mknod $(INSTALL_PREFIX)/dev/zap/ctl c 196 0
+	mknod $(INSTALL_PREFIX)/dev/zap/transcode c 196 250
 	mknod $(INSTALL_PREFIX)/dev/zap/timer c 196 253
 	mknod $(INSTALL_PREFIX)/dev/zap/channel c 196 254
 	mknod $(INSTALL_PREFIX)/dev/zap/pseudo c 196 255

Modified: trunk/build_tools/genudevrules
URL: http://svn.digium.com/view/zaptel/trunk/build_tools/genudevrules?rev=1162&r1=1161&r2=1162&view=diff
==============================================================================
--- trunk/build_tools/genudevrules (original)
+++ trunk/build_tools/genudevrules Fri Jun 23 10:11:45 2006
@@ -23,6 +23,7 @@
 cat <<EOF
 # zaptel devices with ownership/permissions for running as non-root
 KERNEL${match}"zapctl", NAME="zap/ctl", OWNER="asterisk", GROUP="asterisk", MODE="0660"
+KERNEL${match}"zaptranscode", NAME="zap/transcode", OWNER="asterisk", GROUP="asterisk", MODE="0660"
 KERNEL${match}"zaptimer", NAME="zap/timer", OWNER="asterisk", GROUP="asterisk", MODE="0660"
 KERNEL${match}"zapchannel", NAME="zap/channel", OWNER="asterisk", GROUP="asterisk", MODE="0660"
 KERNEL${match}"zappseudo", NAME="zap/pseudo", OWNER="asterisk", GROUP="asterisk", MODE="0660"

Modified: trunk/zaptel.c
URL: http://svn.digium.com/view/zaptel/trunk/zaptel.c?rev=1162&r1=1161&r2=1162&view=diff
==============================================================================
--- trunk/zaptel.c (original)
+++ trunk/zaptel.c Fri Jun 23 10:11:45 2006
@@ -150,6 +150,7 @@
 "-22.5db (CSU)"
 } ;
 
+EXPORT_SYMBOL(zt_transcode_fops);
 EXPORT_SYMBOL(zt_init_tone_state);
 EXPORT_SYMBOL(zt_dtmf_tone);
 EXPORT_SYMBOL(zt_register);
@@ -190,6 +191,7 @@
 static devfs_handle_t pseudo;
 static devfs_handle_t ctl;
 static devfs_handle_t timer;
+static devfs_handle_t transcode;
 #endif
 
 /* udev necessary data structures.  Yeah! */
@@ -283,6 +285,7 @@
 
 static struct zt_span *master;
 static struct file_operations zt_fops;
+struct file_operations *zt_transcode_fops = NULL;
 
 static struct
 {
@@ -2389,10 +2392,24 @@
 static int zt_open(struct inode *inode, struct file *file)
 {
 	int unit = UNIT(file);
+	int ret = -ENXIO;
 	struct zt_chan *chan;
 	/* Minor 0: Special "control" descriptor */
 	if (!unit) 
 		return zt_ctl_open(inode, file);
+	if (unit == 250) {
+		if (!zt_transcode_fops)
+			request_module("zttranscode");
+		if (zt_transcode_fops && zt_transcode_fops->open) {
+			if (try_module_get(zt_transcode_fops->owner)) {
+				ret = zt_transcode_fops->open(inode, file);
+				if (ret)
+					module_put(zt_transcode_fops->owner);
+			}
+			return ret;
+		}
+		return -ENXIO;
+	}
 	if (unit == 253) {
 		if (maxspans) {
 			return zt_timing_open(inode, file);
@@ -2714,6 +2731,11 @@
 		return zt_ctl_release(inode, file);
 	if (unit == 253) {
 		return zt_timer_release(inode, file);
+	}
+	if (unit == 250) {
+		res = zt_transcode_fops->release(inode, file);
+		module_put(zt_transcode_fops->owner);
+		return res;
 	}
 	if (unit == 254) {
 		chan = file->private_data;
@@ -4492,6 +4514,10 @@
 
 	if (!unit)
 		return zt_ctl_ioctl(inode, file, cmd, data);
+
+	if (unit == 250)
+		return zt_transcode_fops->ioctl(inode, file, cmd, data);
+
 	if (unit == 253) {
 		timer = file->private_data;
 		if (timer)
@@ -6369,6 +6395,14 @@
 	return(ret);  /* return what we found */
 }
 
+static int zt_mmap(struct file *file, struct vm_area_struct *vm)
+{
+	int unit = UNIT(file);
+	if (unit == 250)
+		return zt_transcode_fops->mmap(file, vm);
+	return -ENOSYS;
+}
+
 static unsigned int zt_poll(struct file *file, struct poll_table_struct *wait_table)
 {
 	int unit = UNIT(file);
@@ -6376,6 +6410,9 @@
 
 	if (!unit)
 		return -EINVAL;
+
+	if (unit == 250)
+		return zt_transcode_fops->poll(file, wait_table);
 
 	if (unit == 253)
 		return zt_timer_poll(file, wait_table);
@@ -6758,7 +6795,7 @@
 	read: zt_read,
 	write: zt_write,
 	poll: zt_poll,
-	mmap: NULL,
+	mmap: zt_mmap,
 	flush: NULL,
 	fsync: NULL,
 	fasync: NULL,
@@ -6833,6 +6870,7 @@
 
 #ifdef CONFIG_ZAP_UDEV /* udev support functions */
 	zap_class = class_create(THIS_MODULE, "zaptel");
+	CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 250), NULL, "zaptranscode");
 	CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 253), NULL, "zaptimer");
 	CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 254), NULL, "zapchannel");
 	CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 255), NULL, "zappseudo");
@@ -6848,6 +6886,7 @@
 	timer = devfs_register(zaptel_devfs_dir, "timer", DEVFS_FL_DEFAULT, ZT_MAJOR, 253, mode, &zt_fops, NULL);
 	channel = devfs_register(zaptel_devfs_dir, "channel", DEVFS_FL_DEFAULT, ZT_MAJOR, 254, mode, &zt_fops, NULL);
 	pseudo = devfs_register(zaptel_devfs_dir, "pseudo", DEVFS_FL_DEFAULT, ZT_MAJOR, 255, mode, &zt_fops, NULL);
+	transcode = devfs_register(zaptel_devfs_dir, "transcode", DEVFS_FL_DEFAULT, ZT_MAJOR, 250, mode, &zt_fops, NULL);
 	ctl = devfs_register(zaptel_devfs_dir, "ctl", DEVFS_FL_DEFAULT, ZT_MAJOR, 0, mode, &zt_fops, NULL);
 	}
 #else
@@ -6884,6 +6923,7 @@
 			kfree(tone_zones[x]);
 #ifdef CONFIG_DEVFS_FS
 	devfs_unregister(timer);
+	devfs_unregister(transcode);
 	devfs_unregister(channel);
 	devfs_unregister(pseudo);
 	devfs_unregister(ctl);
@@ -6891,6 +6931,7 @@
 	devfs_unregister_chrdev(ZT_MAJOR, "zaptel");
 #else
 #ifdef CONFIG_ZAP_UDEV
+	class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 250)); /* transcode */
 	class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 253)); /* timer */
 	class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 254)); /* channel */
 	class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 255)); /* pseudo */

Modified: trunk/zaptel.h
URL: http://svn.digium.com/view/zaptel/trunk/zaptel.h?rev=1162&r1=1161&r2=1162&view=diff
==============================================================================
--- trunk/zaptel.h (original)
+++ trunk/zaptel.h Fri Jun 23 10:11:45 2006
@@ -34,15 +34,18 @@
 #include "zconfig.h"
 #include <linux/config.h>
 #include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+
 #ifdef CONFIG_ZAPATA_NET	
 #include <linux/hdlc.h>
 #endif
+
 #ifdef CONFIG_ZAPATA_PPP
 #include <linux/ppp_channel.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #endif
-#include <linux/fs.h>
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #define LINUX26
@@ -56,7 +59,9 @@
 
 #include "ecdis.h"
 #include "fasthdlc.h"
-#endif
+
+#endif /* __KERNEL__ */
+
 #ifdef CONFIG_DEVFS_FS
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
 #include <linux/devfs_fs_kernel.h>
@@ -65,7 +70,6 @@
 //#warning "Zaptel doesn't support DEVFS in post 2.4 kernels.  Disabling DEVFS in zaptel"
 #endif
 #endif /* CONFIG_DEVFS_FS */
-#include <linux/ioctl.h>
 
 #ifndef ELAST
 #define ELAST 500
@@ -635,6 +639,11 @@
  */
 #define	ZT_SETPOLARITY		_IOW (ZT_CODE, 92, int)
 
+/*
+ * Transcoder operations
+ */
+#define ZT_TRANSCODE_OP		_IOWR(ZT_CODE, 93, int)
+
 /* 
  * Startup or Shutdown a span
  */
@@ -664,8 +673,59 @@
 #define ZT_TONEDETECT_ON	(1 << 0)		/* Detect tones */
 #define ZT_TONEDETECT_MUTE	(1 << 1)		/* Mute audio in received channel */
 
+#define ZT_TRANSCODE_MAGIC 0x74a9c0de
+
+/* Operations */
+#define ZT_TCOP_RESET		1			/* Reset the channel state / codec selection */
+#define ZT_TCOP_TRANSCODE	2			/* Begin transcoding a block */
+#define ZT_TCOP_GETINFO		3			/* Get information (use zt_transcode_info) */
+
+typedef struct zt_transcode_info {
+	unsigned int op;
+	unsigned int tcnum;
+	char name[80];
+	unsigned int srcfmts;
+	unsigned int dstfmts;
+} ZT_TRANSCODE_INFO;
+
+#define ZT_TCCONF_USETS 	(1 << 0)	/* Use/update timestamp field */
+#define ZT_TCCONF_USESEQ 	(1 << 1)	/* Use/update seqno field */
+
+#define ZT_TCSTAT_DSTRDY	(1 << 0)	/* Destination data is ready */
+#define ZT_TCSTAT_DSTBUSY	(1 << 1)	/* Destination data is outstanding */
+
+#define __ZT_TRANSCODE_BUFSIZ		16384
+#define ZT_TRANSCODE_HDRLEN		256
+#define ZT_TRANSCODE_BUFSIZ		((__ZT_TRANSCODE_BUFSIZ) - (ZT_TRANSCODE_HDRLEN))
+#define ZT_TRANSCODE_DSTOFFSET		(((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
+#define ZT_TRANSCODE_SRCOFFSET		(((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
+
+typedef struct zt_transcode_header {
+	unsigned int srcfmt;		/* See formats.h -- use TCOP_RESET when you change */
+	unsigned int srcoffset; 	/* In bytes -- written by user */
+	unsigned int srclen;		/* In bytes -- written by user */
+	unsigned int srctimestamp;	/* In samples -- written by user (only used if ZT_TCCONF_USETS is set) */
+	unsigned int srcseqno;		/* In units -- written by user (only used if ZT_TCCONF_USESEQ is set) */
+
+	unsigned int dstfmt;		/* See formats.h -- use TCOP_RESET when you change */
+	unsigned int dstoffset;  	/* In bytes -- written by user */
+	unsigned int dsttimestamp;	/* In samples -- read by user */
+	unsigned int dstseqno;		/* In units -- read by user (only used if ZT_TCCONF_USESEQ is set) */
+	unsigned int dstlen;  		/* In bytes -- read by user */
+	unsigned int dstsamples;	/* In timestamp units -- read by user */
+
+	unsigned int magic;		/* Magic value -- ZT_TRANSCODE_MAGIC, read by user */
+	unsigned int config;		/* Read/write by user */
+	unsigned int status;		/* Read/write by user */
+
+	/* XXX: fix this to automatically calculate somehow */
+	unsigned char userhdr[ZT_TRANSCODE_HDRLEN - (sizeof(unsigned int) * 14)];	/* Storage for user parameters */
+	unsigned char srcdata[ZT_TRANSCODE_BUFSIZ / 2];	/* Storage of source data */
+	unsigned char dstdata[ZT_TRANSCODE_BUFSIZ / 2];	/* Storage of destination data */
+} ZT_TRANSCODE_HEADER;
+
 struct zt_ring_cadence {
-	int ringcadence [ZT_MAX_CADENCE];
+	int ringcadence[ZT_MAX_CADENCE];
 };
 
 struct zt_tone_def_header {
@@ -1321,6 +1381,33 @@
 #endif	
 };
 
+struct zt_transcoder_channel {
+	void *pvt;
+	struct zt_transcoder *parent;
+	wait_queue_head_t ready;
+	int errorstatus;
+	int offset;
+	unsigned int flags;
+	unsigned int srcfmt;
+	unsigned int dstfmt;
+	struct zt_transcode_header *tch;
+};
+
+#define ZT_TC_FLAG_BUSY       (1 << 0)
+#define ZT_TC_FLAG_TRANSIENT  (1 << 1)
+
+
+struct zt_transcoder {
+	struct zt_transcoder *next;
+	char name[80];
+	int numchannels;
+	unsigned int srcfmts;
+	unsigned int dstfmts;
+	int (*operation)(struct zt_transcoder_channel *channel, int op);
+	/* Transcoder channels */
+	struct zt_transcoder_channel channels[0];
+};
+
 #define ZT_WATCHDOG_NOINTS		(1 << 0)
 
 #define ZT_WATCHDOG_INIT			1000
@@ -1354,67 +1441,100 @@
 };
 
 /* Receive a dynamic span message */
-extern void zt_dynamic_receive(struct zt_span *span, unsigned char *msg, int msglen);
+void zt_dynamic_receive(struct zt_span *span, unsigned char *msg, int msglen);
 
 /* Register a dynamic driver */
-extern int zt_dynamic_register(struct zt_dynamic_driver *driver);
+int zt_dynamic_register(struct zt_dynamic_driver *driver);
 
 /* Unregister a dynamic driver */
-extern void zt_dynamic_unregister(struct zt_dynamic_driver *driver);
+void zt_dynamic_unregister(struct zt_dynamic_driver *driver);
 
 /* Receive on a span.  The zaptel interface will handle all the calculations for
    all member channels of the span, pulling the data from the readchunk buffer */
-extern int zt_receive(struct zt_span *span);
+int zt_receive(struct zt_span *span);
 
 /* Prepare writechunk buffers on all channels for this span */
-extern int zt_transmit(struct zt_span *span);
+int zt_transmit(struct zt_span *span);
 
 /* Abort the buffer currently being receive with event "event" */
-extern void zt_hdlc_abort(struct zt_chan *ss, int event);
+void zt_hdlc_abort(struct zt_chan *ss, int event);
 
 /* Indicate to zaptel that the end of frame was received and rotate buffers */
-extern void zt_hdlc_finish(struct zt_chan *ss);
+void zt_hdlc_finish(struct zt_chan *ss);
 
 /* Put a chunk of data into the current receive buffer */
-extern void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes);
+void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes);
 
 /* Get a chunk of data from the current transmit buffer.  Returns -1 if no data
  * is left to send, 0 if there is data remaining in the current message to be sent
  * and 1 if the currently transmitted message is now done */
-extern int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size);
+int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size);
 
 
 /* Register a span.  Returns 0 on success, -1 on failure.  Pref-master is non-zero if
    we should have preference in being the master device */
-extern int zt_register(struct zt_span *span, int prefmaster);
+int zt_register(struct zt_span *span, int prefmaster);
+
+/* Allocate / free memory for a transcoder */
+struct zt_transcoder *zt_transcoder_alloc(int numchans);
+void zt_transcoder_free(struct zt_transcoder *ztc);
+
+/* Register a transcoder */
+int zt_transcoder_register(struct zt_transcoder *tc);
+
+/* Unregister a transcoder */
+int zt_transcoder_unregister(struct zt_transcoder *tc);
+
+/* Alert a transcoder */
+int zt_transcoder_alert(struct zt_transcoder_channel *ztc);
+
+/* Sanity check values */
+static inline int zt_tc_sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes)
+{
+	if (zth->dstoffset >= sizeof(zth->dstdata))
+		return 0;
+	if (zth->dstlen >= sizeof(zth->dstdata))
+		return 0;
+	if (outbytes >= sizeof(zth->dstdata))
+		return 0;
+	if ((zth->dstoffset + zth->dstlen + outbytes) >= sizeof(zth->dstdata))
+		return 0;
+	if (zth->srcoffset >= sizeof(zth->srcdata))
+		return 0;
+	if (zth->srclen >= sizeof(zth->srcdata))
+		return 0;
+	if ((zth->srcoffset + zth->srclen) > sizeof(zth->srcdata))
+		return 0;
+	return 1;
+}
 
 /* Unregister a span */
-extern int zt_unregister(struct zt_span *span);
+int zt_unregister(struct zt_span *span);
 
 /* Gives a name to an LBO */
-extern char *zt_lboname(int lbo);
+char *zt_lboname(int lbo);
 
 /* Tell Zaptel about changes in received rbs bits */
-extern void zt_rbsbits(struct zt_chan *chan, int bits);
+void zt_rbsbits(struct zt_chan *chan, int bits);
 
 /* Tell Zaptel abou changes in received signalling */
-extern void zt_hooksig(struct zt_chan *chan, zt_rxsig_t rxsig);
+void zt_hooksig(struct zt_chan *chan, zt_rxsig_t rxsig);
 
 /* Queue an event on a channel */
-extern void zt_qevent_nolock(struct zt_chan *chan, int event);
+void zt_qevent_nolock(struct zt_chan *chan, int event);
 
 /* Queue an event on a channel, locking it first */
-extern void zt_qevent_lock(struct zt_chan *chan, int event);
+void zt_qevent_lock(struct zt_chan *chan, int event);
 
 /* Notify a change possible change in alarm status */
-extern void zt_alarm_notify(struct zt_span *span);
+void zt_alarm_notify(struct zt_span *span);
 
 /* Initialize a tone state */
-extern void zt_init_tone_state(struct zt_tone_state *ts, struct zt_tone *zt);
+void zt_init_tone_state(struct zt_tone_state *ts, struct zt_tone *zt);
 
 /* Get a given DTMF or MF tone struct, suitable for zt_tone_nextsample.
    Set 'mf' to 0 for DTMF or 1 for MFv1 */
-extern struct zt_tone *zt_dtmf_tone(char digit, int mf);
+struct zt_tone *zt_dtmf_tone(char digit, int mf);
 
 /* Echo cancel a receive and transmit chunk for a given channel.  This
    should be called by the low-level driver as close to the interface
@@ -1422,23 +1542,25 @@
    AT THE ZAPTEL LEVEL.  zt_ec_chunk will not echo cancel if it should
    not be doing so.  rxchunk is modified in-place */
 
-extern void zt_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk);
-extern void zt_ec_span(struct zt_span *span);
+void zt_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk);
+void zt_ec_span(struct zt_span *span);
+
+extern struct file_operations *zt_transcode_fops;
 
 /* Don't use these directly -- they're not guaranteed to
    be there. */
 extern short __zt_mulaw[256];
 extern short __zt_alaw[256];
 #ifdef CONFIG_CALC_XLAW
-extern u_char __zt_lineartoulaw(short a);
-extern u_char __zt_lineartoalaw(short a);
+u_char __zt_lineartoulaw(short a);
+u_char __zt_lineartoalaw(short a);
 #else
 extern u_char __zt_lin2mu[16384];
 extern u_char __zt_lin2a[16384];
 #endif
 
 /* Used by dynamic zaptel -- don't use directly */
-extern void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data));
+void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data));
 
 /* Used privately by zaptel.  Avoid touching directly */
 struct zt_tone {
@@ -1604,6 +1726,34 @@
 
 #define	ZT_RADPAR_REMCOMMAND 17	/* Remote conrtol write data block & do cmd */
 
+/* Data formats for capabilities and frames alike (from Asterisk) */
+/*! G.723.1 compression */
+#define ZT_FORMAT_G723_1	(1 << 0)
+/*! GSM compression */
+#define ZT_FORMAT_GSM		(1 << 1)
+/*! Raw mu-law data (G.711) */
+#define ZT_FORMAT_ULAW		(1 << 2)
+/*! Raw A-law data (G.711) */
+#define ZT_FORMAT_ALAW		(1 << 3)
+/*! ADPCM (G.726, 32kbps) */
+#define ZT_FORMAT_G726		(1 << 4)
+/*! ADPCM (IMA) */
+#define ZT_FORMAT_ADPCM		(1 << 5)
+/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define ZT_FORMAT_SLINEAR	(1 << 6)
+/*! LPC10, 180 samples/frame */
+#define ZT_FORMAT_LPC10		(1 << 7)
+/*! G.729A audio */
+#define ZT_FORMAT_G729A		(1 << 8)
+/*! SpeeX Free Compression */
+#define ZT_FORMAT_SPEEX		(1 << 9)
+/*! iLBC Free Compression */
+#define ZT_FORMAT_ILBC		(1 << 10)
+/*! Maximum audio format */
+#define ZT_FORMAT_MAX_AUDIO	(1 << 15)
+/*! Maximum audio mask */
+#define ZT_FORMAT_AUDIO_MASK	((1 << 16) - 1)
+
 #define	ZT_RADPAR_DEEMP 18 /* Audio De-empahsis (on or off) */ 
 
 #define	ZT_RADPAR_PREEMP 19 /* Audio Pre-empahsis (on or off) */ 

Added: trunk/zttranscode.c
URL: http://svn.digium.com/view/zaptel/trunk/zttranscode.c?rev=1162&view=auto
==============================================================================
--- trunk/zttranscode.c (added)
+++ trunk/zttranscode.c Fri Jun 23 10:11:45 2006
@@ -1,0 +1,441 @@
+/*
+ * Transcoder Interface for Zaptel
+ *
+ * Written by Mark Spencer <markster at digium.com>
+ *
+ * Copyright (C) 2006, Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ */
+
+#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/interrupt.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <linux/zaptel.h>
+#endif
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+static int debug = 0;
+static struct zt_transcoder *trans;
+static spinlock_t translock = SPIN_LOCK_UNLOCKED;
+
+EXPORT_SYMBOL(zt_transcoder_register);
+EXPORT_SYMBOL(zt_transcoder_unregister);
+EXPORT_SYMBOL(zt_transcoder_alert);
+EXPORT_SYMBOL(zt_transcoder_alloc);
+EXPORT_SYMBOL(zt_transcoder_free);
+
+struct zt_transcoder *zt_transcoder_alloc(int numchans)
+{
+	struct zt_transcoder *ztc;
+	unsigned int x;
+	size_t size = sizeof(*ztc) + (sizeof(ztc->channels[0]) * numchans);
+
+	if (!(ztc = 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;
+	}
+
+	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 zt_transcoder_free(struct zt_transcoder *ztc)
+{
+	kfree(ztc);
+}
+
+/* Register a transcoder */
+int zt_transcoder_register(struct zt_transcoder *tc)
+{
+	struct zt_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("Registered 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 zt_transcoder_unregister(struct zt_transcoder *tc) 
+{
+	struct zt_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("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 zt_transcoder_alert(struct zt_transcoder_channel *ztc)
+{
+	if (debug)
+		printk("ZT Transcoder Alert!\n");
+	if (ztc->tch)
+		ztc->tch->status &= ~ZT_TC_FLAG_BUSY;
+	wake_up_interruptible(&ztc->ready);
+
+	return 0;
+}
+
+static int zt_tc_open(struct inode *inode, struct file *file)
+{
+	struct zt_transcoder_channel *ztc;
+	struct zt_transcode_header *zth;
+
+	ztc = kmalloc(sizeof(*ztc), GFP_KERNEL);
+	zth = kmalloc(sizeof(*zth), GFP_KERNEL | GFP_DMA);
+	
+	if (ztc && zth) {
+		memset(ztc, 0, sizeof(*ztc));
+		memset(zth, 0, sizeof(*zth));
+		ztc->flags = ZT_TC_FLAG_TRANSIENT|ZT_TC_FLAG_BUSY;
+		ztc->tch = zth;
+		if (debug)
+			printk("Allocated Transcoder Channel, header is at %p!\n", zth);
+		zth->magic = ZT_TRANSCODE_MAGIC;
+		file->private_data = ztc;
+
+		return 0;
+	}
+
+	if (ztc)
+		kfree(ztc);
+	if (zth)
+		kfree(zth);
+	return -ENOMEM;
+}
+
+static void ztc_release(struct zt_transcoder_channel *ztc)
+{
+	if (!ztc)
+		return;
+
+	ztc->flags &= ~(ZT_TC_FLAG_BUSY);
+	if (ztc->tch)
+		kfree(ztc->tch);
+	ztc->tch = NULL;
+	if (ztc->flags & ZT_TC_FLAG_TRANSIENT)
+		kfree(ztc);
+	if (debug)
+		printk("Released Transcoder!\n");
+}
+
+static int zt_tc_release(struct inode *inode, struct file *file)
+{
+	ztc_release(file->private_data);
+
+	return 0;
+}
+
+static int do_reset(struct zt_transcoder_channel **ztc)
+{
+	struct zt_transcoder_channel *newztc = NULL, *origztc = NULL;
+	struct zt_transcode_header *zth = (*ztc)->tch;
+	struct zt_transcoder *tc;
+	unsigned int x;
+	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 & ZT_TC_FLAG_BUSY)
+					continue;
+
+				newztc = &tc->channels[x];
+				newztc->flags = ZT_TC_FLAG_BUSY;
+				break;
+			}
+		}
+		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 & ~(ZT_TC_FLAG_TRANSIENT));
+		ztc_release(origztc);
+	}
+
+	/* Actually reset the transcoder channel */
+	if ((*ztc)->parent && ((*ztc)->parent->operation))
+		return (*ztc)->parent->operation((*ztc), ZT_TCOP_RESET);
+
+	return -EINVAL;
+}
+
+static int wait_busy(struct zt_transcoder_channel *ztc)
+{
+	int ret;
+
+	for (;;) {
+		if (!(ztc->tch->status & ZT_TC_FLAG_BUSY))
+			return 0;
+		if ((ret = schluffen(&ztc->ready)))
+			return ret;
+	}
+}
+
+static int zt_tc_getinfo(unsigned long data)
+{
+	struct zt_transcode_info info;
+	unsigned int x;
+	struct zt_transcoder *tc;
+	
+	if (copy_from_user(&info, (struct zt_transcode_info *) data, sizeof(info)))
+		return -EFAULT;
+
+	spin_lock(&translock);
+	for (tc = trans, x = info.tcnum; tc && x; tc = tc->next, x--);
+	spin_unlock(&translock);
+
+	if (!tc)
+		return -ENOSYS;
+
+	strncpy(info.name, tc->name, sizeof(info.name) - 1);
+	info.srcfmts = tc->srcfmts;
+	info.dstfmts = tc->dstfmts;
+
+	return copy_to_user((struct zt_transcode_info *) data, &info, sizeof(info)) ? -EFAULT : 0;
+}
+
+static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+{
+	int op;
+	int ret;
+	struct zt_transcoder_channel *ztc = file->private_data;
+
+	if (cmd != ZT_TRANSCODE_OP)
+		return -ENOSYS;
+
+	if (get_user(op, (int *) data))
+		return -EFAULT;
+
+	if (debug)
+		printk("ZT Transcode ioctl op = %d!\n", op);
+
+	switch(op) {
+	case ZT_TCOP_GETINFO:
+		ret = zt_tc_getinfo(data);
+		break;
+	case ZT_TCOP_RESET:
+		/* Reset transcoder, possibly changing who we point to */
+		ret = do_reset(&ztc);
+		file->private_data = ztc;
+		break;
+	case ZT_TCOP_TRANSCODE:
+		if (!ztc->parent->operation)
+			return -EINVAL;
+
+		ztc->tch->status |= ZT_TC_FLAG_BUSY;
+		if (!(ret = ztc->parent->operation(ztc, ZT_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 &= ~ZT_TC_FLAG_BUSY;
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	return ret;
+}
+
+static int zt_tc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct zt_transcoder_channel *ztc = file->private_data;
+	unsigned long physical;
+
+	if (!ztc)
+		return -EINVAL;
+
+	/* Do not allow an offset */
+	if (vma->vm_pgoff) {
+		if (debug)
+			printk("zttranscode: Attempted to mmap with offset!\n");
+		return -EINVAL;
+	}
+
+	if ((vma->vm_end - vma->vm_start) != sizeof(struct zt_transcode_header)) {
+		if (debug)
+			printk("zttranscode: Attempted to mmap with size %d != %zd!\n", (int) (vma->vm_end - vma->vm_start), sizeof(struct zt_transcode_header));
+		return -EINVAL;
+	}
+
+	physical = (unsigned long) virt_to_phys(ztc->tch);
+	if (remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, sizeof(struct zt_transcode_header), PAGE_SHARED)) {
+		if (debug)
+			printk("zttranscode: remap failed!\n");
+		return -EAGAIN;
+	}
+
+	if (debug)
+		printk("zttranscode: successfully mapped transcoder!\n");
+
+	return 0;
+}
+
+static unsigned int zt_tc_poll(struct file *file, struct poll_table_struct *wait_table)
+{
+	struct zt_transcoder_channel *ztc = file->private_data;
+
+	if (!ztc)
+		return -EINVAL;
+
+	poll_wait(file, &ztc->ready, wait_table);
+	return ztc->tch->status & ZT_TC_FLAG_BUSY ? 0 : POLLPRI;
+}
+
+struct file_operations __zt_transcode_fops = {
+	owner: THIS_MODULE,
+	llseek: NULL,
+	open: zt_tc_open,
+	release: zt_tc_release,
+	ioctl: zt_tc_ioctl,
+	read: NULL,
+	write: NULL,
+	poll: zt_tc_poll,
+	mmap: zt_tc_mmap,
+	flush: NULL,
+	fsync: NULL,
+	fasync: NULL,
+};
+
+int zttranscode_init(void)
+{
+	if (zt_transcode_fops) {
+		printk("Whoa, zt_transcode_fops already set?!\n");
+		return -EBUSY;
+	}
+
+	zt_transcode_fops = &__zt_transcode_fops;
+	printk("Zaptel Transcoder support loaded\n");
+
+	return 0;
+}
+
+void zttranscode_cleanup(void)
+{
+	zt_transcode_fops = NULL;
+	printk("Zaptel Transcoder support unloaded\n");
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+#endif
+MODULE_DESCRIPTION("Zaptel Transcoder Support");
+MODULE_AUTHOR("Mark Spencer <markster at digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(zttranscode_init);
+module_exit(zttranscode_cleanup);

Propchange: trunk/zttranscode.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/zttranscode.c
------------------------------------------------------------------------------
    svn:keywords = Author Id Date Revision

Propchange: trunk/zttranscode.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain



More information about the zaptel-commits mailing list