📄 wcusb.c
字号:
schedule_timeout(1); } printk("ending transmit\n"); return 0;}static int flip_relays(struct wc_usb_pvt *p, int onoff){ unsigned char ctl; unsigned char data; /* Read data */ if (wcinp(p->dev, 0x12, &data)) return -1; /* Read control */ if (wcinp(p->dev, 0x13, &ctl)) return -1; /* Setup values properly -- Pins AUX3 & AUX4 control the relays */ ctl |= 0x18; if (onoff) { data |= 0x18; } else { data &= 0xe7; } if (wcoutp(p->dev, 0x12, data)) return -1; if (wcoutp(p->dev, 0x13, ctl)) return -1; return 0;}static int prepare_transfer_urbs(struct wc_usb_pvt *p){ int x; /* Endpoint 6 is the wave-in device */ unsigned int readpipe = usb_rcvisocpipe(p->dev, 0x06); /* Endpoint 7 is the wave-out device */ unsigned int writepipe = usb_sndisocpipe(p->dev, 0x07); for (x = 0; x < 2; x++) { p->dataread[x].urb.dev = p->dev; p->dataread[x].urb.pipe = readpipe;#ifdef LINUX26 p->dataread[x].urb.transfer_flags = URB_ISO_ASAP;#else p->dataread[x].urb.transfer_flags = USB_ISO_ASAP;#endif p->dataread[x].urb.number_of_packets = 1; p->dataread[x].urb.context = p; p->dataread[x].urb.complete = wcusb_read_complete; p->dataread[x].urb.iso_frame_desc[0].length = ZT_CHUNKSIZE * 2; p->dataread[x].urb.iso_frame_desc[0].offset = 0; p->dataread[x].urb.transfer_buffer = p->readchunk + ZT_CHUNKSIZE * x; p->dataread[x].urb.transfer_buffer_length = ZT_CHUNKSIZE * 2; p->datawrite[x].urb.dev = p->dev; p->datawrite[x].urb.pipe = writepipe;#ifdef LINUX26 p->datawrite[x].urb.transfer_flags = URB_ISO_ASAP;#else p->datawrite[x].urb.transfer_flags = USB_ISO_ASAP;#endif p->datawrite[x].urb.number_of_packets = 1; p->datawrite[x].urb.context = p; p->datawrite[x].urb.complete = wcusb_write_complete; p->datawrite[x].urb.iso_frame_desc[0].length = ZT_CHUNKSIZE * 2; p->datawrite[x].urb.iso_frame_desc[0].offset = 0; p->datawrite[x].urb.transfer_buffer = p->writechunk + ZT_CHUNKSIZE * x; p->datawrite[x].urb.transfer_buffer_length = ZT_CHUNKSIZE * 2; } return 0;}static int begin_transfer(struct wc_usb_pvt *p){ int x; p->urbcount = 4; p->flags |= FLAG_RUNNING; for (x = 0; x < 2; x++) {#ifdef LINUX26 if (usb_submit_urb(&p->dataread[x].urb, GFP_KERNEL)) #else if (usb_submit_urb(&p->dataread[x].urb)) #endif { printk(KERN_ERR "wcusb: Read submit failed\n"); return -1; }#ifdef LINUX26 if (usb_submit_urb(&p->datawrite[x].urb, GFP_KERNEL))#else if (usb_submit_urb(&p->datawrite[x].urb)) #endif { printk(KERN_ERR "wcusb: Write submit failed\n"); return -1; } } /* Start checking for interrupts */ wcusb_check_interrupt(p); return 0;}static int wc_usb_hooksig(struct zt_chan *chan, zt_txsig_t txsig){ struct wc_usb_pvt *p = chan->pvt; 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; } return 0;}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; }#ifndef LINUX26 MOD_INC_USE_COUNT;#endif p->usecount++; return 0;}static int wc_usb_close(struct zt_chan *chan){ struct wc_usb_pvt *p = chan->pvt; p->usecount--; if (!p->usecount && p->dead) { /* Someone unplugged us while we were running, so now 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); }#ifndef LINUX26 MOD_DEC_USE_COUNT;#endif return 0;}static struct wc_usb_pvt *wc_detect_device(struct usb_device *dev, struct wc_usb_pvt *orig){ struct wc_usb_pvt *p; p = orig; if (!p) { p = kmalloc(sizeof(struct wc_usb_pvt), GFP_KERNEL); if (!p) { printk("wcusb: kmalloc failed\n"); return NULL; } memset(p, 0, sizeof(struct wc_usb_pvt)); } p->dev = dev;#ifdef PROSLIC_POWERSAVE /* By default we can't send on hook */ p->idletxhookstate = 1;#else /* By default we can always send on hook */ p->idletxhookstate = 2; #endif printk("wcusb: wc_detect_device\n"); 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 NULL; } memset(d, 0, sizeof(struct wc_keypad_data)); p->pvt_data = d; d->count = 0; d->running = 1; d->tone = NULL; return p; } else { p->pvt_data = NULL; p->devclass = WC_PROSLIC; } printk("Second exit\n"); return p;}static int wc_set_zaptel(struct wc_usb_pvt *p){ int x; for (x = 0; x < WC_MAX_IFACES; x++) if (!ifaces[x]) break; if (x >= WC_MAX_IFACES) { printk("wcusb: Too many interfaces\n"); return -1; } sprintf(p->span.name, "WCUSB/%d", x); sprintf(p->span.desc,"%s %d", p->span.name, x); sprintf(p->chan.name, "WCUSB/%d/%d", x, 0); 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; p->span.open = wc_usb_open; p->span.close = wc_usb_close; ifaces[x] = p; p->pos = x; p->span.flags = ZT_FLAG_RBS; init_waitqueue_head(&p->span.maintq); p->span.pvt = p; p->chan.pvt = p; /* Set the stream to just pass the data from the device uninhibited */ p->sample = STREAM_NORMAL; if (zt_register(&p->span, 0)) { printk("wcusb: Unable to register span %s\n", p->span.name); return -1; } return 0;} #ifdef LINUX26static int wc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)#elsestatic void *wc_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)#endif{ struct wc_usb_pvt *p = NULL; struct wc_usb_desc *d = (struct wc_usb_desc *)id->driver_info;#ifdef LINUX26 struct usb_device *dev = interface_to_usbdev(intf);#endif int x; for (x=0;x<WC_MAX_IFACES;x++) { /* Find first dead or empty space */ p = ifaces[x]; if (!p) { if (debug) printk("Device slot %d is free\n", x); break; } if (p->dead) { if (debug) printk("Device slot %d can be revived\n", x); break; } if (debug) printk("Device slot %d is still in use\n", x); } if (!(p = wc_detect_device(dev, p))) { printk("wcusb: No wcusb devices found\n");#ifdef LINUX26 return -ENODEV;#else return NULL;#endif }#ifndef LINUX26 if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) { printk("wcusb: set_configuration failed (ConfigValue 0x%x)\n", dev->config[0].bConfigurationValue); return NULL; }#endif if (init_hardware(p)) { printk("wcusb: Hardware intialization failed.\n"); goto cleanup; } if (prepare_transfer_urbs(p)) { printk("wcusb: problem preparing the urbs for transfer\n"); goto cleanup; } if (d->flags & FLAG_FLIP_RELAYS) { flip_relays(p, 1); } if (!p->dead && wc_set_zaptel(p)) { printk("wcusb: Error in starting the zaptel stuff\n"); goto cleanup; } if (begin_transfer(p)) { printk("wcusb: Something went wrong when starting the transfer\n"); goto cleanup; } if (p->dead) printk("wcusb: Rekindling a %s (%s)\n", d->name, p->span.name); else printk("wcusb: Found a %s (%s)\n", d->name, p->span.name); /* Reset deadness */ p->dead = 0; /* Clear alarms */ p->span.alarms = 0; zt_alarm_notify(&p->span);#ifdef LINUX26 usb_set_intfdata(intf, p); return 0;#else return p;#endif cleanup: printk("cleanup\n"); if (p) { if (p->pvt_data) { kfree(p->pvt_data); } kfree(p); }#ifdef LINUX26 return -ENODEV;#else return NULL;#endif }#ifdef LINUX26static void wc_usb_disconnect(struct usb_interface *intf)#elsestatic void wc_usb_disconnect(struct usb_device *dev, void *ptr)#endif{ /* Doesn't handle removal if we're in use right */#ifdef LINUX26 struct wc_usb_pvt *p = usb_get_intfdata(intf);#else struct wc_usb_pvt *p = ptr;#endif if (p) { StopTransmit(p); p->dev = NULL; if (!p->usecount) { zt_unregister(&p->span); if (p->pvt_data) kfree(p->pvt_data); ifaces[p->pos] = NULL; kfree(p); } else { /* Generate alarm and note that we're dead */ p->span.alarms = ZT_ALARM_RED; zt_alarm_notify(&p->span); p->dead = 1; } } printk("wcusb: Removed a Wildcard device\n");#ifdef LINUX26 usb_set_intfdata(intf, NULL);#endif return;}static struct usb_device_id wc_dev_ids[] = { /* This needs to be a USB audio device, and it needs to be made by us and have the right device ID */ { 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: 0x831c, /* Product ID / Chip configuration (you can't change this) */ driver_info: (unsigned long)&wcusb, }, { 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: 0x831e, 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 */};static struct usb_driver wc_usb_driver ={#ifdef LINUX26 owner: THIS_MODULE,#else fops: NULL, minor: 0,#endif name: "wcusb", probe: wc_usb_probe, disconnect: wc_usb_disconnect, id_table: wc_dev_ids,};static int __init wc_init (void) { int res; res = usb_register(&wc_usb_driver); if (res) return res; printk("Wildcard USB FXS Interface driver registered\n"); return 0;} static void __exit wc_cleanup(void){ usb_deregister(&wc_usb_driver);}MODULE_AUTHOR("Matthew Fredrickson <creslin@linux-support.net>");MODULE_DESCRIPTION("Wildcard USB FXS Interface driver");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifMODULE_DEVICE_TABLE(usb, wc_dev_ids);module_init(wc_init);module_exit(wc_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -