voip-device.c
上传用户:weyjxb
上传日期:2020-05-18
资源大小:52k
文件大小:48k
- /*
- * voipblaster.c
- * (C) Copyright 2001, 2002 by Thomas Davis (tdavis@beeble.homelinux.net)
- * (C) Copyright 2001 by Michael Bosland <mike@ring.org>
- *
- * 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/config.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/signal.h>
- #include <linux/errno.h>
- #include <linux/proc_fs.h>
- #include <linux/fs.h>
- #include <linux/poll.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/spinlock.h>
- #include <linux/smp_lock.h>
- #include <linux/usb.h>
- #include <asm/string.h>
- #include "telephony.h"
- #include "voip-ver.h"
- #include "voip-config.h"
- #include "ixjuser.h"
- #include "phonedev.h"
- #include "voipblaster.h"
- /* These lines are taken from the netbsd port. */
- static u_char init_1[] =
- {
- 0x3b,0x00,0x40,0x8b // first 2 bytes is length, second 2 bytes is command?
- };
- static u_char init_2[] =
- {
- 0x00,0x01,0x00,0x00,0x18,0x02,0x8f,0x00,
- 0x10,0x00,0x28,0x40,0x03,0x1a,0x0d,0x0c,
- 0xfa,0x43,0xfd,0xea,0x93,0xfe,0x1a,0x41,
- 0x00,0x4a,0x93,0xfe,0x2a,0x40,0x00,0x1a,
- 0x93,0xfe,0x3a,0x0a,0x00,0x1f,0x3c,0x00,
- 0x8c,0x0d,0x03,0xa3,0x23,0xa2,0xdf,0x0d,
- 0x0c,0x3a,0x40,0x00,0x2a,0x93,0xfe,0x4a,
- 0x0a,0x00,0x0f
- };
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
- static struct usb_device_id voipblaster_ids[] = {
- { USB_DEVICE(0x1292,0x258) }, /* Vendor/Device */
- { },
- };
- MODULE_DEVICE_TABLE (usb, voipblaster_ids);
- #endif
- static struct usb_voipblaster *voipblaster_table[VOIP_MAX];
- /* lock to protect the voipblaster_table structure */
- static DECLARE_MUTEX (voipblaster_table_mutex);
- /* local function prototypes */
- static ssize_t voipblaster_read(struct file *file, char *buffer, size_t count, loff_t *ppos);
- static ssize_t voipblaster_write(struct file *file, const char *buffer, size_t count, loff_t *ppos);
- static int voipblaster_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
- static int voipblaster_release(struct inode *inode, struct file *file);
- static unsigned int voipblaster_poll(struct file *file, poll_table * wait);
- static int voipblaster_fasync(int fd, struct file *file, int mode);
- /* external functions */
- extern void voipblaster_register_device(struct usb_voipblaster *);
- extern void voipblaster_proc_init(void);
- extern void voipblaster_proc_destroy(void);
- extern int voipblaster_get_status_proc(char *);
- extern int voipblaster_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
- static void *voipblaster_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);
- #else
- static void *voipblaster_probe(struct usb_device *dev, unsigned int ifnum);
- #endif
- static void voipblaster_disconnect(struct usb_device *dev, void *ptr);
- struct file_operations voipblaster_fops =
- {
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
- owner: THIS_MODULE,
- #endif
- read: voipblaster_read,
- write: voipblaster_write,
- poll: voipblaster_poll,
- ioctl: voipblaster_ioctl,
- release: voipblaster_release,
- fasync: voipblaster_fasync
- };
- #define VOIP_DEBUG
- #ifdef VOIP_DEBUG
- static int VOIPdebug = 1;
- #else
- static int VOIPdebug = 0;
- #endif
- char VOIPversion[32];
- static int hertz;
- /* Use our own dbg macro */
- #undef dbg
- #define dbg(format, arg...) do { if (VOIPdebug) printk(KERN_DEBUG __FUNCTION__ ": " format "n" , ## arg); } while (0)
- #undef info
- #define info(format, arg...) printk(KERN_INFO __FUNCTION__ ": " format "n" , ## arg)
- #define get_voipblaster(b) voipblaster_table[(b)]
- extern __inline__ void voipblaster_kill_fasync(struct usb_voipblaster *dev, IXJ_SIGEVENT event, int dir)
- {
- dbg("minor %d, event = %d", dev->minor, event);
- if(dev->signals[event]) {
- dbg("Sending signal for event %d", event);
- /* Send apps notice of change */
- /* see config.h for macro definition */
- VOIP_KILL_FASYNC(dev->async_queue, dev->signals[event], dir);
- }
- }
- static int capabilities_check(struct usb_voipblaster *dev, struct phone_capability *pcreq)
- {
- int cnt;
- int retval = 0;
- for (cnt = 0; cnt < dev->caps; cnt++) {
- if (pcreq->captype == dev->caplist[cnt].captype
- && pcreq->cap == dev->caplist[cnt].cap) {
- retval = 1;
- break;
- }
- }
- return retval;
- }
- static void add_caps(struct usb_voipblaster *j)
- {
- j->caps = 0;
- j->caplist[j->caps].cap = PHONE_VENDOR_VOIPBLASTER;
- strcpy(j->caplist[j->caps].desc, "Linux Hackers, Inc");
- j->caplist[j->caps].captype = vendor;
- j->caplist[j->caps].handle = j->caps++;
- j->caplist[j->caps].captype = device;
- switch (j->cardtype) {
- case CREATIVE_VOIPBLASTER:
- strcpy(j->caplist[j->caps].desc, "Creative VOIP Blaster/USB");
- break;
- default:
- strcpy(j->caplist[j->caps].desc, "Unknown Card");
- break;
- }
- j->caplist[j->caps].cap = j->cardtype;
- j->caplist[j->caps].handle = j->caps++;
- strcpy(j->caplist[j->caps].desc, "POTS");
- j->caplist[j->caps].captype = port;
- j->caplist[j->caps].cap = pots;
- j->caplist[j->caps].handle = j->caps++;
- /* add devices that can do speaker/mic */
- switch (j->cardtype) {
- case CREATIVE_VOIPBLASTER:
- strcpy(j->caplist[j->caps].desc, "SPEAKER");
- j->caplist[j->caps].captype = port;
- j->caplist[j->caps].cap = speaker;
- j->caplist[j->caps].handle = j->caps++;
- default:
- break;
- }
- #if 0
- /* add devices that can do handset */
- switch (j->cardtype) {
- case CREATIVE_VOIPBLASTER:
- strcpy(j->caplist[j->caps].desc, "HANDSET");
- j->caplist[j->caps].captype = port;
- j->caplist[j->caps].cap = handset;
- j->caplist[j->caps].handle = j->caps++;
- break;
- default:
- break;
- }
- #endif
- #define ENABLE_G723_63 1
- #if defined(ENABLE_G723_63)
- strcpy(j->caplist[j->caps].desc, "G.723.1 6.3kbps");
- j->caplist[j->caps].captype = codec;
- j->caplist[j->caps].cap = G723_63;
- j->caplist[j->caps].handle = j->caps++;
- #endif
- strcpy(j->caplist[j->caps].desc, "G.723.1 5.3kbps");
- j->caplist[j->caps].captype = codec;
- j->caplist[j->caps].cap = G723_53;
- j->caplist[j->caps].handle = j->caps++;
- }
- static void voipblaster_event_irq(urb_t *urb)
- {
- struct usb_voipblaster *dev = urb->context;
- char event;
- unsigned long flags;
- /* Received an event from the voipblaster. Place it in the event
- buffer if there is any room. If it is DTMF data place it in the
- DTMF buffer instead. Maybe signal somebody that some new stuff
- has arrived. */
- spin_lock_irqsave(&dev->io_lock,flags);
- /* Figure out what we have. */
- event = dev->event_data[0];
- dbg("Event Received: 0x%02x, dtmf_ready = %d",event, dev->ex.bits.dtmf_ready);
- if ((event >= VB_EVENT_DTMF0 && event <= VB_EVENT_DTMF9)
- || event == VB_EVENT_DTMFSTAR || event == VB_EVENT_DTMFPND) {
- /* This is DTMF Information. Convert to char and add to
- the DTMF buffer if there is room available. If not,
- drop it. */
- char dtmf;
- switch (event) {
- case VB_EVENT_DTMFSTAR:
- dbg("*");
- dtmf = 10;
- break;
- case VB_EVENT_DTMFPND:
- dbg("#");
- dtmf = 12;
- break;
- case VB_EVENT_DTMF0:
- dbg("0");
- dtmf = 11;
- break;
- default:
- dtmf = event - VB_EVENT_DTMF0;
- break;
- }
-
- dbg("DTMF decoded: 0x%02x", dtmf & 0xff);
- if (dev->dtmf_buffer_len > VB_DTMF_BUFF_LENGTH) {
- info("No more room for DTMF data. Discarding");
- } else {
- /* Add this DTMF data to the end of the DTMF buffer */
- dev->ex.bits.dtmf_ready = 1;
- if (dev->ex_sig.bits.dtmf_ready) {
- voipblaster_kill_fasync(dev, SIG_DTMF_READY, POLL_IN);
- }
- dev->dtmf_buffer[dev->dtmf_buffer_in] = dtmf;
- dev->dtmf_buffer_len++;
- dev->dtmf_buffer_in++;
- if (dev->dtmf_buffer_in > VB_DTMF_BUFF_LENGTH)
- dev->dtmf_buffer_in = 0;
- }
- } else {
- /* Determine what, if any flags to set. */
- switch (event) {
- case VB_EVENT_OFFHOOK:
- dbg("VB_EVENT_OFFHOOK");
- dev->hookstate = 1;
- dev->ex.bits.hookstate = 1;
- voipblaster_kill_fasync(dev, SIG_HOOKSTATE, POLL_IN);
- break;
- case VB_EVENT_ONHOOK:
- dbg("VB_EVENT_ONHOOK");
- dev->hookstate = 0;
- dev->ex.bits.hookstate = 1;
- voipblaster_kill_fasync(dev, SIG_HOOKSTATE, POLL_IN);
- break;
- case VB_EVENT_RINGING_OFF:
- dbg("VB_EVENT_RINGING_OFF");
- dev->ringing = 0;
- break;
- case VB_EVENT_RINGING_ON:
- dbg("VB_EVENT_RINGING_ON");
- dev->ringing = 1;
- break;
- default:
- /* This is not DTMF data. It is some other event */
- if (dev->event_buffer_len > VB_EVENT_BUFF_LENGTH) {
- info("No more room for EVENT data. Discarding");
- } else {
- /* Add this EVENT data to the end of the EVENT buffer */
- dev->event_buffer_len++;
- dev->event_buffer_in++;
- if (dev->event_buffer_in > VB_EVENT_BUFF_LENGTH)
- dev->event_buffer_in = 0;
- dev->event_buffer[dev->event_buffer_in] = event;
- }
- dbg("got event 0x%02x", event);
- break;
- }
-
- }
- #if 0
- #if !defined(USB_INT_URB)
- if (dev->udev != NULL) {
- /* Prepare the event urb... */
- FILL_BULK_URB(dev->event_urb, dev->udev,
- usb_rcvbulkpipe(dev->udev, 0x81),
- dev->event_data, 1,
- voipblaster_event_irq, dev);
- dbg("Starting Event URB");
- if (usb_submit_urb(dev->event_urb) != 0) {
- dbg("error with event_urb, status = %d", dev->event_urb->status);
- }
- } else {
- dbg("udev = NULL");
- }
- #endif
- #endif
- /* Notify driver of new event data... */
- dbg("waking sleeper(s)..");
- wake_up(&dev->event_q);
- wake_up(&dev->poll_q);
- wake_up(&dev->read_q);
- spin_unlock_irqrestore(&dev->io_lock,flags);
- }
- static void voipblaster_event_poll(struct usb_voipblaster *dev, int timeout)
- {
- interruptible_sleep_on_timeout(&dev->event_q, timeout);
- }
- #if 0
- static int voipblaster_status(struct usb_voipblaster *dev)
- {
- int retval;
- dbg("%d events in buffer", dev->event_buffer_len);
- if (dev->event_buffer_len > 0) {
- dev->event_buffer_len--;
- dev->event_buffer_out++;
- if (dev->event_buffer_out > VB_EVENT_BUFF_LENGTH)
- dev->event_buffer_out = 0;
- retval = dev->event_buffer[dev->event_buffer_in];
- } else {
- retval = -1;
- }
- dbg("retval = %d", retval);
- return retval;
- }
- #endif
- static void voipblaster_cmd_irq(urb_t *urb)
- {
- struct usb_voipblaster *dev = urb->context;
- unsigned long flags;
- /* The last command was sent to the voipblaster. If there are
- any more commands send them off too. If there aren't anymore
- then unlink this urb. This completion handler may also be
- called when we unlink the URB... */
- dbg("URB Returned, urb->status = %d", urb->status);
- spin_lock_irqsave(&dev->io_lock,flags);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
- dbg(" nonzero status received: %d", urb->status);
- }
- spin_unlock_irqrestore(&dev->io_lock,flags);
- goto exit;
- }
- spin_unlock_irqrestore(&dev->io_lock,flags);
- dbg("waking sleeper..");
- wake_up(&dev->cmd_q);
- exit:
- dbg("CMD completed");
- }
- static int voipblaster_cmd(struct usb_voipblaster *dev, char cmd)
- {
- /* Send a command to the voipblaster using a single shot
- interupt URB. This command will wait for completion before
- returning control */
-
- unsigned long flags;
- int urb_err;
- dbg("Queuing command: 0x%02x", cmd);
- /* see if we are already in the middle of a write */
- if (dev->cmd_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- return -1;
- }
- spin_lock_irqsave(&dev->io_lock,flags);
- if (dev->cmd_buffer_len > VB_CMD_BUFF_LENGTH) {
- info(" No room in command buffer for new command");
- spin_unlock_irqrestore(&dev->io_lock,flags);
- return -1;
- }
- /* A fresh URB needs to be sent off */
- dbg("Submitting CMD URB");
- dev->cmd_data[0] = cmd;
- /* Prepare the command urb... */
- #if defined(USE_INT_URB)
- FILL_INT_URB(dev->cmd_urb,
- dev->udev,
- usb_sndintpipe(dev->udev,0x01),
- dev->cmd_data,
- 1,
- voipblaster_cmd_irq,
- dev,
- 0);
- #else
- FILL_BULK_URB(dev->cmd_urb,
- dev->udev,
- usb_sndbulkpipe(dev->udev,0x01),
- dev->cmd_data,
- 1,
- voipblaster_cmd_irq,
- dev);
- #endif
- urb_err = usb_submit_urb(dev->cmd_urb);
- if ( urb_err != 0) {
- info("error submitting CMD URB: %d, %d",dev->cmd_urb->status, urb_err);
- spin_unlock_irqrestore(&dev->io_lock,flags);
- return dev->cmd_urb->status;
- }
- spin_unlock_irqrestore(&dev->io_lock,flags);
- /* now wait for the IRQ to complete. */
- interruptible_sleep_on(&dev->cmd_q);
- dbg("completed");
- return 0;
- }
- static void voipblaster_snd_voice_irq(urb_t *urb)
- {
- struct usb_voipblaster *dev = urb->context;
- unsigned long flags;
- spin_lock_irqsave(&dev->io_lock,flags);
- dbg("URB Returned, urb->status = %d", urb->status);
-
- /* The current voice block has been processed... */
- dev->write_buffer_len = 0;
- spin_unlock_irqrestore(&dev->io_lock,flags);
- dbg("waking sleeper..");
- wake_up(&dev->write_q);
- dbg("completed");
- }
- static int voipblaster_snd_voice(struct usb_voipblaster *dev,
- u_char *data, int length)
- {
- /* Send voice data to the voipblaster using a single shot
- interupt URB. This command will wait for completion before
- returning control */
-
- unsigned long flags;
- int i;
- dbg("sending %d bytes of voice data.", length);
- /* see if we are already in the middle of a write */
- if (dev->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- return -1;
- }
- spin_lock_irqsave(&dev->io_lock,flags);
- if (length > VB_W_BUFF_LENGTH) {
- dbg("No room in write buffer for new voice data");
- spin_unlock_irqrestore(&dev->io_lock,flags);
- return -1;
- }
- /* Add this voice data to the write buffer. */
- for (i=0; i<length; i++) {
- dev->write_buffer[i] = data[i];
- }
- dev->write_buffer_len = length;
- /* A fresh URB needs to be sent off */
- dbg("submitting write URB..");
- /* Prepare the write urb... */
- #if defined(USE_INT_URB)
- FILL_INT_URB(dev->write_urb, dev->udev,
- usb_sndintpipe(dev->udev,0x2),
- dev->write_buffer, dev->write_buffer_len,
- voipblaster_snd_voice_irq, dev,
- 0);
- #else
- FILL_BULK_URB(dev->write_urb, dev->udev,
- usb_sndbulkpipe(dev->udev,0x2),
- dev->write_buffer, dev->write_buffer_len,
- voipblaster_snd_voice_irq, dev);
- #endif
- if (usb_submit_urb(dev->write_urb) != 0) {
- dbg("error submitting WRITE URB: %d",dev->write_urb->status);
- spin_unlock_irqrestore(&dev->io_lock,flags);
- return dev->write_urb->status;
- }
- spin_unlock_irqrestore(&dev->io_lock,flags);
- dbg("sleeping..");
- interruptible_sleep_on(&dev->write_q);
- dbg("done.");
- return 0;
- }
- static void voipblaster_read_irq(urb_t *urb)
- {
- struct usb_voipblaster *dev = urb->context;
- unsigned long flags;
- spin_lock_irqsave(&dev->io_lock,flags);
- dbg("URB Returned, status = %d", urb->status);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
- dbg(" - nonzero status received: %d", urb->status);
- }
- spin_unlock_irqrestore(&dev->io_lock,flags);
- goto exit;
- }
- if (!dev->ispresent) {
- dev->ispresent = 1;
- memcpy(dev->dsp_version, dev->read_buffer_urb, 10);
- memcpy(dev->dsp_serial, &dev->read_buffer_urb[10], 10);
- } else {
- memcpy(dev->read_buffer, dev->read_buffer_urb, 20);
- dev->read_buffer_ready = 1;
- dev->read_buffer_in = 20;
- }
- /* A fresh URB needs to be sent off */
- dbg("submitting read URB..");
- /* Prepare the read urb... */
- FILL_BULK_URB(dev->read_urb, dev->udev,
- usb_rcvbulkpipe(dev->udev, 0x82),
- dev->read_buffer_urb, 20,
- voipblaster_read_irq, dev);
- dbg("Starting read URB");
- if (usb_submit_urb(dev->read_urb) != 0) {
- dbg("error with read_urb, status = %d", dev->read_urb->status);
- }
- spin_unlock_irqrestore(&dev->io_lock,flags);
- dbg("waking sleeper..");
- //wake_up(&dev->poll_q);
- wake_up(&dev->read_q);
- exit:
- dbg("CMD completed");
- }
- /*
- * voipblaster_read
- */
- static ssize_t voipblaster_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
- {
- struct usb_voipblaster *dev;
- int retval = 0;
- dev = (struct usb_voipblaster *)file->private_data;
-
- dbg("minor %d, count = %d, read_buffer_ready = %d, read_wait = %ld", dev->minor,
- count, dev->read_buffer_ready, dev->read_wait);
- /* lock this object */
- down (&dev->sem);
- if (dev->flags.inread) {
- up (&dev->sem);
- return -EALREADY;
- }
- dev->flags.inread = 1;
- #if 0
- while (dev->read_buffer_ready || (dev->dtmf_state && dev->flags.dtmf_oob)) {
- #else
- while (!dev->read_buffer_ready) {
- #endif
- ++dev->read_wait;
- if (file->f_flags & O_NONBLOCK) {
- dbg("O_NONBLOCK");
- dev->flags.inread = 0;
- up (&dev->sem);
- return -EAGAIN;
- }
- if (!dev->hookstate) {
- dbg("on hook..");
- dev->flags.inread = 0;
- up (&dev->sem);
- return 0;
- }
- interruptible_sleep_on(&dev->read_q);
- if (signal_pending(current)) {
- dbg("signal_pending");
- dev->flags.inread = 0;
- up (&dev->sem);
- return -EINTR;
- }
- }
- dev->read_buffer_ready = 0;
- dev->flags.inread = 0;
- if (copy_to_user(buffer, dev->read_buffer, dev->read_buffer_in)) {
- retval = -EFAULT;
- } else {
- if (count == 24 && dev->read_buffer_in == 20) {
- retval = count;
- } else {
- retval = dev->read_buffer_in;
- dev->read_buffer_in = 0;
- }
- }
- up (&dev->sem);
- dbg("done, retval = %d", retval);
- return retval;
- #if 0
- /* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
- up (&dev->sem);
- return -ENODEV;
- }
-
-
- /* do an immediate bulk read to get data from the device */
- retval = usb_bulk_msg (dev->udev,
- usb_rcvbulkpipe (dev->udev, 0x82),
- dev->read_buffer, 20,
- &count, 60);
- /* if the read was successful, copy the data to userspace */
- if (!retval) {
- if (copy_to_user (buffer, dev->read_buffer, count))
- retval = -EFAULT;
- else
- retval = count;
- }
- #endif
- }
- /**
- * skel_write_bulk_callback
- */
- static void voipblaster_write_callback (struct urb *urb)
- {
- struct usb_voipblaster *dev = (struct usb_voipblaster *)urb->context;
- dbg("minor %d", dev->minor);
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
- dbg("write bulk status received: %d", urb->status);
- }
- wake_up(&dev->write_q);
- return;
- }
- /*
- * voipblaster_write
- */
- static u_char G723count[4] = { 24, 20, 4, 1};
- static ssize_t voipblaster_write (struct file *file, const char *buffer, size_t count, loff_t *ppos)
- {
- struct usb_voipblaster *dev;
- ssize_t bytes_written = 0;
- int retval = 0;
- dev = (struct usb_voipblaster *)file->private_data;
- dbg("minor %d, count = %d", dev->minor, count);
- /* lock this object */
- down (&dev->sem);
- /* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
- retval = -ENODEV;
- goto exit;
- }
- /* verify that we actually have some data to write */
- if (count < 4) {
- dbg("write request of too few bytes");
- goto exit;
- }
- /* see if we are already in the middle of a write */
- if (dev->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
- goto exit;
- }
- /* the least significant two bits of the start of the frame
- tell us how big the frame really is */
- bytes_written = G723count[(*(u_char *)buffer)&3];
- /* we can only write as much as 1 urb will hold */
- bytes_written = (bytes_written > VB_W_BUFF_LENGTH) ?
- VB_W_BUFF_LENGTH : bytes_written;
-
- if (count < bytes_written) {
- dbg("write request of too few bytes %d vs %d",count,bytes_written);
- goto exit;
- }
- /* copy the data from userspace into our urb */
- if (copy_from_user(dev->write_urb->transfer_buffer, buffer,
- bytes_written)) {
- retval = -EFAULT;
- goto exit;
- }
- #if 0
- usb_skel_debug_data (__FUNCTION__, bytes_written,
- dev->write_urb->transfer_buffer);
- #endif
- /* set up our urb */
- FILL_BULK_URB(dev->write_urb, dev->udev,
- usb_sndbulkpipe(dev->udev, 0x02 ),
- dev->write_buffer, bytes_written,
- voipblaster_write_callback, dev);
- /* send the data out the bulk port */
- if (usb_submit_urb(dev->write_urb) != 0) {
- err("failed submitting write urb, error %d",
- dev->write_urb->status);
- } else { /*return full frame size or max buffer size */
- retval = (count > VB_W_BUFF_LENGTH) ?
- VB_W_BUFF_LENGTH : count;
- }
- interruptible_sleep_on(&dev->write_q);
- exit:
- /* unlock the device */
- up (&dev->sem);
- return retval;
- }
- static void voipblaster_ring_start(struct usb_voipblaster *dev)
- {
- voipblaster_cmd(dev,VB_CMD_RING_ON);
- voipblaster_event_poll(dev, 10000);
- }
- static void voipblaster_ring_stop(struct usb_voipblaster *dev)
- {
- voipblaster_cmd(dev,VB_CMD_RING_OFF);
- voipblaster_event_poll(dev, 10000);
- }
- static void voipblaster_record_start(struct usb_voipblaster *dev)
- {
- voipblaster_cmd(dev,VB_CMD_VINP_START);
- // voipblaster_event_poll(dev, 10000);
- }
- static void voipblaster_record_stop(struct usb_voipblaster *dev)
- {
- voipblaster_cmd(dev,VB_CMD_VINP_STOP);
- // voipblaster_event_poll(dev, 10000);
- }
- static void voipblaster_play_start(struct usb_voipblaster *dev)
- {
- voipblaster_cmd(dev,VB_CMD_VOUT_START);
- voipblaster_cmd(dev,VB_CMD_0x10);
- voipblaster_cmd(dev,VB_CMD_0x11);
- // voipblaster_event_poll(dev, 10000);
- }
- static void voipblaster_play_stop(struct usb_voipblaster *dev)
- {
- voipblaster_cmd(dev,VB_CMD_VOUT_DONE);
- voipblaster_event_poll(dev, 10000);
- }
- static unsigned int voipblaster_poll(struct file *file, poll_table * wait)
- {
- unsigned int mask = 0;
- struct usb_voipblaster *dev;
- dev = (struct usb_voipblaster *) file->private_data;
- dbg("minor = %d, read_buffer_in = %d, write_buffer_in = %d", dev->minor,
- dev->read_buffer_in, dev->write_buffer_in);
- poll_wait(file, &(dev->poll_q), wait);
- poll_wait(file, &(dev->read_q), wait);
- dbg("poll wakeup");
- if (dev->read_buffer_in > 0) {
- dbg("read_buffer_in = %d", dev->read_buffer_in);
- mask |= POLLIN | POLLRDNORM; /* readable */
- }
- #if 0
- if (dev->write_buffer_in > 0) {
- mask |= POLLOUT | POLLWRNORM; /* writable */
- }
- #endif
- mask |= POLLOUT | POLLWRNORM; /* writable */
- if (dev->ex.bytes) {
- dbg("ex.bytes = %d", dev->ex.bytes);
- mask |= POLLPRI;
- }
- dbg("mask = 0x%04x", mask);
- return mask;
- }
- static int voipblaster_fasync(int fd, struct file *file, int mode)
- {
- struct usb_voipblaster *dev;
- dev = (struct usb_voipblaster *) file->private_data;
- dbg("minor = %d", dev->minor);
- return fasync_helper(fd, file, mode, &dev->async_queue);
- }
- /*
- * voipblaster_ioctl
- */
- static int voipblaster_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- struct usb_voipblaster *dev;
- int retval = -ENOTTY;
- int raise, mant;
- #if 0
- int c;
- #endif
- dev = (struct usb_voipblaster *)file->private_data;
- /* lock this object */
- down (&dev->sem);
- /* verify that the device wasn't unplugged */
- if (dev->udev == NULL) {
- up (&dev->sem);
- return -ENODEV;
- }
- dbg("dev %d, minor %d, cmd 0x%.4x, arg 0x%.8lx",
- dev->udev->devnum, dev->minor, cmd, arg);
- /* fill in your device specific stuff here */
- if (!capable(CAP_SYS_ADMIN)) {
- switch (cmd) {
- case IXJCTL_TESTRAM:
- case IXJCTL_HZ:
- retval = -EPERM;
- }
- }
- switch (cmd) {
- case IXJCTL_TESTRAM:
- dbg("IXJCTL_TESTRAM");
- retval = 0;
- break;
- case IXJCTL_CARDTYPE:
- dbg("IXJCTL_CARDTYPE");
- retval = dev->cardtype;
- break;
- case IXJCTL_SERIAL:
- dbg("IXJCTL_SERIAL");
- retval = dev->serial;
- break;
- case IXJCTL_VERSION:
- dbg("IXJCTL_VERSION");
- if (copy_to_user((char *) arg, VOIPversion, strlen(VOIPversion)))
- retval = -EFAULT;
- break;
- case PHONE_RING_CADENCE:
- dbg("PHONE_RING_CADENCE");
- retval = -EPERM;
- break;
- case IXJCTL_CIDCW:
- dbg("IXJCTL_CIDCW");
- retval = -EPERM;
- break;
- /* Binary compatbility */
- case OLD_PHONE_RING_START:
- dbg("OLD_PHONE_RING_START");
- arg = 0;
- /* Fall through */
- case PHONE_RING_START:
- dbg("PHONE_RING_START");
- memset(&dev->cid_send, 0, sizeof(PHONE_CID));
- voipblaster_ring_start(dev);
- retval = 0;
- break;
- case PHONE_RING_STOP:
- dbg("PHONE_RING_STOP");
- dev->flags.cringing = 0;
- if (dev->cadence_f[5].enable) {
- dev->cadence_f[5].state = 0;
- }
- voipblaster_ring_stop(dev);
- retval = 0;
- break;
- case PHONE_RING:
- dbg("PHONE_RING, maxrings = %d", dev->maxrings);
- if (dev->maxrings == 0) {
- dbg("setting maxrings = 2");
- dev->maxrings = 2;
- }
- dev->ringcnt = 0;
- retval = 0;
- while (dev->ringcnt < dev->maxrings) {
- voipblaster_ring_start(dev);
- voipblaster_event_poll(dev, 10000);
- dbg("poll returned; ringcnt = %d, hookstate = %d",
- dev->ringcnt, dev->hookstate);
- if (dev->hookstate == 1) {
- dbg("phone answered, stop ringing");
- retval = 1;
- break;
- }
- dev->ringcnt++;
- }
-
- dbg("ringcnt = %d, maxrings = %d", dev->ringcnt, dev->maxrings);
- if (!dev->hookstate) {
- voipblaster_ring_stop(dev);
- }
- break;
- case PHONE_EXCEPTION:
- dbg("PHONE_EXCEPTION");
- retval = dev->ex.bytes;
- #if 0
- if(dev->ex.bits.flash) {
- dev->flash_end = 0;
- dev->ex.bits.flash = 0;
- }
- #endif
- dev->ex.bits.pstn_ring = 0;
- dev->ex.bits.caller_id = 0;
- dev->ex.bits.pstn_wink = 0;
- dev->ex.bits.f0 = 0;
- dev->ex.bits.f1 = 0;
- dev->ex.bits.f2 = 0;
- dev->ex.bits.f3 = 0;
- dev->ex.bits.fc0 = 0;
- dev->ex.bits.fc1 = 0;
- dev->ex.bits.fc2 = 0;
- dev->ex.bits.fc3 = 0;
- dev->ex.bits.reserved = 0;
- break;
- case PHONE_HOOKSTATE:
- dbg("PHONE_HOOKSTATE");
- dev->ex.bits.hookstate = 0;
- retval = dev->hookstate;
- break;
- case IXJCTL_SET_LED:
- dbg("IXJCTL_SET_LED");
- return 0;
- break;
- case PHONE_FRAME:
- dbg("PHONE_FRAME");
- if (arg == 30) {
- retval = arg;
- } else {
- retval = -1;
- }
- break;
- case PHONE_REC_CODEC:
- dbg("PHONE_REC_CODEC");
- switch (arg) {
- case G723_53:
- dbg("G723_53");
- dev->rec_codec = arg;
- retval = 0;
- break;
- #if defined(ENABLE_G723_63)
- case G723_63:
- dbg("G723_63");
- dev->rec_codec = arg;
- retval = 0;
- break;
- #endif
- default:
- dbg("default; %ld not supported.", arg);
- retval = 1;
- break;
- }
- break;
- case PHONE_VAD:
- dbg("PHONE_VAD");
- #if 0
- blaster_vad(dev, arg);
- #endif
- break;
- case PHONE_REC_START:
- dbg("PHONE_REC_START");
- voipblaster_record_start(dev);
- retval = 0;
- break;
- case PHONE_REC_STOP:
- dbg("PHONE_REC_STOP");
- voipblaster_record_stop(dev);
- retval = 0;
- break;
- case PHONE_REC_DEPTH:
- dbg("PHONE_REC_DEPTH");
- #if 0
- set_rec_depth(dev, arg);
- #endif
- retval = 1;
- break;
- case PHONE_REC_VOLUME:
- dbg("PHONE_REC_VOLUME");
- #if 0
- if(arg == -1) {
- retval = get_rec_volume(dev);
- }
- else {
- set_rec_volume(dev, arg);
- retval = arg;
- }
- #endif
- break;
- case PHONE_REC_VOLUME_LINEAR:
- dbg("PHONE_REC_VOLUME_LINEAR");
- #if 0
- if(arg == -1) {
- retval = get_rec_volume_linear(dev);
- }
- else {
- set_rec_volume_linear(dev, arg);
- retval = arg;
- }
- #endif
- break;
- case IXJCTL_DTMF_PRESCALE:
- dbg("IXJCTL_DTMF_PRESCALE");
- #if 0
- if(arg == -1) {
- retval = get_dtmf_prescale(dev);
- }
- else {
- set_dtmf_prescale(dev, arg);
- retval = arg;
- }
- #endif
- break;
- case PHONE_REC_LEVEL:
- dbg("PHONE_REC_LEVEL");
- #if 0
- retval = get_rec_level(dev);
- #endif
- break;
- case IXJCTL_SC_RXG:
- dbg("IXJCTL_SC_RXG");
- #if 0
- retval = VOIPblaster_siadc(dev, arg);
- #endif
- break;
- case IXJCTL_SC_TXG:
- dbg("IXJCTL_SC_TXG");
- #if 0
- retval = VOIPblaster_sidac(dev, arg);
- #endif
- break;
- case IXJCTL_AEC_START:
- dbg("IXJCTL_AEC_START");
- retval = -EPERM;
- break;
- case IXJCTL_AEC_STOP:
- dbg("IXJCTL_AEC_STOP");
- retval = -EPERM;
- break;
- case IXJCTL_AEC_GET_LEVEL:
- dbg("IXJCTL_AEC_GET_LEVEL");
- retval = AEC_OFF;
- break;
- case PHONE_PLAY_CODEC:
- dbg("PHONE_PLAY_CODEC");
- #if 0
- retval = set_play_codec(dev, arg);
- #endif
- retval = 0;
- break;
- case PHONE_PLAY_START:
- dbg("PHONE_PLAY_START");
- voipblaster_play_start(dev);
- dev->drybuffer = 0;
- retval = 0;
- break;
- case PHONE_PLAY_STOP:
- dbg("PHONE_PLAY_STOP");
- voipblaster_play_stop(dev);
- retval = 0;
- break;
- case PHONE_PLAY_DEPTH:
- dbg("PHONE_PLAY_DEPTH");
- #if 0
- set_play_depth(dev, arg);
- #endif
- break;
- case PHONE_PLAY_VOLUME:
- dbg("PHONE_PLAY_VOLUME");
- #if 0
- if (arg == -1) {
- retval = get_play_volume(dev);
- } else {
- set_play_volume(dev, arg);
- retval = arg;
- }
- #endif
- break;
- case PHONE_PLAY_VOLUME_LINEAR:
- dbg("PHONE_PLAY_VOLUME_LINEAR");
- #if 0
- if (arg == -1) {
- retval = get_play_volume_linear(dev);
- } else {
- set_play_volume_linear(dev, arg);
- retval = arg;
- }
- #endif
- break;
- case PHONE_PLAY_LEVEL:
- dbg("PHONE_PLAY_LEVEL");
- #if 0
- retval = get_play_level(dev);
- #endif
- retval = 0;
- break;
- case IXJCTL_DSP_TYPE:
- dbg("dsp_serial[5] = 0x%02x, dsp_serial[8] = 0x%02x",
- dev->dsp_version[5], dev->dsp_version[8]);
- retval = ((dev->dsp_version[5] << 8) | (dev->dsp_version[8] & 0xff)) & 0xffff;
- break;
- case IXJCTL_DSP_VERSION:
- dbg("dsp_serial[1] = 0x%02x, dsp_serial[2] = 0x%02x",
- dev->dsp_version[1], dev->dsp_version[2]);
- retval = ((dev->dsp_version[1] << 8) | (dev->dsp_version[2] & 0xff)) & 0xffff;
- break;
- case IXJCTL_HZ:
- dbg("IXJCTL_HZ");
- hertz = arg;
- retval = 0;
- break;
- case IXJCTL_RATE:
- dbg("IXJCTL_RATE");
- retval = -EPERM;
- break;
- case IXJCTL_DRYBUFFER_READ:
- dbg("IXJCTL_DRYBUFFER_READ");
- put_user(dev->drybuffer, (unsigned long *) arg);
- retval = 0;
- break;
- case IXJCTL_DRYBUFFER_CLEAR:
- dbg("IXJCTL_DRYBUFFER_CLEAR");
- dev->drybuffer = 0;
- retval = 0;
- break;
- case IXJCTL_FRAMES_READ:
- dbg("IXJCTL_FRAMES_READ");
- put_user(dev->framesread, (unsigned long *) arg);
- retval = 0;
- break;
- case IXJCTL_FRAMES_WRITTEN:
- dbg("IXJCTL_FRAMES_WRITTEN");
- put_user(dev->frameswritten, (unsigned long *) arg);
- retval = 0;
- break;
- case IXJCTL_READ_WAIT:
- dbg("IXJCTL_READ_WAIT");
- put_user(dev->read_wait, (unsigned long *) arg);
- retval = 0;
- break;
- case IXJCTL_WRITE_WAIT:
- dbg("IXJCTL_WRITE_WAIT");
- put_user(dev->write_wait, (unsigned long *) arg);
- retval = 0;
- break;
- case PHONE_MAXRINGS:
- dbg("IXJCTL_MAXRINGS");
- dev->maxrings = arg;
- break;
- case PHONE_SET_TONE_ON_TIME:
- dbg("PHONE_SET_TONE_ON_TIME");
- retval = -EPERM;
- break;
- case PHONE_SET_TONE_OFF_TIME:
- dbg("PHONE_SET_TONE_OFF_TIME");
- retval = -EPERM;
- break;
- case PHONE_GET_TONE_ON_TIME:
- dbg("PHONE_GET_TONE_ON_TIME");
- retval = -EPERM;
- break;
- case PHONE_GET_TONE_OFF_TIME:
- dbg("PHONE_GET_TONE_OFF_TIME");
- retval = -EPERM;
- break;
- case PHONE_PLAY_TONE:
- dbg("PHONE_PLAY_TONE");
- retval = -EPERM;
- break;
- case PHONE_GET_TONE_STATE:
- dbg("PHONE_GET_TONE_STATE");
- retval = dev->tonestate;
- break;
- case PHONE_DTMF_READY:
- dbg("PHONE_DTMF_READY, %d", dev->ex.bits.dtmf_ready);
- retval = dev->ex.bits.dtmf_ready;
- break;
- case PHONE_GET_DTMF:
- dbg("PHONE_GET_DTMF");
- dbg("hookstate = %d, len = %d, out = %d, in = %d, retval = %d",
- dev->hookstate, dev->dtmf_buffer_len, dev->dtmf_buffer_out,
- dev->dtmf_buffer_in, dev->dtmf_buffer[dev->dtmf_buffer_out]);
- if (dev->hookstate) {
- if (dev->dtmf_buffer_len > 0) {
- retval = dev->dtmf_buffer[dev->dtmf_buffer_out];
- dev->dtmf_buffer_out++;
- dev->dtmf_buffer_len--;
- if (dev->dtmf_buffer_out == VB_DTMF_BUFF_LENGTH)
- dev->dtmf_buffer_out = 0;
- if (dev->dtmf_buffer_len == 0) {
- dev->ex.bits.dtmf_ready = 0;
- dev->dtmf_buffer_out = 0;
- dev->dtmf_buffer_in = 0;
- }
- }
- }
- break;
- case PHONE_GET_DTMF_ASCII:
- dbg("PHONE_GET_DTMF_ASCII");
- if (dev->hookstate) {
- if (dev->dtmf_buffer_len > 0) {
- switch (dev->dtmf_buffer[dev->dtmf_buffer_out]) {
- case 10:
- dbg("10");
- retval = 42; /* '*'; */
- break;
- case 11:
- dbg("11");
- retval = 48; /*'0'; */
- break;
- case 12:
- dbg("12");
- retval = 35; /*'#'; */
- break;
- case 28:
- dbg("28");
- retval = 65; /*'A'; */
- break;
- case 29:
- dbg("29");
- retval = 66; /*'B'; */
- break;
- case 30:
- dbg("30");
- retval = 67; /*'C'; */
- break;
- case 31:
- dbg("31");
- retval = 68; /*'D'; */
- break;
- default:
- dbg("default");
- retval = 48 + dev->dtmf_buffer[dev->dtmf_buffer_out];
- break;
- }
- dev->dtmf_buffer_out++;
- dev->dtmf_buffer_len--;
- if (dev->dtmf_buffer_out == VB_DTMF_BUFF_LENGTH)
- dev->dtmf_buffer_out = 0;
- if (dev->dtmf_buffer_len == 0) {
- dev->ex.bits.dtmf_ready = 0;
- dev->dtmf_buffer_out = 0;
- dev->dtmf_buffer_in = 0;
- }
- }
- }
- break;
- case PHONE_DTMF_OOB:
- dbg("PHONE_DTMF_OOB");
- dev->flags.dtmf_oob = arg;
- break;
- case PHONE_DIALTONE:
- dbg("PHONE_DIALTONE");
- #if 0
- blaster_dialtone(dev);
- #endif
- break;
- case PHONE_BUSY:
- dbg("PHONE_BUSY");
- #if 0
- blaster_busytone(dev);
- #endif
- break;
- case PHONE_RINGBACK:
- dbg("PHONE_RINGBACK");
- #if 0
- blaster_ringback(dev);
- #endif
- break;
- case PHONE_WINK:
- dbg("PHONE_WINK");
- retval = -EPERM;
- break;
- case PHONE_CPT_STOP:
- dbg("PHONE_CPT_STOP");
- #if 0
- blaster_cpt_stop(dev);
- retval = -EPERM;
- #endif
- retval = 0;
- break;
- case PHONE_QUERY_CODEC:
- {
- struct phone_codec_data pd;
- int val;
- int proto_size[] = {
- -1,
- 12, 10, 16, 9, 8, 48, 5,
- 40, 40, 80, 40, 40, 6
- };
- dbg("PHONE_QUERY_CODEC");
- if (copy_from_user(&pd, (void *)arg, sizeof(pd))) {
- retval = -EFAULT;
- break;
- }
- #if defined(ENABLE_G723_63)
- if (pd.type <1 || pd.type>2) {
- retval = -EPROTONOSUPPORT;
- break;
- }
- #else
- if (pd.type != 2) {
- retval = -EPROTONOSUPPORT;
- break;
- }
- #endif
- val=proto_size[pd.type];
- pd.buf_min=pd.buf_max=pd.buf_opt=val;
- dbg("type = 0x%02x", pd.type);
- if (copy_to_user((void *)arg, &pd, sizeof(pd)))
- retval = -EFAULT;
- retval = 0;
- break;
- }
- case IXJCTL_DSP_IDLE:
- dbg("IXJCTL_DSP_IDLE");
- retval = 0;
- break;
- case IXJCTL_MIXER:
- dbg("IXJCTL_MIXER");
- retval = -EPERM;
- break;
- case IXJCTL_DAA_COEFF_SET:
- dbg("IXJCTL_DAA_COEFF_SET");
- switch (arg) {
- case DAA_US:
- dbg("DAA_US");
- dev->daa_country = DAA_US;
- retval = 1;
- break;
- case DAA_UK:
- dbg("DAA_UK");
- retval = 0;
- break;
- case DAA_FRANCE:
- dbg("DAA_FRANCE");
- retval = 0;
- break;
- case DAA_GERMANY:
- dbg("DAA_GERMANY");
- retval = 0;
- break;
- case DAA_AUSTRALIA:
- dbg("DAA_AUSTRALIA");
- retval = 0;
- break;
- case DAA_JAPAN:
- dbg("DAA_JAPAN");
- retval = 0;
- break;
- default:
- retval = 0;
- break;
- }
- break;
- case IXJCTL_DAA_AGAIN:
- dbg("IXJCTL_DAA_AGAIN");
- retval = -EPERM;
- break;
- case IXJCTL_PSTN_LINETEST:
- dbg("IXJCTL_PSTN_LINETEST");
- retval = -EPERM;
- break;
- case IXJCTL_VMWI:
- dbg("IXJCTL_VMWI");
- retval = -EPERM;
- break;
- case IXJCTL_CID:
- dbg("IXJCTL_CID");
- if (copy_to_user((char *) arg, &dev->cid, sizeof(PHONE_CID)))
- retval = -EFAULT;
- dev->ex.bits.caller_id = 0;
- retval = -EPERM;
- break;
- case IXJCTL_WINK_DURATION:
- dbg("IXJCTL_WINK_DURATION");
- dev->winktime = arg;
- retval = -EPERM;
- break;
- case IXJCTL_PORT:
- dbg("IXJCTL_PORT");
- /* VOIP Blaster have only one port to be used (Telephone) */
- if ((arg == PORT_POTS) || (arg == PORT_HANDSET)) {
- dev->port = PORT_POTS;
- retval = 0;
- } else if (arg == PORT_QUERY) {
- retval = dev->port;
- } else {
- retval = -EPERM;
- }
- break;
- case IXJCTL_POTS_PSTN:
- dbg("IXJCTL_POTS_PSTN");
- #if 0
- retval = voipblaster_set_pots(dev, arg);
- #endif
- break;
- case PHONE_CAPABILITIES:
- dbg("PHONE_CAPABILITIES");
- add_caps(dev);
- retval = dev->caps;
- break;
- case PHONE_CAPABILITIES_LIST:
- dbg("PHONE_CAPABILITIES_LIST");
- add_caps(dev);
- if (copy_to_user((char *) arg, dev->caplist,
- sizeof(struct phone_capability) * dev->caps))
- retval = -EFAULT;
- retval = 0;
- break;
- case PHONE_CAPABILITIES_CHECK:
- dbg("PHONE_CAPABILITIES_CHECK");
- {
- struct phone_capability cap;
- if (copy_from_user(&cap, (char *) arg, sizeof(cap)))
- retval = -EFAULT;
- else {
- add_caps(dev);
- retval = capabilities_check(dev, &cap);
- }
- }
- break;
- case PHONE_PSTN_SET_STATE:
- dbg("PHONE_PSTN_SET_STATE");
- #if 0
- daa_set_mode(dev, arg);
- #endif
- retval = 0;
- break;
- case PHONE_PSTN_GET_STATE:
- dbg("PHONE_PSTN_GET_STATE");
- #if 0
- retval = dev->daa_mode;
- #endif
- dev->ex.bits.pstn_ring = 0;
- retval = 0;
- break;
- case IXJCTL_SET_FILTER:
- dbg("IXJCTL_SET_FILTER");
- retval = -EPERM;
- break;
- case IXJCTL_SET_FILTER_RAW:
- dbg("IXJCTL_SET_FILTER_RAW");
- retval = -EPERM;
- break;
- case IXJCTL_GET_FILTER_HIST:
- dbg("IXJCTL_GET_FILTER_HIST");
- retval = -EINVAL;
- break;
- case IXJCTL_INIT_TONE:
- dbg("IXJCTL_INIT_TONE");
- retval = -EPERM;
- break;
- case IXJCTL_TONE_CADENCE:
- dbg("IXJCTL_TONE_CADENCE");
- retval = -EPERM;
- break;
- case IXJCTL_FILTER_CADENCE:
- dbg("IXJCTL_FILTER_CADENCE");
- retval = -EPERM;
- break;
- case IXJCTL_SIGCTL:
- dbg("IXJCTL_SIGCTL");
- if (copy_from_user(&dev->sigdef, (char *)arg, sizeof(IXJ_SIGDEF)))
- retval = -EFAULT;
- dbg("sigdef.event = %d, signal = %d", dev->sigdef.event, dev->sigdef.signal);
- dev->signals[dev->sigdef.event] = dev->sigdef.signal;
- if(dev->sigdef.event < 33) {
- raise = 1;
- for(mant = 0; mant < dev->sigdef.event; mant++){
- raise *= 2;
- }
- if(dev->sigdef.signal)
- dev->ex_sig.bytes |= raise;
- else
- dev->ex_sig.bytes &= (raise^0xffff);
- }
- retval = 0;;
- break;
- case IXJCTL_INTERCOM_STOP:
- dbg("IXJCTL_INTERCOM_STOP");
- #if 0
- if(arg < 0 || arg >= IXJMAX)
- return -EINVAL;
- dev->intercom = -1;
- blaster_record_stop(dev);
- blaster_play_stop(dev);
- idle(dev);
- get_ixj(arg)->intercom = -1;
- blaster_record_stop(get_ixj(arg));
- blaster_play_stop(get_ixj(arg));
- idle(get_ixj(arg));
- #endif
- break;
- case IXJCTL_INTERCOM_START:
- dbg("IXJCTL_INTERCOM_START");
- #if 0
- if(arg < 0 || arg >= IXJMAX)
- return -EINVAL;
- dev->intercom = arg;
- blaster_record_start(dev);
- blaster_play_start(dev);
- get_ixj(arg)->intercom = board;
- blaster_play_start(get_ixj(arg));
- blaster_record_start(get_ixj(arg));
- #endif
- break;
- }
- dbg("phone%d ioctl end, cmd: 0x%x, arg: 0x%lx, retval: 0x%.8x",
- dev->minor, cmd, arg, retval);
-
- /* unlock the device */
- up (&dev->sem);
-
- /* return that we did not understand this ioctl call */
- return retval;
- }
- static inline void voipblaster_delete (struct usb_voipblaster *dev)
- {
- int status;
- dbg("deleting USB device %d", dev->udev->devnum);
- voipblaster_table[dev->board] = NULL;
- /* Unlinking can be performed even if URB is not active */
- if ((status = usb_unlink_urb(dev->cmd_urb)))
- dbg("trouble unlinking Command URB on close: %d", status);
-
- if ((status = usb_unlink_urb(dev->event_urb)))
- dbg("trouble unlinking Event URB on close: %d", status);
- /* Unlinking can be performed even if URB is not active */
- status = usb_unlink_urb(dev->write_urb);
- if (status > 0)
- dbg("trouble unlinking write URB on close; status = %d", status);
-
- /* Unlinking can be performed even if URB is not active */
- status = usb_unlink_urb(dev->read_urb);
- if (status != 0)
- dbg("trouble unlinking read URB on close; status = %d", status);
-
- if (dev->cq.buffer != NULL) {
- dbg("freeing cq buffer");
- kfree (dev->cq.buffer);
- }
- if (dev->rq.buffer != NULL) {
- dbg("freeing rq buffer");
- kfree (dev->rq.buffer);
- }
- if (dev->wq.buffer != NULL) {
- dbg("freeing wq buffer");
- kfree (dev->wq.buffer);
- }
- if (dev->eq.buffer != NULL) {
- dbg("freeing eq buffer");
- kfree (dev->eq.buffer);
- }
- if (dev->event_urb != NULL) {
- dbg("freeing event_urb");
- usb_free_urb(dev->event_urb);
- }
- if (dev->cmd_urb != NULL) {
- dbg("freeing cmd_urb");
- usb_free_urb(dev->cmd_urb);
- }
- if (dev->read_urb != NULL) {
- dbg("freeing read_urb");
- usb_free_urb(dev->read_urb);
- }
- if (dev->write_urb != NULL) {
- dbg("freeing write_urb");
- usb_free_urb(dev->write_urb);
- }
- kfree (dev);
- }
- static inline void voipblaster_flush (struct usb_voipblaster *dev)
- {
-
- dbg("flushing USB device %d", dev->udev->devnum);
- dev->dtmf_buffer_in = dev->dtmf_buffer_out = dev->dtmf_buffer_len = 0;
- dev->ex.bits.dtmf_ready = 0;
- dev->event_buffer_in = dev->event_buffer_out = dev->event_buffer_len = 0;
- dev->read_buffer_in = 0;
-
- }
- static int voipblaster_release(struct inode *inode, struct file *file)
- {
- struct usb_voipblaster *dev;
- int retval = 0;
- dev = (struct usb_voipblaster *)file->private_data;
- if (dev == NULL) {
- dbg ("object is NULL");
- return -ENODEV;
- }
- dbg("VOIP blaster device %d, minor %d, (USB dev %d) closed", dev->board,
- dev->minor, dev->udev->devnum);
- /* lock our minor table */
- down (&voipblaster_table_mutex);
- /* lock our device */
- down (&dev->sem);
- if (dev->open_count <= 0) {
- dbg ("minordevice not opened");
- retval = -ENODEV;
- goto exit_not_opened;
- }
- #if 0
- voipblaster_fasync(-1, file, 0);
- #endif
- if (dev->udev == NULL) {
- /* the device was unplugged before the file was released */
- up (&dev->sem);
- voipblaster_delete(dev);
- // MOD_DEC_USE_COUNT;
- up (&voipblaster_table_mutex);
- return 0;
- }
- /* decrement our usage count for the device */
- --dev->open_count;
- // MOD_DEC_USE_COUNT;
- dbg("VoIP Blaster closed");
-
- exit_not_opened:
- up (&dev->sem);
- up (&voipblaster_table_mutex);
- return retval;
- }
- int voipblaster_open(struct phone_device *phone, struct file *file)
- {
- struct usb_voipblaster *dev;
- int retval = 0;
- /* increment our usage count for the module */
- // MOD_INC_USE_COUNT;
- /* lock our minor table and get our local data for this minor */
- down (&voipblaster_table_mutex);
- dev = voipblaster_table[phone->board];
- if (dev == NULL) {
- err("No device passed found!");
- up (&voipblaster_table_mutex);
- // MOD_DEC_USE_COUNT;
- return -ENODEV;
- }
- dbg("VOIP Blaster device %d (USB device %d) open...", phone->board, dev->udev->devnum);
- /* unlock the minor table */
- up (&voipblaster_table_mutex);
- /* lock this device */
- down (&dev->sem);
- /* increment our usage count for the driver */
- ++dev->open_count;
- /* save our object in the file's private structure */
- file->private_data = dev;
- voipblaster_flush(dev);
- dbg("dtmf = %d", dev->ex.bits.dtmf_ready);
- #if 0
- /* Send off an interupt urb to retrieve voice packets from the hardware */
- dbg("Starting read URB");
- if (usb_submit_urb(&dev->read_urb))
- return -EIO;
- #endif
- /* unlock this device */
- up (&dev->sem);
- return retval;
- }
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
- static void *voipblaster_probe(struct usb_device *udev, unsigned int ifnum
- ,const struct usb_device_id *id)
- #else
- static void *voipblaster_probe(struct usb_device *udev, unsigned int ifnum)
- #endif
- {
- struct usb_voipblaster *dev;
- int board;
- int i;
- int status;
-
- dbg(__FUNCTION__);
- /* allocate memory for our device state and intialize it */
- dev = kmalloc (sizeof(struct usb_voipblaster), GFP_KERNEL);
- if (dev == NULL) {
- err ("Out of memory");
- goto error;
- }
- down (&voipblaster_table_mutex);
- for (board = 0; board < VOIP_MAX; ++board) {
- if (voipblaster_table[board] == NULL)
- break;
- }
- if (board >= VOIP_MAX) {
- info ("Too many devices plugged in, can not handle this device.");
- goto error;
- }
- dbg("allocated board %d", board);
- voipblaster_table[board] = dev;
- up (&voipblaster_table_mutex);
- memset(dev, 0, sizeof(struct usb_voipblaster));
- spin_lock_init(&dev->io_lock);
- init_MUTEX (&dev->sem);
- if (udev != NULL) {
- dbg("udev->devnum = %d", udev->devnum);
- } else {
- dbg("udev is null!");
- }
- dev->udev = udev;
- dev->interface = &udev->actconfig->interface[ifnum];
- dev->board = board;
- memcpy(dev->dsp_serial, "0", 1);
- dbg("USB VoIP Blaster device %d", dev->udev->devnum);
- dev->wq.buffer = kmalloc(256, GFP_KERNEL);
- if (dev->wq.buffer == NULL) {
- err("no memory for wq.buffer");
- }
- dev->wq.size = 256;
- dev->rq.buffer = kmalloc(80, GFP_KERNEL);
- if (dev->rq.buffer == NULL) {
- err("no memory for rq.buffer");
- }
- dev->rq.size = 80;
- init_waitqueue_head(&dev->cmd_q);
- init_waitqueue_head(&dev->write_q);
- init_waitqueue_head(&dev->read_q);
- init_waitqueue_head(&dev->poll_q);
- init_waitqueue_head(&dev->event_q);
- dev->event_urb = usb_alloc_urb(0);
- dev->cmd_urb = usb_alloc_urb(0);
- dev->write_urb = usb_alloc_urb(0);
- dev->read_urb = usb_alloc_urb(0);
- /* Prepare the event urb... */
- FILL_INT_URB(dev->event_urb, udev,
- usb_rcvintpipe( udev, 0x81),
- dev->event_data, 1,
- voipblaster_event_irq, dev,
- 30);
- /* Prepare the read urb... */
- FILL_BULK_URB(dev->read_urb, dev->udev,
- usb_rcvbulkpipe(dev->udev,0x82),
- dev->read_buffer_urb, 20,
- voipblaster_read_irq, dev);
- /* Send off an interupt urb to retrieve command events from the hardware */
- dbg("Starting Event URB");
- if ((status = usb_submit_urb(dev->event_urb)) != 0) {
- dbg("error with event_urb, status = %d, %d", dev->event_urb->status, status);
- }
- dbg("Starting Read URB");
- if (usb_submit_urb(dev->read_urb) != 0) {
- dbg("error with read_urb, status = %d", dev->read_urb->status);
- }
- voipblaster_cmd(dev, VB_CMD_SETUP_MODE);
- voipblaster_flush(dev);
- voipblaster_snd_voice(dev, init_1, sizeof(init_1));
- voipblaster_flush(dev);
- voipblaster_snd_voice(dev, init_2, sizeof(init_2));
- voipblaster_flush(dev);
- voipblaster_event_poll(dev, 500);
- dbg ("init done.");
- dev->ringing = 1;
- for (i = 0; i < 2; i++) {
- int j = 10;
- voipblaster_cmd(dev, VB_CMD_VOL_3);
- voipblaster_cmd(dev, VB_CMD_RING_OFF);
- voipblaster_cmd(dev, VB_CMD_PHONE_ON);
- while (1) {
- j--;
- dbg("polling; j = %d, dev->ringing = %d", j, dev->ringing);
- voipblaster_event_poll(dev, 100);
- if (!dev->ringing) {
- break;
- }
- if (j == 0) {
- dbg ("exiting while loop..");
- break;
- }
- }
- if (!dev->ringing) {
- break;
- }
- }
- voipblaster_cmd(dev, VB_CMD_VOL_3);
- voipblaster_cmd(dev, VB_CMD_MUTE_OFF);
- dev->hookstate = 0;
- dev->cardtype = CREATIVE_VOIPBLASTER;
- dev->aec_level = AEC_OFF;
- dev->play_codec = G723_53;
- dev->rec_codec = G723_53;
- dev->port = PORT_POTS;
- snprintf(dev->serialnum, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
- dev->dsp_serial[0] & 0xff, dev->dsp_serial[1] & 0xff,
- dev->dsp_serial[2] & 0xff, dev->dsp_serial[3] & 0xff,
- dev->dsp_serial[4] & 0xff, dev->dsp_serial[5] & 0xff);
-
- snprintf(dev->revision, 30, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
- dev->dsp_version[0] & 0xff, dev->dsp_version[1] & 0xff,
- dev->dsp_version[2] & 0xff, dev->dsp_version[3] & 0xff,
- dev->dsp_version[4] & 0xff, dev->dsp_version[5] & 0xff,
- dev->dsp_version[6] & 0xff, dev->dsp_version[7] & 0xff,
- dev->dsp_version[8] & 0xff, dev->dsp_version[9] & 0xff);
-
- dbg("serial: %s", dev->serialnum);
- dbg("revision: %s", dev->revision);
- voipblaster_register_device(dev);
- dev->phone.f_op = &voipblaster_fops;
- dev->phone.open = voipblaster_open;
- dev->phone.board = board;
- phone_register_device(&dev->phone, PHONE_UNIT_ANY);
- dbg("USB VoIP Blaster registered with Linux Telephony sub system");
- goto exit;
- error:
- voipblaster_delete (dev);
- dev = NULL;
- exit:
- return dev;
- }
- static void voipblaster_disconnect(struct usb_device *udev, void *ptr)
- {
- struct usb_voipblaster *dev = (struct usb_voipblaster *) ptr;
- phone_unregister_device(&dev->phone);
- dbg("USB VoIP Blaster deregistered with Linux Telephony sub system");
- voipblaster_deregister_device(dev);
- voipblaster_delete(dev);
- dbg("USB VoIP Blaster disconnected");
- }
- static struct usb_driver voipblaster_driver = {
- name: "voipblaster",
- probe: voipblaster_probe,
- disconnect: voipblaster_disconnect,
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
- id_table: voipblaster_ids,
- #endif
- fops: &voipblaster_fops,
- };
- int __init voipblaster_init(void)
- {
- int result;
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
- voipblaster_proc_init();
- snprintf(VOIPversion, 32, "%d.%d.%d", VOIP_VER_MAJOR, VOIP_VER_MINOR, VOIP_BLD_VER);
- #else
- /* 2.2.19 does not like create_proc_read_entry and snprintf */
- sprintf(VOIPversion, "%d.%d.%d", VOIP_VER_MAJOR, VOIP_VER_MINOR, VOIP_BLD_VER);
- #endif
- result = usb_register(&voipblaster_driver);
- if (result < 0) {
- err("usb_register failed for the "__FILE__" driver. Error number %d",
- result);
- return -1;
- }
- info(DRIVER_DESC " v%s", VOIPversion);
- info("using %s", ixjuser_h_rcsid);
- return 0;
- }
- void __exit voipblaster_exit(void)
- {
- voipblaster_proc_destroy();
- usb_deregister(&voipblaster_driver);
- }
- module_init(voipblaster_init);
- module_exit(voipblaster_exit);
- MODULE_AUTHOR("Michael Bosland, <mike@ring.org>, Thomas Davis, <tadavis@veriomail.com>");
- MODULE_DESCRIPTION("USB Driver for Creative Labs VoIP Blaster");
- #ifdef MODULE_LICENSE
- MODULE_LICENSE("GPL");
- #endif
- /*
- * Local variables:
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */