From a6aa5b6c4b6795e8d18e7dfbc7f8ee11b770048a Mon Sep 17 00:00:00 2001 From: markster Date: Fri, 28 Dec 2001 17:48:23 +0000 Subject: Version 0.1.4 from FTP git-svn-id: http://svn.digium.com/svn/zaptel/trunk@44 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wcfxsusb.c | 581 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 482 insertions(+), 99 deletions(-) (limited to 'wcfxsusb.c') diff --git a/wcfxsusb.c b/wcfxsusb.c index 8dc66ff..1f2cc89 100755 --- a/wcfxsusb.c +++ b/wcfxsusb.c @@ -39,13 +39,16 @@ #include #include #ifdef STANDALONE_ZAPATA + #include "zaptel.h" #else #include -#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) @@ -128,6 +136,11 @@ struct stinky_urb { iso_packet_descriptor_t isoframe[1]; }; +typedef enum { + STREAM_NORMAL, + STREAM_DTMF, +} stream_t; + typedef enum { STATE_WCREAD_WRITEREG, STATE_WCREAD_READRES, @@ -135,8 +148,49 @@ typedef enum { 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;xchan.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; -- cgit v1.2.3