📄 dvb-ttusb-budget.c
字号:
}static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len){ int maxwork = 1024; while (len) { if (!(maxwork--)) { printk("%s: too much work\n", __FUNCTION__); break; } switch (ttusb->mux_state) { case 0: case 1: case 2: len--; if (*data++ == 0xAA) ++ttusb->mux_state; else { ttusb->mux_state = 0;#if DEBUG > 3 if (ttusb->insync) printk("%02x ", data[-1]);#else if (ttusb->insync) { printk("%s: lost sync.\n", __FUNCTION__); ttusb->insync = 0; }#endif } break; case 3: ttusb->insync = 1; len--; ttusb->mux_npacks = *data++; ++ttusb->mux_state; ttusb->muxpack_ptr = 0; /* maximum bytes, until we know the length */ ttusb->muxpack_len = 2; break; case 4: { int avail; avail = len; if (avail > (ttusb->muxpack_len - ttusb->muxpack_ptr)) avail = ttusb->muxpack_len - ttusb->muxpack_ptr; memcpy(ttusb->muxpack + ttusb->muxpack_ptr, data, avail); ttusb->muxpack_ptr += avail; if (ttusb->muxpack_ptr > 264) BUG(); data += avail; len -= avail; /* determine length */ if (ttusb->muxpack_ptr == 2) { if (ttusb->muxpack[0] & 0x80) { ttusb->muxpack_len = ttusb->muxpack[1] + 2; if (ttusb-> muxpack[0] & 0x20) ttusb-> muxpack_len++; if ((!! (ttusb-> muxpack[0] & 0x20)) ^ !!(ttusb-> muxpack[1] & 1)) ttusb-> muxpack_len++; ttusb->muxpack_len += 4; } else if (ttusb->muxpack[0] == 0x47) ttusb->muxpack_len = 188 + 4; else if (ttusb->muxpack[0] == 0x00) ttusb->muxpack_len = ttusb->muxpack[1] + 2 + 4; else { dprintk ("%s: invalid state: first byte is %x\n", __FUNCTION__, ttusb->muxpack[0]); ttusb->mux_state = 0; } } /** * if length is valid and we reached the end: * goto next muxpack */ if ((ttusb->muxpack_ptr >= 2) && (ttusb->muxpack_ptr == ttusb->muxpack_len)) { ttusb_process_muxpack(ttusb, ttusb-> muxpack, ttusb-> muxpack_ptr); ttusb->muxpack_ptr = 0; /* maximum bytes, until we know the length */ ttusb->muxpack_len = 2; /** * no muxpacks left? * return to search-sync state */ if (!ttusb->mux_npacks--) { ttusb->mux_state = 0; break; } } break; } default: BUG(); break; } }}static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs){ struct ttusb *ttusb = urb->context; if (!ttusb->iso_streaming) return;#if 0 printk("%s: status %d, errcount == %d, length == %i\n", __FUNCTION__, urb->status, urb->error_count, urb->actual_length);#endif if (!urb->status) { int i; for (i = 0; i < urb->number_of_packets; ++i) { struct usb_iso_packet_descriptor *d; u8 *data; int len; numpkt++; if ((jiffies - lastj) >= HZ) {#if DEBUG > 2 printk ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n", numpkt * HZ / (jiffies - lastj), numts, numstuff, numsec, numinvalid, numts + numstuff + numsec + numinvalid);#endif numts = numstuff = numsec = numinvalid = 0; lastj = jiffies; numpkt = 0; } d = &urb->iso_frame_desc[i]; data = urb->transfer_buffer + d->offset; len = d->actual_length; d->actual_length = 0; d->status = 0; ttusb_process_frame(ttusb, data, len); } } usb_submit_urb(urb, GFP_KERNEL);}static void ttusb_free_iso_urbs(struct ttusb *ttusb){ int i; for (i = 0; i < ISO_BUF_COUNT; i++) if (ttusb->iso_urb[i]) usb_free_urb(ttusb->iso_urb[i]); pci_free_consistent(NULL, ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT, ttusb->iso_buffer, ttusb->iso_dma_handle);}static int ttusb_alloc_iso_urbs(struct ttusb *ttusb){ int i; ttusb->iso_buffer = pci_alloc_consistent(NULL, ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT, &ttusb->iso_dma_handle); memset(ttusb->iso_buffer, 0, ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); for (i = 0; i < ISO_BUF_COUNT; i++) { struct urb *urb; if (! (urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) { ttusb_free_iso_urbs(ttusb); return -ENOMEM; } ttusb->iso_urb[i] = urb; } return 0;}static void ttusb_stop_iso_xfer(struct ttusb *ttusb){ int i; for (i = 0; i < ISO_BUF_COUNT; i++) usb_unlink_urb(ttusb->iso_urb[i]); ttusb->iso_streaming = 0;}static int ttusb_start_iso_xfer(struct ttusb *ttusb){ int i, j, err, buffer_offset = 0; if (ttusb->iso_streaming) { printk("%s: iso xfer already running!\n", __FUNCTION__); return 0; } ttusb->cc = -1; ttusb->insync = 0; ttusb->mux_state = 0; for (i = 0; i < ISO_BUF_COUNT; i++) { int frame_offset = 0; struct urb *urb = ttusb->iso_urb[i]; urb->dev = ttusb->dev; urb->context = ttusb; urb->complete = ttusb_iso_irq; urb->pipe = ttusb->isoc_in_pipe; urb->transfer_flags = URB_ISO_ASAP; urb->interval = 1; urb->number_of_packets = FRAMES_PER_ISO_BUF; urb->transfer_buffer_length = ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; urb->transfer_buffer = ttusb->iso_buffer + buffer_offset; buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { urb->iso_frame_desc[j].offset = frame_offset; urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; frame_offset += ISO_FRAME_SIZE; } } for (i = 0; i < ISO_BUF_COUNT; i++) { if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_KERNEL))) { ttusb_stop_iso_xfer(ttusb); printk ("%s: failed urb submission (%i: err = %i)!\n", __FUNCTION__, i, err); return err; } } ttusb->iso_streaming = 1; return 0;}#ifdef TTUSB_HWSECTIONSstatic void ttusb_handle_ts_data(struct ttusb_channel *channel, const u8 * data, int len){ struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0);}static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data, int len){// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;#error TODO: handle ugly stuff// dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0);}#endifstatic struct ttusb_channel *ttusb_channel_allocate(struct ttusb *ttusb){ int i; if (down_interruptible(&ttusb->sem)) return NULL; /* lock! */ for (i = 0; i < TTUSB_MAXCHANNEL; ++i) { if (!ttusb->channel[i].active) { ttusb->channel[i].active = 1; up(&ttusb->sem); return ttusb->channel + i; } } up(&ttusb->sem); return NULL;}static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed){ struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; struct ttusb_channel *channel; dprintk("ttusb_start_feed\n"); switch (dvbdmxfeed->type) { case DMX_TYPE_TS: break; case DMX_TYPE_SEC: break; default: return -EINVAL; } if (dvbdmxfeed->type == DMX_TYPE_TS) { switch (dvbdmxfeed->pes_type) { case DMX_TS_PES_VIDEO: case DMX_TS_PES_AUDIO: case DMX_TS_PES_TELETEXT: case DMX_TS_PES_PCR: case DMX_TS_PES_OTHER: channel = ttusb_channel_allocate(ttusb); break; default: return -EINVAL; } } else { channel = ttusb_channel_allocate(ttusb); } if (!channel) return -EBUSY; dvbdmxfeed->priv = channel; channel->dvbdmxfeed = dvbdmxfeed; channel->pid = dvbdmxfeed->pid;#ifdef TTUSB_HWSECTIONS if (dvbdmxfeed->type == DMX_TYPE_TS) { channel->type = 1; } else if (dvbdmxfeed->type == DMX_TYPE_SEC) { channel->type = 2;#error TODO: allocate filters }#else channel->type = 1;#endif ttusb_set_channel(ttusb, channel->id, channel->type, channel->pid); if (0 == ttusb->running_feed_count++) ttusb_start_iso_xfer(ttusb); return 0;}static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed){ struct ttusb_channel *channel = (struct ttusb_channel *) dvbdmxfeed->priv; struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; ttusb_del_channel(channel->ttusb, channel->id); if (--ttusb->running_feed_count == 0) ttusb_stop_iso_xfer(ttusb); channel->active = 0; return 0;}static int ttusb_setup_interfaces(struct ttusb *ttusb){ usb_set_interface(ttusb->dev, 1, 1); ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1); ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2); return 0;}#if 0static u8 stc_firmware[8192];static int stc_open(struct inode *inode, struct file *file){ struct ttusb *ttusb = file->private_data; int addr; for (addr = 0; addr < 8192; addr += 16) { u8 snd_buf[2] = { addr >> 8, addr & 0xFF }; ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr, 16); } return 0;}static ssize_t stc_read(struct file *file, char *buf, size_t count, loff_t * offset){ int tc = count; if ((tc + *offset) > 8192) tc = 8192 - *offset; if (tc < 0) return 0; if (copy_to_user(buf, stc_firmware + *offset, tc)) return -EFAULT; *offset += tc; return tc;}static int stc_release(struct inode *inode, struct file *file){ return 0;}static struct file_operations stc_fops = { .owner = THIS_MODULE, .read = stc_read, .open = stc_open, .release = stc_release,};#endifstatic int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *udev; struct ttusb *ttusb; int result, channel; dprintk("%s: TTUSB DVB connected\n", __FUNCTION__); udev = interface_to_usbdev(intf); /* Device has already been reset; its configuration was chosen. * If this fault happens, use a hotplug script to choose the * right configuration (write bConfigurationValue in sysfs). */ if (udev->actconfig->desc.bConfigurationValue != 1) { dev_err(&intf->dev, "device config is #%d, need #1\n", udev->actconfig->desc.bConfigurationValue); return -ENODEV; } if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV; if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL))) return -ENOMEM; memset(ttusb, 0, sizeof(struct ttusb)); for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) { ttusb->channel[channel].id = channel; ttusb->channel[channel].ttusb = ttusb; } ttusb->dev = udev; ttusb->c = 0; ttusb->mux_state = 0; sema_init(&ttusb->sem, 0); sema_init(&ttusb->semusb, 1); ttusb_setup_interfaces(ttusb); ttusb_alloc_iso_urbs(ttusb); if (ttusb_init_controller(ttusb)) printk("ttusb_init_controller: error\n"); up(&ttusb->sem); dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE); dvb_register_i2c_bus(ttusb_i2c_xfer, ttusb, ttusb->adapter, 0); dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL, ttusb); memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); ttusb->dvb_demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; ttusb->dvb_demux.priv = NULL;#ifdef TTUSB_HWSECTIONS ttusb->dvb_demux.filternum = TTUSB_MAXFILTER;#else ttusb->dvb_demux.filternum = 32;#endif ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; ttusb->dvb_demux.start_feed = ttusb_start_feed; ttusb->dvb_demux.stop_feed = ttusb_stop_feed; ttusb->dvb_demux.write_to_decoder = NULL; if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); goto err; }//FIXME dmxdev (nur WAS?) ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; ttusb->dmxdev.capabilities = 0; if ((result = dvb_dmxdev_init(&ttusb->dmxdev, ttusb->adapter)) < 0) { printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", result); dvb_dmx_release(&ttusb->dvb_demux); goto err; } if (dvb_net_init (ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { printk("ttusb_dvb: dvb_net_init failed!\n"); } err:#if 0 ttusb->stc_devfs_handle = devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME, DEVFS_FL_DEFAULT, 0, 192, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &stc_fops, ttusb);#endif usb_set_intfdata(intf, (void *) ttusb); return 0;}static void ttusb_disconnect(struct usb_interface *intf){ struct ttusb *ttusb = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); ttusb->disconnecting = 1; ttusb_stop_iso_xfer(ttusb); ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx); dvb_net_release(&ttusb->dvbnet); dvb_dmxdev_release(&ttusb->dmxdev); dvb_dmx_release(&ttusb->dvb_demux); dvb_unregister_i2c_bus(ttusb_i2c_xfer, ttusb->adapter, 0); dvb_unregister_adapter(ttusb->adapter); ttusb_free_iso_urbs(ttusb); kfree(ttusb); dprintk("%s: TTUSB DVB disconnected\n", __FUNCTION__);}static struct usb_device_id ttusb_table[] = { {USB_DEVICE(0xb48, 0x1003)}, {USB_DEVICE(0xb48, 0x1004)}, /* to be confirmed ???? */ {USB_DEVICE(0xb48, 0x1005)}, {}};MODULE_DEVICE_TABLE(usb, ttusb_table);static struct usb_driver ttusb_driver = { .name = "Technotrend/Hauppauge USB-Nova", .probe = ttusb_probe, .disconnect = ttusb_disconnect, .id_table = ttusb_table,};static int __init ttusb_init(void){ int err; if ((err = usb_register(&ttusb_driver)) < 0) { printk("%s: usb_register failed! Error number %d", __FILE__, err); return err; } return 0;}static void __exit ttusb_exit(void){ usb_deregister(&ttusb_driver);}module_init(ttusb_init);module_exit(ttusb_exit);MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug or not");MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");MODULE_DESCRIPTION("TTUSB DVB Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -