Index: s2/linux/drivers/media/dvb/cinergyT2/cinergyT2.c =================================================================== --- s2.orig/linux/drivers/media/dvb/cinergyT2/cinergyT2.c 2008-09-14 12:31:34.000000000 -0400 +++ s2/linux/drivers/media/dvb/cinergyT2/cinergyT2.c 2008-09-14 12:40:47.000000000 -0400 @@ -36,6 +36,7 @@ #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_net.h" +#include "dvb_frontend.h" #ifdef CONFIG_DVB_CINERGYT2_TUNING #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT) @@ -103,29 +104,17 @@ uint8_t prev_lock_bits; } __attribute__((packed)); -static struct dvb_frontend_info cinergyt2_fe_info = { - .name = DRIVER_NAME, - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS -}; - struct cinergyt2 { struct dvb_demux demux; struct usb_device *udev; struct mutex sem; struct mutex wq_sem; struct dvb_adapter adapter; - struct dvb_device *fedev; struct dmxdev dmxdev; struct dvb_net dvbnet; + struct dvb_frontend *frontend; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; int streaming; int sleeping; @@ -501,266 +490,208 @@ return tps; } -static int cinergyt2_open (struct inode *inode, struct file *file) +static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) +{ + if (cinergyt2->frontend != NULL) { + dvb_net_release(&cinergyt2->dvbnet); + cinergyt2->demux.dmx.remove_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_mem); + cinergyt2->demux.dmx.remove_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_hw); + dvb_dmxdev_release(&cinergyt2->dmxdev); + dvb_dmx_release(&cinergyt2->demux); + dvb_unregister_frontend(cinergyt2->frontend); + dvb_frontend_detach(cinergyt2->frontend); + dvb_unregister_adapter(&cinergyt2->adapter); + } + + cinergyt2_free_stream_urbs(cinergyt2); + kfree(cinergyt2); +} + +static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait) { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - int err = -EAGAIN; + unsigned int mask = 0; if (cinergyt2->disconnect_pending) - goto out; - err = mutex_lock_interruptible(&cinergyt2->wq_sem); - if (err) - goto out; - - err = mutex_lock_interruptible(&cinergyt2->sem); - if (err) - goto out_unlock1; - - if ((err = dvb_generic_open(inode, file))) - goto out_unlock2; + return -EAGAIN; + if (mutex_lock_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - cinergyt2_sleep(cinergyt2, 0); - schedule_delayed_work(&cinergyt2->query_work, HZ/2); - } + poll_wait(file, &cinergyt2->poll_wq, wait); - atomic_inc(&cinergyt2->inuse); + if (cinergyt2->pending_fe_events != 0) + mask |= (POLLIN | POLLRDNORM | POLLPRI); -out_unlock2: mutex_unlock(&cinergyt2->sem); -out_unlock1: - mutex_unlock(&cinergyt2->wq_sem); -out: - return err; + + return mask; } -static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) +static int cinergyt2_read_status(struct dvb_frontend* fe, fe_status_t* status) { - dvb_net_release(&cinergyt2->dvbnet); - dvb_dmxdev_release(&cinergyt2->dmxdev); - dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_device(cinergyt2->fedev); - dvb_unregister_adapter(&cinergyt2->adapter); + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; + struct dvbt_get_status_msg *s = &cinergyt2->status; - cinergyt2_free_stream_urbs(cinergyt2); - kfree(cinergyt2); + if (0xffff - le16_to_cpu(s->gain) > 30) + *status |= FE_HAS_SIGNAL; + if (s->lock_bits & (1 << 6)) + *status |= FE_HAS_LOCK; + if (s->lock_bits & (1 << 5)) + *status |= FE_HAS_SYNC; + if (s->lock_bits & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (s->lock_bits & (1 << 1)) + *status |= FE_HAS_VITERBI; + + return 0; } -static int cinergyt2_release (struct inode *inode, struct file *file) +static int cinergyt2_read_ber(struct dvb_frontend* fe, u32* ber) { - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; + struct dvbt_get_status_msg *s = &cinergyt2->status; - mutex_lock(&cinergyt2->wq_sem); + *ber = s->viterbi_error_rate; - if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) { - cancel_rearming_delayed_work(&cinergyt2->query_work); + return 0; +} - mutex_lock(&cinergyt2->sem); - cinergyt2_sleep(cinergyt2, 1); - mutex_unlock(&cinergyt2->sem); - } +static int cinergyt2_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; + struct dvbt_get_status_msg *s = &cinergyt2->status; - mutex_unlock(&cinergyt2->wq_sem); + *signal_strength = 0xffff - le16_to_cpu(s->gain); - if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) { - warn("delayed unregister in release"); - cinergyt2_unregister(cinergyt2); - } + return 0; +} + +static int cinergyt2_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; + struct dvbt_get_status_msg *s = &cinergyt2->status; - return dvb_generic_release(inode, file); + *snr = (s->snr << 8) | s->snr; + + return 0; } -static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait) +static int cinergyt2_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - unsigned int mask = 0; + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; - if (cinergyt2->disconnect_pending) - return -EAGAIN; if (mutex_lock_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; - poll_wait(file, &cinergyt2->poll_wq, wait); + *ucblocks = cinergyt2->uncorrected_block_count; - if (cinergyt2->pending_fe_events != 0) - mask |= (POLLIN | POLLRDNORM | POLLPRI); + cinergyt2->uncorrected_block_count = 0; mutex_unlock(&cinergyt2->sem); - return mask; + /* UNC are already converted to host byte order... */ + + return 0; } +static int cinergyt2_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} -static int cinergyt2_ioctl (struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) +static int cinergyt2_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - struct dvbt_get_status_msg *stat = &cinergyt2->status; - fe_status_t status = 0; + /* Taken from the previous IOCTL handler */ - switch (cmd) { - case FE_GET_INFO: - return copy_to_user((void __user*) arg, &cinergyt2_fe_info, - sizeof(struct dvb_frontend_info)); - - case FE_READ_STATUS: - if (0xffff - le16_to_cpu(stat->gain) > 30) - status |= FE_HAS_SIGNAL; - if (stat->lock_bits & (1 << 6)) - status |= FE_HAS_LOCK; - if (stat->lock_bits & (1 << 5)) - status |= FE_HAS_SYNC; - if (stat->lock_bits & (1 << 4)) - status |= FE_HAS_CARRIER; - if (stat->lock_bits & (1 << 1)) - status |= FE_HAS_VITERBI; - - return copy_to_user((void __user*) arg, &status, sizeof(status)); - - case FE_READ_BER: - return put_user(le32_to_cpu(stat->viterbi_error_rate), - (__u32 __user *) arg); - - case FE_READ_SIGNAL_STRENGTH: - return put_user(0xffff - le16_to_cpu(stat->gain), - (__u16 __user *) arg); - - case FE_READ_SNR: - return put_user((stat->snr << 8) | stat->snr, - (__u16 __user *) arg); - - case FE_READ_UNCORRECTED_BLOCKS: - { - uint32_t unc_count; - - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - unc_count = cinergyt2->uncorrected_block_count; - cinergyt2->uncorrected_block_count = 0; - mutex_unlock(&cinergyt2->sem); - - /* UNC are already converted to host byte order... */ - return put_user(unc_count,(__u32 __user *) arg); - } - case FE_SET_FRONTEND: - { - struct dvbt_set_parameters_msg *param = &cinergyt2->param; - struct dvb_frontend_parameters p; - int err; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - return -EPERM; - - if (copy_from_user(&p, (void __user*) arg, sizeof(p))) - return -EFAULT; - - if (cinergyt2->disconnect_pending) - return -EAGAIN; - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - - param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - param->tps = cpu_to_le16(compute_tps(&p)); - param->freq = cpu_to_le32(p.frequency / 1000); - param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + /** + * trivial to implement (see struct dvbt_get_status_msg). + * equivalent to FE_READ ioctls, but needs + * TPS -> linux-dvb parameter set conversion. Feel free + * to implement this and send us a patch if you need this + * functionality. + */ - stat->lock_bits = 0; - cinergyt2->pending_fe_events++; - wake_up_interruptible(&cinergyt2->poll_wq); + return 0; +} - err = cinergyt2_command(cinergyt2, - (char *) param, sizeof(*param), - NULL, 0); - - mutex_unlock(&cinergyt2->sem); - - return (err < 0) ? err : 0; - } - - case FE_GET_FRONTEND: - /** - * trivial to implement (see struct dvbt_get_status_msg). - * equivalent to FE_READ ioctls, but needs - * TPS -> linux-dvb parameter set conversion. Feel free - * to implement this and send us a patch if you need this - * functionality. - */ - break; - - case FE_GET_EVENT: - { - /** - * for now we only fill the status field. the parameters - * are trivial to fill as soon FE_GET_FRONTEND is done. - */ - struct dvb_frontend_event __user *e = (void __user *) arg; - if (cinergyt2->pending_fe_events == 0) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - wait_event_interruptible(cinergyt2->poll_wq, - cinergyt2->pending_fe_events > 0); - } - cinergyt2->pending_fe_events = 0; - return cinergyt2_ioctl(inode, file, FE_READ_STATUS, - (unsigned long) &e->status); - } +static int cinergyt2_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; + struct dvbt_get_status_msg *s = &cinergyt2->status; + struct dvbt_set_parameters_msg *param = &cinergyt2->param; + int err; - default: - ; - } + if (cinergyt2->disconnect_pending) + return -EAGAIN; + if (mutex_lock_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param->tps = cpu_to_le16(compute_tps(p)); + param->freq = cpu_to_le32(p->frequency / 1000); + param->bandwidth = 8 - p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; - return -EINVAL; + s->lock_bits = 0; + cinergyt2->pending_fe_events++; + wake_up_interruptible(&cinergyt2->poll_wq); + + err = cinergyt2_command(cinergyt2, + (char *) param, sizeof(*param), + NULL, 0); + + mutex_unlock(&cinergyt2->sem); + + return (err < 0) ? err : 0; } -static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma) +static int cinergyt2_fe_init(struct dvb_frontend* fe) { - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - int ret = 0; + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; + int err = -EAGAIN; - lock_kernel(); + if (cinergyt2->disconnect_pending) + goto out; + err = mutex_lock_interruptible(&cinergyt2->wq_sem); + if (err) + goto out; - if (vma->vm_flags & (VM_WRITE | VM_EXEC)) { - ret = -EPERM; - goto bailout; - } + err = mutex_lock_interruptible(&cinergyt2->sem); + if (err) + goto out_unlock1; - if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) { - ret = -EINVAL; - goto bailout; - } + cinergyt2_sleep(cinergyt2, 0); + schedule_delayed_work(&cinergyt2->query_work, HZ/2); - vma->vm_flags |= (VM_IO | VM_DONTCOPY); - vma->vm_file = file; + atomic_inc(&cinergyt2->inuse); - ret = remap_pfn_range(vma, vma->vm_start, - virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot) ? -EAGAIN : 0; -bailout: - unlock_kernel(); - return ret; + mutex_unlock(&cinergyt2->sem); +out_unlock1: + mutex_unlock(&cinergyt2->wq_sem); +out: + return err; } -static struct file_operations cinergyt2_fops = { - .owner = THIS_MODULE, - .ioctl = cinergyt2_ioctl, - .poll = cinergyt2_poll, - .open = cinergyt2_open, - .release = cinergyt2_release, - .mmap = cinergyt2_mmap -}; +static void cinergyt2_release(struct dvb_frontend* fe) +{ + struct cinergyt2 *cinergyt2 = fe->demodulator_priv; -static struct dvb_device cinergyt2_fe_template = { - .users = ~0, - .writers = 1, - .readers = (~0)-1, - .fops = &cinergyt2_fops -}; + mutex_lock(&cinergyt2->wq_sem); + + cancel_rearming_delayed_work(&cinergyt2->query_work); + + mutex_lock(&cinergyt2->sem); + cinergyt2_sleep(cinergyt2, 1); + mutex_unlock(&cinergyt2->sem); + + mutex_unlock(&cinergyt2->wq_sem); + + if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) { + warn("delayed unregister in release"); + cinergyt2_unregister(cinergyt2); + } +} #ifdef ENABLE_RC @@ -956,6 +887,8 @@ mutex_unlock(&cinergyt2->sem); } +static struct dvb_frontend_ops cinergyt2_fe_ops; + static int cinergyt2_probe (struct usb_interface *intf, const struct usb_device_id *id) { @@ -995,6 +928,15 @@ return err; } + /* register frontend */ + cinergyt2->adapter.priv = cinergyt2; + err = dvb_register_frontend(&cinergyt2->adapter, cinergyt2->frontend); + if (err < 0) { + printk(KERN_ERR "%s: dvb_register_frontend failed " + "(errno = %d)\n", DRIVER_NAME, err); + goto fail_frontend; + } + cinergyt2->demux.priv = cinergyt2; cinergyt2->demux.filternum = 256; cinergyt2->demux.feednum = 256; @@ -1006,7 +948,7 @@ if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) { dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err); - goto bailout; + goto fail_dmx; } cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum; @@ -1015,26 +957,60 @@ if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) { dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err); - goto bailout; + goto fail_dmxdev; } + cinergyt2->fe_hw.source = DMX_FRONTEND_0; + err = cinergyt2->demux.dmx.add_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_hw); + if (err < 0) { + printk(KERN_ERR "%s: add_frontend failed " + "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, err); + goto fail_fe_hw; + } + + cinergyt2->fe_mem.source = DMX_MEMORY_FE; + err = cinergyt2->demux.dmx.add_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_mem); + if (err < 0) { + printk(KERN_ERR "%s: add_frontend failed " + "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, err); + goto fail_fe_mem; + } + + err = cinergyt2->demux.dmx.connect_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_hw); + if (err < 0) { + printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", + DRIVER_NAME, err); + goto fail_fe_conn; + } + + /* Attach the DVB frontend */ + memcpy(&cinergyt2->frontend->ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); + cinergyt2->frontend->demodulator_priv = cinergyt2; + if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx)) + /* ST- Why wouldn't this be mandatory failure? */ dprintk(1, "dvb_net_init() failed!\n"); - dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev, - &cinergyt2_fe_template, cinergyt2, - DVB_DEVICE_FRONTEND); - err = cinergyt2_register_rc(cinergyt2); if (err) - goto bailout; + goto fail_net; return 0; -bailout: +fail_net: dvb_net_release(&cinergyt2->dvbnet); +fail_fe_conn: + cinergyt2->demux.dmx.remove_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_mem); +fail_fe_mem: + cinergyt2->demux.dmx.remove_frontend(&cinergyt2->demux.dmx, &cinergyt2->fe_hw); +fail_fe_hw: dvb_dmxdev_release(&cinergyt2->dmxdev); +fail_dmxdev: dvb_dmx_release(&cinergyt2->demux); +fail_dmx: + dvb_unregister_frontend(cinergyt2->frontend); +fail_frontend: + dvb_frontend_detach(cinergyt2->frontend); dvb_unregister_adapter(&cinergyt2->adapter); cinergyt2_free_stream_urbs(cinergyt2); kfree(cinergyt2); @@ -1119,6 +1095,37 @@ MODULE_DEVICE_TABLE(usb, cinergyt2_table); +static struct dvb_frontend_ops cinergyt2_fe_ops = { + + .info = { + .name = DRIVER_NAME, + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS + }, + + .release = cinergyt2_release, + + .init = cinergyt2_fe_init, + + .set_frontend = cinergyt2_set_frontend, + .get_frontend = cinergyt2_get_frontend, + .get_tune_settings = cinergyt2_get_tune_settings, + + .read_status = cinergyt2_read_status, + .read_ber = cinergyt2_read_ber, + .read_signal_strength = cinergyt2_read_signal_strength, + .read_snr = cinergyt2_read_snr, + .read_ucblocks = cinergyt2_read_ucblocks, +}; + static struct usb_driver cinergyt2_driver = { .name = "cinergyT2", .probe = cinergyt2_probe,