summaryrefslogtreecommitdiff
path: root/wcfxsusb.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2001-12-28 17:48:23 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2001-12-28 17:48:23 +0000
commita6aa5b6c4b6795e8d18e7dfbc7f8ee11b770048a (patch)
tree6029ffb5ea8cc70a7f708c66fc2a0be56d2c9d61 /wcfxsusb.c
parent1699b655be978ba8bc1d09f6c01b3255e0efe734 (diff)
Version 0.1.4 from FTP
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@44 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'wcfxsusb.c')
-rwxr-xr-xwcfxsusb.c581
1 files changed, 482 insertions, 99 deletions
diff --git a/wcfxsusb.c b/wcfxsusb.c
index 8dc66ff..1f2cc89 100755
--- a/wcfxsusb.c
+++ b/wcfxsusb.c
@@ -39,13 +39,16 @@
#include <linux/usb.h>
#include <linux/errno.h>
#ifdef STANDALONE_ZAPATA
+
#include "zaptel.h"
#else
#include <linux/zaptel.h>
-#endif
+#endif /* STANDALONE_ZAPATA */
+
#include "wcfxsusb.h"
#include "proslic.h"
+
#ifdef DEBUG_WILDCARD
#define DPRINTK(x) printk x
#else
@@ -91,7 +94,7 @@ static alpha indirect_regs[] =
{25,"PULSE_Y",0x0000},
//{26,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower
{26,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower
-{27,"XMIT_DIGITAL_GAIN",0x4000},
+{27,"XMIT_DIGITAL_GAIN",0xc000 /* was 0x4000 */ },
{28,"LOOP_CLOSE_TRES",0x1000},
{29,"RING_TRIP_TRES",0x3600},
{30,"COMMON_MIN_TRES",0x1000},
@@ -114,6 +117,11 @@ static alpha indirect_regs[] =
#define WCUSB_SPORT2 0x28
#define WCUSB_SPORT_CTRL 0x29
+#define WC_AUX0 0x1
+#define WC_AUX1 0x2
+#define WC_AUX2 0x4
+#define WC_AUX3 0x8
+
#define CONTROL_TIMEOUT_MS (500) /* msec */
#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ) / 1000)
@@ -129,14 +137,60 @@ struct stinky_urb {
};
typedef enum {
+ STREAM_NORMAL,
+ STREAM_DTMF,
+} stream_t;
+
+typedef enum {
STATE_WCREAD_WRITEREG,
STATE_WCREAD_READRES,
STATE_WCWRITE_WRITEREG,
STATE_WCWRITE_WRITERES,
} control_state_t;
+typedef enum {
+ WC_KEYPAD,
+ WC_PROSLIC,
+} dev_type_t;
+
+typedef enum {
+ STATE_FOR_LOOP_1_OUT,
+ STATE_FOR_LOOP_2_IN,
+ STATE_FOR_LOOP_PROC_DATA,
+ STATE_FOR_LOOP_CLEAR_DIGIT,
+} keypad_state_t;
+
+typedef enum {
+ STATE_RUNNING,
+ STATE_STOPPED,
+} keypad_control_t;
+
+struct wc_keypad_data {
+ /* Keypad state monitoring variables */
+ keypad_state_t state;
+ urb_t urb;
+ keypad_control_t control;
+ char data;
+ char data12;
+ char tmp;
+ int traffic_count;
+ int scanned_event;
+ int i;
+ int count;
+ /* DTMF tone generation stuff for zaptel */
+ struct zt_tone_state ts;
+ struct zt_tone *tone;
+};
+
+#define WC_IO_READ (1 << 0)
+#define WC_IO_WRITE (1 << 1)
+
+#define IO_READY(x) (((x) & (WC_IO_READ | WC_IO_WRITE)) == \
+ (WC_IO_READ | WC_IO_WRITE))
+
struct wc_usb_pvt {
struct usb_device *dev;
+ dev_type_t devclass;
unsigned int readpipe;
unsigned int writepipe;
int usecount;
@@ -146,6 +200,8 @@ struct wc_usb_pvt {
struct zt_chan chan;
struct stinky_urb dataread[2];
struct stinky_urb datawrite[2];
+ int iostate; /* Whether reads/writes are complete */
+ urb_t *pendingurb; /* Pending URB for transmission */
urb_t control;
devrequest dr;
control_state_t controlstate;
@@ -162,8 +218,10 @@ struct wc_usb_pvt {
unsigned char wcregindex;
unsigned char wcregbuf[4];
unsigned char wcregval;
- short writechunk[ZT_MAX_CHUNKSIZE * 2];
short readchunk[ZT_MAX_CHUNKSIZE * 2];
+ short writechunk[ZT_MAX_CHUNKSIZE * 2];
+ stream_t sample;
+ void *pvt_data;
};
struct wc_usb_desc {
@@ -175,9 +233,16 @@ struct wc_usb_desc {
static struct wc_usb_desc wcusb = { "Wildcard S100U USB FXS Interface" };
static struct wc_usb_desc wcusb2 = { "Wildcard S110U USB FXS Interface", FLAG_FLIP_RELAYS };
-
+static struct wc_usb_desc wc_usb_phone = { "Wildcard Phone Test driver" };
static struct wc_usb_pvt *ifaces[WC_MAX_IFACES];
+
+
+static void wcusb_check_keypad(struct wc_usb_pvt *p);
+static int set_aux_ctrl(struct wc_usb_pvt *p, char auxpins, int on);
+
+
+
static int Wcusb_WriteWcRegs(struct usb_device *dev, unsigned char index,
unsigned char *data, int len)
{
@@ -222,8 +287,9 @@ static int Wcusb_ReadWcRegs(struct usb_device *dev, unsigned char index,
return 0;
}
-static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state);
-static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state);
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb));
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb));
+static void wcusb_async_control(urb_t *urb);
static void proslic_read_direct_async(struct wc_usb_pvt *p, unsigned char address)
{
@@ -232,7 +298,7 @@ static void proslic_read_direct_async(struct wc_usb_pvt *p, unsigned char addres
p->wcregbuf[1] = 0;
p->wcregbuf[2] = 0;
p->wcregbuf[3] = 0x67;
- wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCREAD_WRITEREG);
+ wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCREAD_WRITEREG, wcusb_async_control);
}
static void proslic_write_direct_async(struct wc_usb_pvt *p, unsigned char address, unsigned char val)
@@ -242,7 +308,7 @@ static void proslic_write_direct_async(struct wc_usb_pvt *p, unsigned char addre
p->wcregbuf[1] = val;
p->wcregbuf[2] = 0;
p->wcregbuf[3] = 0x27;
- wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCWRITE_WRITERES);
+ wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCWRITE_WRITERES, wcusb_async_control);
}
static void wcusb_async_control(urb_t *urb)
@@ -259,7 +325,7 @@ static void wcusb_async_control(urb_t *urb)
switch (p->controlstate) {
case STATE_WCREAD_WRITEREG:
/* We've written the register to sport0, now read form sport 1 */
- wcusb_async_read(p, WCUSB_SPORT1, &p->wcregval, 1, STATE_WCREAD_READRES);
+ wcusb_async_read(p, WCUSB_SPORT1, &p->wcregval, 1, STATE_WCREAD_READRES, wcusb_async_control);
return;
case STATE_WCREAD_READRES:
switch(p->wcregindex) {
@@ -327,19 +393,122 @@ static void wcusb_async_control(urb_t *urb)
}
}
+static void keypad_check_done(urb_t *urb)
+{
+ struct wc_usb_pvt *p = urb->context;
+ struct wc_keypad_data *d = p->pvt_data;
+ static char aux_pattern[] = {0x1e, 0x1d, 0x17, 0xf};
+ char digit = 'z';
+
+ p->urbcount--;
+ if (d->control == STATE_STOPPED) {
+ printk("Stopping stream (check_done)\n");
+ return;
+ }
+
+ if (urb->status) {
+ printk("status %d\n", urb->status);
+ }
+
+ if (debug) printk("i is %d\n", d->i);
+ switch (d->state) {
+loop_start:
+ case STATE_FOR_LOOP_1_OUT:
+ if (debug) printk("data12 is %x\n", d->data12);
+ if(d->i < sizeof(aux_pattern) / sizeof(char)) {
+ d->tmp = aux_pattern[d->i] | (d->data12 & 0xe0);
+ d->state = STATE_FOR_LOOP_2_IN;
+ if (debug) printk("tmp is %x\n", d->tmp);
+ wcusb_async_write(p, 0x12, &d->tmp, 1, 0, keypad_check_done);
+ return;
+ } else {
+ goto func_end;
+ }
+ case STATE_FOR_LOOP_2_IN:
+ d->state = STATE_FOR_LOOP_PROC_DATA;
+ wcusb_async_read(p, 0xc0, &d->data, 1, 0, keypad_check_done);
+ return;
+ case STATE_FOR_LOOP_PROC_DATA:
+ d->state = STATE_FOR_LOOP_CLEAR_DIGIT;
+ if(debug) printk("data is %x\n", d->data);
+ if ((d->data & 0x1f) != 0x1f) {
+ if(d->data == 0xe && aux_pattern[d->i] == 0x1e) { digit = '1';}
+ else if(d->data == 0xd && aux_pattern[d->i] == 0x1e) { digit = '2';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0x1e) { digit = '3';}
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0x1e) {
+ p->hookstate = 0; /* On||Off */
+ zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK);
+ }
+
+ else if(d->data == 0xe && aux_pattern[d->i] == 0x1d) { digit = '4';}
+ else if(d->data == 0xd && aux_pattern[d->i] == 0x1d) { digit = '5';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0x1d) { digit = '6';}
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0x1d) {
+ p->hookstate = 1;/* Dial */
+ zt_hooksig(&p->chan, ZT_RXSIG_OFFHOOK);
+ }
+
+ else if(d->data == 0xe && aux_pattern[d->i] == 0x17) { digit = '7';}
+ else if(d->data == 0xd && aux_pattern[d->i] == 0x17) { digit = '8';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0x17) { digit = '9';}
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0x17) d->scanned_event = 15; /* ReDial */
+
+ else if(d->data == 0xe && aux_pattern[d->i] == 0xf) { digit = '*';}/* '*' */
+ else if(d->data == 0xd && aux_pattern[d->i] == 0xf) { digit = '0';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0xf) { digit = '#';} /* '#' */
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0xf) d->scanned_event = 16; /* Volume? */
+ else {
+ (d->i)++;
+ if (debug) printk("Scanned event %d; data = %x\n", d->scanned_event, d->data);
+ goto loop_start;
+ }
+ } else {
+ if(debug) printk("Hit new if\n");
+ goto func_end;
+ }
+ if (debug) printk("wcusb: got digit %d\n", d->scanned_event);
+ if (digit != 'z') {
+ d->tone = zt_dtmf_tone(digit, 0);
+ if (!d->tone) {
+ printk("wcusb: Didn't get a tone structure\n");
+ goto func_end;
+ }
+ zt_init_tone_state(&d->ts, d->tone);
+ p->sample = STREAM_DTMF;
+ }
+ d->count = 0;
+ case STATE_FOR_LOOP_CLEAR_DIGIT:
+ if (((d->data & 0xf) != 0xf) && d->count < 200) {
+ wcusb_async_read(p, 0xc0, &d->data, 1, 0, keypad_check_done);
+ return;
+ }
+ (d->i)++;
+ p->sample = STREAM_NORMAL;
+ goto loop_start;
+ }
+func_end:
+ p->timer = 100;
+ return;
+}
+
static void wcusb_check_interrupt(struct wc_usb_pvt *p)
{
/* Start checking for interrupts */
- proslic_read_direct_async(p, 68);
+ if (p->devclass == WC_KEYPAD) {
+ wcusb_check_keypad(p);
+ } else {
+ proslic_read_direct_async(p, 68);
+ }
+ return;
}
-static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state)
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb))
{
urb_t *urb = &p->control;
__u16 size = len;
__u16 ind = index;
- memset(urb, 0, sizeof(p->control));
+ memset(urb, 0, sizeof(urb_t));
p->dr.requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
p->dr.request = REQUEST_NORMAL;
@@ -347,7 +516,7 @@ static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned
p->dr.index = cpu_to_le16(ind);
p->dr.length = cpu_to_le16(size);
- FILL_CONTROL_URB(urb, p->dev, usb_rcvctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, wcusb_async_control, p);
+ FILL_CONTROL_URB(urb, p->dev, usb_rcvctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, complete, p);
if (usb_submit_urb(urb)) {
printk("wcusb_async_read: control URB died\n");
return -1;
@@ -357,13 +526,13 @@ static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned
return 0;
}
-static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state)
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb))
{
urb_t *urb = &p->control;
__u16 size = len;
__u16 ind = index;
- memset(urb, 0, sizeof(p->control));
+ memset(urb, 0, sizeof(urb_t));
p->dr.requesttype = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
p->dr.request = REQUEST_NORMAL;
@@ -371,7 +540,7 @@ static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned
p->dr.index = cpu_to_le16(ind);
p->dr.length = cpu_to_le16(size);
- FILL_CONTROL_URB(urb, p->dev, usb_sndctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, wcusb_async_control, p);
+ FILL_CONTROL_URB(urb, p->dev, usb_sndctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, complete, p);
if (usb_submit_urb(urb)) {
printk("wcusb_async_write: control URB died\n");
return -1;
@@ -642,36 +811,45 @@ static int InitProSlic(struct usb_device *dev)
return 0;
}
-static int InitHardware(struct usb_device *dev)
+static int InitHardware(struct wc_usb_pvt *p)
{
+ struct usb_device *dev = p->dev;
- if (wcoutp(dev, 0x12, 0x00)) // AUX6 as output, set to low
- return -1;
+ switch (p->devclass) {
+ case WC_PROSLIC:
+ if (wcoutp(dev, 0x12, 0x00)) // AUX6 as output, set to low
+ return -1;
- if (wcoutp(dev, 0x13, 0x40)) // AUX6 is output
- return -1;
+ if (wcoutp(dev, 0x13, 0x40)) // AUX6 is output
+ return -1;
- if (wcoutp(dev, 0, 0x50)) // extrst, AUX2 is suspend
- return -1;
+ if (wcoutp(dev, 0, 0x50)) // extrst, AUX2 is suspend
+ return -1;
- if (wcoutp(dev, 0x29, 0x20)) // enable SerialUP AUX pin definition
- return -1;
+ if (wcoutp(dev, 0x29, 0x20)) // enable SerialUP AUX pin definition
+ return -1;
- if(wcoutp(dev, 0, 0x51)) // no extrst, AUX2 is suspend
- return -1;
+ if(wcoutp(dev, 0, 0x51)) // no extrst, AUX2 is suspend
+ return -1;
/* Make sure there is no gain */
- if (wcoutp(dev, 0x22, 0x00))
- return -1;
- if (wcoutp(dev, 0x23, 0xf2))
- return -1;
- if (wcoutp(dev, 0x24, 0x00))
- return -1;
- if (wcoutp(dev, 0x25, 0xc9))
- return -1;
+ if (wcoutp(dev, 0x22, 0x00))
+ return -1;
+ if (wcoutp(dev, 0x23, 0xf2))
+ return -1;
+ if (wcoutp(dev, 0x24, 0x00))
+ return -1;
+ if (wcoutp(dev, 0x25, 0xc9))
+ return -1;
// Now initial Proslic
- if(InitProSlic(dev)) {
- printk("Failed to initialize proslic\n");
- return -1;
+ if(InitProSlic(dev)) {
+ printk("Failed to initialize proslic\n");
+ return -1;
+ }
+ case WC_KEYPAD:
+ set_aux_ctrl(p, WC_AUX0, 1);
+ set_aux_ctrl(p, WC_AUX1, 1);
+ set_aux_ctrl(p, WC_AUX2, 1);
+ set_aux_ctrl(p, WC_AUX3, 1);
}
if (debug)
@@ -703,44 +881,167 @@ static struct usb_device_id wc_dev_ids[] = {
idProduct: 0x831e, /* Product ID / Chip configuration (you can't change this) */
driver_info: (unsigned long)&wcusb2,
},
+ { match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_DEVICE),
+ bInterfaceClass: USB_CLASS_AUDIO,
+ bInterfaceSubClass: 1,
+ idVendor: 0x06e6, /* */
+ idProduct: 0xb210,
+ driver_info: (unsigned long)&wc_usb_phone,
+ },
{ } /* Terminating Entry */
};
+// Don't call from an interrupt context
+static int set_aux_ctrl(struct wc_usb_pvt *p, char uauxpins, int on)
+{
+ char udata12 = 0;
+ char udata13 = 0;
+
+ wcinp(p->dev, 0x12, &udata12);
+ wcinp(p->dev, 0x13, &udata13);
+
+ wcoutp(p->dev, 0x12, on ? (uauxpins | udata12) : (~uauxpins & udata12));
+ wcoutp(p->dev, 0x13, uauxpins | udata13);
+
+ return 0;
+}
+
+static void wcusb_check_keypad(struct wc_usb_pvt *p)
+{
+ struct wc_keypad_data *d = p->pvt_data;
+
+ if (d->control == STATE_STOPPED) {
+ printk("Stopping keypad stream\n");
+ return;
+ }
+ if (debug) printk("Launched a packet\n");
+ d->state = STATE_FOR_LOOP_1_OUT;
+ d->data = -1;
+ d->data12 = -1;
+ d->scanned_event = -1;
+ d->i = 0;
+ wcusb_async_read(p, 0x12, &d->data12, 1, 0, keypad_check_done);
+ return;
+}
+
+static char wc_dtmf(struct wc_usb_pvt *p)
+{
+ struct wc_keypad_data *d = p->pvt_data;
+ short linsample = 0;
+
+ if (!d) {
+ printk("NULL pointer, go away\n");
+ return 0;
+ }
+ linsample = zt_tone_nextsample(&d->ts, d->tone);
+
+
+ return ZT_LIN2MU(linsample);
+}
+
+static void wcusb_do_io(struct wc_usb_pvt *p, struct urb *out, struct urb *in)
+{
+ /* This function performs glues together the USB side
+ with the zaptel side, always doing things in receive/transmit
+ order */
+
+ int x;
+ short *ochunk = out->transfer_buffer;
+ short *ichunk = in->transfer_buffer;
+
+ /* Perform input preparations */
+ switch (p->sample) {
+ case STREAM_NORMAL:
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ p->chan.readchunk[x] = ZT_LIN2MU(ichunk[x]);
+ }
+
+ break;
+ case STREAM_DTMF:
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ p->chan.readchunk[x] = wc_dtmf(p);
+ }
+ break;
+ }
+
+ /* Work with Zaptel now */
+ zt_receive(&p->span);
+ zt_transmit(&p->span);
+
+ /* Fill in transmission info */
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ ochunk[x] = ZT_MULAW(p->chan.writechunk[x]);
+ }
+
+ /* Transmit the pending outgoing urb */
+ if (usb_submit_urb(out)) {
+ printk("wcusb: 'write' urb failed\n");
+ } else {
+ p->urbcount++;
+ }
+
+ /* Readsubmit read URB */
+ if (usb_submit_urb(in)) {
+ printk("wcusb: 'read' urb failed\n");
+ } else
+ p->urbcount++;
+ /* Clear I/O state */
+ p->iostate = 0;
+}
static void wcusb_read_complete(struct urb *q)
{
struct wc_usb_pvt *p = q->context;
- short *chunk = q->transfer_buffer;
- int x;
+
+ /* Decrement number of outstanding URB's */
+ p->urbcount--;
if (!p->flags & FLAG_RUNNING) {
/* Stop sending URBs since we're not running anymore */
- p->urbcount--;
return;
}
- for (x = 0; x < ZT_CHUNKSIZE; x++) {
- p->chan.readchunk[x] = zt_lin2mu[chunk[x] + 32768];
+
+ /* Prepare for retransmission */
+ q->dev = p->dev;
+
+ if (p->iostate & WC_IO_READ) {
+ static int notify=0;
+ if (!notify)
+ printk("Already ready to read?\n");
+ notify++;
}
- zt_receive(&p->span);
+ /* Note that our read is now complete */
+ p->iostate |= WC_IO_READ;
- q->dev = p->dev;
-
- if (usb_submit_urb(q)) {
- printk("wcusb: Read cycle failed\n");
+ if (IO_READY(p->iostate)) {
+ /* Transmit side is complete, lets go */
+ wcusb_do_io(p, p->pendingurb, q);
+ } else {
+ /* Let the transmission side know we're
+ ready to go again */
+ p->pendingurb = q;
}
- if (p->timer && !--p->timer)
- wcusb_check_interrupt(p);
+ if (p->timer && !--p->timer) {
+ if (p->devclass == WC_KEYPAD) {
+ if(debug) printk("Checking keypad\n");
+ wcusb_check_keypad(p);
+ } else {
+ wcusb_check_interrupt(p);
+ }
+ }
#ifdef PROSLIC_POWERSAVE
- if (p->lowpowertimer && !--p->lowpowertimer) {
- /* Switch back into low power mode */
- p->idletxhookstate = 1;
- if (p->txhook == 2)
- p->newtxhook = p->idletxhookstate;
+ if (p->devclass != WC_KEYPAD) {
+ if (p->lowpowertimer && !--p->lowpowertimer) {
+ /* Switch back into low power mode */
+ p->idletxhookstate = 1;
+ if (p->txhook == 2)
+ p->newtxhook = p->idletxhookstate;
+ }
}
#endif
return;
@@ -749,34 +1050,48 @@ static void wcusb_read_complete(struct urb *q)
static void wcusb_write_complete(struct urb *q)
{
struct wc_usb_pvt *p = q->context;
- short *chunk = q->transfer_buffer;
- int x;
+ /* Decrement counter */
+ p->urbcount--;
if (!p->flags & FLAG_RUNNING) {
/* Stop sending URBs since we're not running anymore */
- p->urbcount--;
return;
}
- zt_transmit(&p->span);
- for (x = 0; x < ZT_CHUNKSIZE; x++) {
- chunk[x] = zt_mulaw[p->chan.writechunk[x]];
+ if (p->iostate & WC_IO_WRITE) {
+ static int notify=0;
+ if (!notify)
+ printk("Already ready to write?\n");
+ notify++;
}
+
+ /* Prepare for retransmission */
+ p->iostate |= WC_IO_WRITE;
q->dev = p->dev;
- if (usb_submit_urb(q)) {
- printk("wcusb: Write cycle failed\n");
+ if (IO_READY(p->iostate)) {
+ /* Receive is already done, lets go */
+ wcusb_do_io(p, q, p->pendingurb);
+ } else {
+ /* Let the receive side know we're
+ ready to go again */
+ p->pendingurb = q;
}
- return;
}
static int StopTransmit(struct wc_usb_pvt *p)
{
p->flags &= ~FLAG_RUNNING;
+
+ if (p->devclass == WC_KEYPAD) {
+ struct wc_keypad_data *d = p->pvt_data;
+ d->control = STATE_STOPPED;
+ }
while(p->urbcount) {
schedule_timeout(1);
}
+ printk("ending transmit\n");
return 0;
}
@@ -868,37 +1183,53 @@ static int InitTransfer(struct wc_usb_pvt *p)
static int wc_usb_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
{
struct wc_usb_pvt *p = chan->pvt;
-#ifdef PROSLIC_POWERSAVE
- if (p->txhook == 4) {
- /* Switching out of ring... Be sure we idle at 2, not 1 at least
- for a bit so we can transmit caller*ID */
- p->idletxhookstate = 2;
- p->lowpowertimer = POWERSAVE_TIME;
- }
-#endif
- p->txhook = -1;
- switch(txsig) {
- case ZT_TXSIG_ONHOOK:
- switch(chan->sig) {
- case ZT_SIG_FXOKS:
- case ZT_SIG_FXOLS:
- p->newtxhook = p->idletxhookstate;
- break;
- case ZT_SIG_FXOGS:
- p->newtxhook = 3;
+ switch (p->devclass) {
+ case WC_PROSLIC:
+#ifdef PROSLIC_POWERSAVE
+ if (p->txhook == 4) {
+ /* Switching out of ring... Be sure we idle at 2, not 1 at least
+ for a bit so we can transmit caller*ID */
+ p->idletxhookstate = 2;
+ p->lowpowertimer = POWERSAVE_TIME;
+ }
+#endif
+
+ p->txhook = -1;
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ switch(chan->sig) {
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ p->newtxhook = p->idletxhookstate;
+ break;
+ case ZT_SIG_FXOGS:
+ p->newtxhook = 3;
+ break;
+ }
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ p->newtxhook = p->idletxhookstate;
+ break;
+ case ZT_TXSIG_START:
+ p->newtxhook = 4;
+ break;
+ case ZT_TXSIG_KEWL:
+ p->newtxhook = 0;
+ break;
+ }
+ case WC_KEYPAD:
+ switch (txsig) {
+ case ZT_TXSIG_ONHOOK:
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ break;
+ case ZT_TXSIG_START:
+ break;
+ case ZT_TXSIG_KEWL:
+ break;
+ }
break;
- }
- break;
- case ZT_TXSIG_OFFHOOK:
- p->newtxhook = p->idletxhookstate;
- break;
- case ZT_TXSIG_START:
- p->newtxhook = 4;
- break;
- case ZT_TXSIG_KEWL:
- p->newtxhook = 0;
- break;
}
return 0;
}
@@ -908,6 +1239,14 @@ static int wc_usb_open(struct zt_chan *chan)
struct wc_usb_pvt *p = chan->pvt;
if (p->dead)
return -1;
+ switch (p->devclass) {
+ case WC_KEYPAD:
+ p->hookstate = 0;
+ zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK);
+ break;
+ default:
+ break;
+ }
MOD_INC_USE_COUNT;
p->usecount++;
return 0;
@@ -922,18 +1261,48 @@ static int wc_usb_close(struct zt_chan *chan)
that the program exited, we can release our resources */
zt_unregister(&p->span);
ifaces[p->pos] = NULL;
+ if (p->pvt_data)
+ kfree(p->pvt_data);
kfree(p);
}
MOD_DEC_USE_COUNT;
return 0;
}
+static int init_device_pvt(struct wc_usb_pvt *p)
+{
+ struct usb_device *dev = p->dev;
+
+ if (dev->descriptor.idProduct == 0xb210) {
+ struct wc_keypad_data *d = kmalloc(sizeof(struct wc_keypad_data), GFP_KERNEL);
+ printk("wcusb: Found a WC Keyed Phone\n");
+ p->devclass = WC_KEYPAD;
+ if (!d) {
+ printk("wcusb: kmalloc failed in init_device_pvt\n");
+ return -1;
+ }
+ memset(d, 0, sizeof(struct wc_keypad_data));
+ p->pvt_data = d;
+ d->traffic_count = 0;
+ d->count = 0;
+ d->control = STATE_RUNNING;
+ d->tone = NULL;
+ return 0;
+ } else {
+ p->pvt_data = NULL;
+ p->devclass = WC_PROSLIC;
+ }
+ return 0;
+}
+
static void *wc_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
{
struct usb_config_descriptor *config = dev->actconfig;
struct wc_usb_pvt *p=NULL;
struct wc_usb_desc *d = (struct wc_usb_desc *)id->driver_info;
-
+#if 0
+ char auxcon = 0;
+#endif
int x;
for (x=0;x<WC_MAX_IFACES;x++)
if (!ifaces[x]) break;
@@ -957,6 +1326,7 @@ static void *wc_usb_probe(struct usb_device *dev, unsigned int ifnum, const stru
#endif
p->chan.sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS; /* We're capabable of both FXOKS and FXOLS */
p->chan.chanpos = 1;
+ p->span.deflaw = ZT_LAW_MULAW;
p->span.chans = &p->chan;
p->span.channels = 1;
p->span.hooksig = wc_usb_hooksig;
@@ -976,14 +1346,18 @@ static void *wc_usb_probe(struct usb_device *dev, unsigned int ifnum, const stru
p->idletxhookstate = 2;
#endif
ifaces[x] = p;
+ p->sample = STREAM_NORMAL;
-
+ if (init_device_pvt(p)) {
+ printk(KERN_ERR "wcusb: init_device_pvt failed\n");
+ goto fail;
+ }
if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) {
printk(KERN_ERR "wcusb: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
goto fail;
}
- if (InitHardware(dev)) {
+ if (InitHardware(p)) {
printk(KERN_ERR "wcusb: Hardware initialization failed\n");
goto fail;
}
@@ -995,25 +1369,32 @@ static void *wc_usb_probe(struct usb_device *dev, unsigned int ifnum, const stru
if (p->hardwareflags & FLAG_FLIP_RELAYS) {
flip_relays(p, 1);
}
-#if 1
+
if (zt_register(&p->span, 0)) {
printk("Unable to register span %s\n", p->span.name);
goto fail;
}
-#endif
if (InitTransfer(p)) {
printk(KERN_ERR "wcusb: Unable to begin data flow\n");
goto fail;
}
printk("wcusb: Found a %s\n", d->name);
+#if 0
+ wcinp(p->dev, 0x13, &auxcon);
+ printk("Register 0x13 is set to %x\n",auxcon);
+#endif
return p;
fail:
if (x < WC_MAX_IFACES)
ifaces[x] = NULL;
- if (p)
+ if (p) {
+ if (p->pvt_data) {
+ kfree(p->pvt_data);
+ }
kfree(p);
+ }
return NULL;
}
@@ -1026,6 +1407,8 @@ static void wc_usb_disconnect(struct usb_device *dev, void *ptr)
if (!p->usecount) {
zt_unregister(&p->span);
ifaces[p->pos] = NULL;
+ if (p->pvt_data)
+ kfree(p->pvt_data);
kfree(ptr);
} else
p->dead = 1;