Path: blob/master/drivers/media/video/au0828/au0828-dvb.c
17907 views
/*1* Driver for the Auvitek USB bridge2*3* Copyright (c) 2008 Steven Toth <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13*14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.19*/2021#include <linux/module.h>22#include <linux/slab.h>23#include <linux/init.h>24#include <linux/device.h>25#include <linux/suspend.h>26#include <media/v4l2-common.h>2728#include "au0828.h"29#include "au8522.h"30#include "xc5000.h"31#include "mxl5007t.h"32#include "tda18271.h"3334DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);3536#define _AU0828_BULKPIPE 0x8337#define _BULKPIPESIZE 0xe5223839static u8 hauppauge_hvr950q_led_states[] = {400x00, /* off */410x02, /* yellow */420x04, /* green */43};4445static struct au8522_led_config hauppauge_hvr950q_led_cfg = {46.gpio_output = 0x00e0,47.gpio_output_enable = 0x6006,48.gpio_output_disable = 0x0660,4950.gpio_leds = 0x00e2,51.led_states = hauppauge_hvr950q_led_states,52.num_led_states = sizeof(hauppauge_hvr950q_led_states),5354.vsb8_strong = 20 /* dB */ * 10,55.qam64_strong = 25 /* dB */ * 10,56.qam256_strong = 32 /* dB */ * 10,57};5859static struct au8522_config hauppauge_hvr950q_config = {60.demod_address = 0x8e >> 1,61.status_mode = AU8522_DEMODLOCKING,62.qam_if = AU8522_IF_6MHZ,63.vsb_if = AU8522_IF_6MHZ,64.led_cfg = &hauppauge_hvr950q_led_cfg,65};6667static struct au8522_config fusionhdtv7usb_config = {68.demod_address = 0x8e >> 1,69.status_mode = AU8522_DEMODLOCKING,70.qam_if = AU8522_IF_6MHZ,71.vsb_if = AU8522_IF_6MHZ,72};7374static struct au8522_config hauppauge_woodbury_config = {75.demod_address = 0x8e >> 1,76.status_mode = AU8522_DEMODLOCKING,77.qam_if = AU8522_IF_4MHZ,78.vsb_if = AU8522_IF_3_25MHZ,79};8081static struct xc5000_config hauppauge_hvr950q_tunerconfig = {82.i2c_address = 0x61,83.if_khz = 6000,84};8586static struct mxl5007t_config mxl5007t_hvr950q_config = {87.xtal_freq_hz = MxL_XTAL_24_MHZ,88.if_freq_hz = MxL_IF_6_MHZ,89};9091static struct tda18271_config hauppauge_woodbury_tunerconfig = {92.gate = TDA18271_GATE_DIGITAL,93};9495/*-------------------------------------------------------------------*/96static void urb_completion(struct urb *purb)97{98struct au0828_dev *dev = purb->context;99int ptype = usb_pipetype(purb->pipe);100101dprintk(2, "%s()\n", __func__);102103if (!dev)104return;105106if (dev->urb_streaming == 0)107return;108109if (ptype != PIPE_BULK) {110printk(KERN_ERR "%s() Unsupported URB type %d\n",111__func__, ptype);112return;113}114115/* Feed the transport payload into the kernel demux */116dvb_dmx_swfilter_packets(&dev->dvb.demux,117purb->transfer_buffer, purb->actual_length / 188);118119/* Clean the buffer before we requeue */120memset(purb->transfer_buffer, 0, URB_BUFSIZE);121122/* Requeue URB */123usb_submit_urb(purb, GFP_ATOMIC);124}125126static int stop_urb_transfer(struct au0828_dev *dev)127{128int i;129130dprintk(2, "%s()\n", __func__);131132for (i = 0; i < URB_COUNT; i++) {133usb_kill_urb(dev->urbs[i]);134kfree(dev->urbs[i]->transfer_buffer);135usb_free_urb(dev->urbs[i]);136}137138dev->urb_streaming = 0;139140return 0;141}142143static int start_urb_transfer(struct au0828_dev *dev)144{145struct urb *purb;146int i, ret = -ENOMEM;147148dprintk(2, "%s()\n", __func__);149150if (dev->urb_streaming) {151dprintk(2, "%s: bulk xfer already running!\n", __func__);152return 0;153}154155for (i = 0; i < URB_COUNT; i++) {156157dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);158if (!dev->urbs[i])159goto err;160161purb = dev->urbs[i];162163purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);164if (!purb->transfer_buffer) {165usb_free_urb(purb);166dev->urbs[i] = NULL;167goto err;168}169170purb->status = -EINPROGRESS;171usb_fill_bulk_urb(purb,172dev->usbdev,173usb_rcvbulkpipe(dev->usbdev,174_AU0828_BULKPIPE),175purb->transfer_buffer,176URB_BUFSIZE,177urb_completion,178dev);179180}181182for (i = 0; i < URB_COUNT; i++) {183ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);184if (ret != 0) {185stop_urb_transfer(dev);186printk(KERN_ERR "%s: failed urb submission, "187"err = %d\n", __func__, ret);188return ret;189}190}191192dev->urb_streaming = 1;193ret = 0;194195err:196return ret;197}198199static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)200{201struct dvb_demux *demux = feed->demux;202struct au0828_dev *dev = (struct au0828_dev *) demux->priv;203struct au0828_dvb *dvb = &dev->dvb;204int ret = 0;205206dprintk(1, "%s()\n", __func__);207208if (!demux->dmx.frontend)209return -EINVAL;210211if (dvb) {212mutex_lock(&dvb->lock);213if (dvb->feeding++ == 0) {214/* Start transport */215au0828_write(dev, 0x608, 0x90);216au0828_write(dev, 0x609, 0x72);217au0828_write(dev, 0x60a, 0x71);218au0828_write(dev, 0x60b, 0x01);219ret = start_urb_transfer(dev);220}221mutex_unlock(&dvb->lock);222}223224return ret;225}226227static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)228{229struct dvb_demux *demux = feed->demux;230struct au0828_dev *dev = (struct au0828_dev *) demux->priv;231struct au0828_dvb *dvb = &dev->dvb;232int ret = 0;233234dprintk(1, "%s()\n", __func__);235236if (dvb) {237mutex_lock(&dvb->lock);238if (--dvb->feeding == 0) {239/* Stop transport */240au0828_write(dev, 0x608, 0x00);241au0828_write(dev, 0x609, 0x00);242au0828_write(dev, 0x60a, 0x00);243au0828_write(dev, 0x60b, 0x00);244ret = stop_urb_transfer(dev);245}246mutex_unlock(&dvb->lock);247}248249return ret;250}251252static int dvb_register(struct au0828_dev *dev)253{254struct au0828_dvb *dvb = &dev->dvb;255int result;256257dprintk(1, "%s()\n", __func__);258259/* register adapter */260result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,261&dev->usbdev->dev, adapter_nr);262if (result < 0) {263printk(KERN_ERR "%s: dvb_register_adapter failed "264"(errno = %d)\n", DRIVER_NAME, result);265goto fail_adapter;266}267dvb->adapter.priv = dev;268269/* register frontend */270result = dvb_register_frontend(&dvb->adapter, dvb->frontend);271if (result < 0) {272printk(KERN_ERR "%s: dvb_register_frontend failed "273"(errno = %d)\n", DRIVER_NAME, result);274goto fail_frontend;275}276277/* register demux stuff */278dvb->demux.dmx.capabilities =279DMX_TS_FILTERING | DMX_SECTION_FILTERING |280DMX_MEMORY_BASED_FILTERING;281dvb->demux.priv = dev;282dvb->demux.filternum = 256;283dvb->demux.feednum = 256;284dvb->demux.start_feed = au0828_dvb_start_feed;285dvb->demux.stop_feed = au0828_dvb_stop_feed;286result = dvb_dmx_init(&dvb->demux);287if (result < 0) {288printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",289DRIVER_NAME, result);290goto fail_dmx;291}292293dvb->dmxdev.filternum = 256;294dvb->dmxdev.demux = &dvb->demux.dmx;295dvb->dmxdev.capabilities = 0;296result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);297if (result < 0) {298printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",299DRIVER_NAME, result);300goto fail_dmxdev;301}302303dvb->fe_hw.source = DMX_FRONTEND_0;304result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);305if (result < 0) {306printk(KERN_ERR "%s: add_frontend failed "307"(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);308goto fail_fe_hw;309}310311dvb->fe_mem.source = DMX_MEMORY_FE;312result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);313if (result < 0) {314printk(KERN_ERR "%s: add_frontend failed "315"(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);316goto fail_fe_mem;317}318319result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);320if (result < 0) {321printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",322DRIVER_NAME, result);323goto fail_fe_conn;324}325326/* register network adapter */327dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);328return 0;329330fail_fe_conn:331dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);332fail_fe_mem:333dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);334fail_fe_hw:335dvb_dmxdev_release(&dvb->dmxdev);336fail_dmxdev:337dvb_dmx_release(&dvb->demux);338fail_dmx:339dvb_unregister_frontend(dvb->frontend);340fail_frontend:341dvb_frontend_detach(dvb->frontend);342dvb_unregister_adapter(&dvb->adapter);343fail_adapter:344return result;345}346347void au0828_dvb_unregister(struct au0828_dev *dev)348{349struct au0828_dvb *dvb = &dev->dvb;350351dprintk(1, "%s()\n", __func__);352353if (dvb->frontend == NULL)354return;355356dvb_net_release(&dvb->net);357dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);358dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);359dvb_dmxdev_release(&dvb->dmxdev);360dvb_dmx_release(&dvb->demux);361dvb_unregister_frontend(dvb->frontend);362dvb_frontend_detach(dvb->frontend);363dvb_unregister_adapter(&dvb->adapter);364}365366/* All the DVB attach calls go here, this function get's modified367* for each new card. No other function in this file needs368* to change.369*/370int au0828_dvb_register(struct au0828_dev *dev)371{372struct au0828_dvb *dvb = &dev->dvb;373int ret;374375dprintk(1, "%s()\n", __func__);376377/* init frontend */378switch (dev->boardnr) {379case AU0828_BOARD_HAUPPAUGE_HVR850:380case AU0828_BOARD_HAUPPAUGE_HVR950Q:381dvb->frontend = dvb_attach(au8522_attach,382&hauppauge_hvr950q_config,383&dev->i2c_adap);384if (dvb->frontend != NULL)385dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap,386&hauppauge_hvr950q_tunerconfig);387break;388case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:389dvb->frontend = dvb_attach(au8522_attach,390&hauppauge_hvr950q_config,391&dev->i2c_adap);392if (dvb->frontend != NULL)393dvb_attach(mxl5007t_attach, dvb->frontend,394&dev->i2c_adap, 0x60,395&mxl5007t_hvr950q_config);396break;397case AU0828_BOARD_HAUPPAUGE_WOODBURY:398dvb->frontend = dvb_attach(au8522_attach,399&hauppauge_woodbury_config,400&dev->i2c_adap);401if (dvb->frontend != NULL)402dvb_attach(tda18271_attach, dvb->frontend,4030x60, &dev->i2c_adap,404&hauppauge_woodbury_tunerconfig);405break;406case AU0828_BOARD_DVICO_FUSIONHDTV7:407dvb->frontend = dvb_attach(au8522_attach,408&fusionhdtv7usb_config,409&dev->i2c_adap);410if (dvb->frontend != NULL) {411dvb_attach(xc5000_attach, dvb->frontend,412&dev->i2c_adap,413&hauppauge_hvr950q_tunerconfig);414}415break;416default:417printk(KERN_WARNING "The frontend of your DVB/ATSC card "418"isn't supported yet\n");419break;420}421if (NULL == dvb->frontend) {422printk(KERN_ERR "%s() Frontend initialization failed\n",423__func__);424return -1;425}426/* define general-purpose callback pointer */427dvb->frontend->callback = au0828_tuner_callback;428429/* register everything */430ret = dvb_register(dev);431if (ret < 0) {432if (dvb->frontend->ops.release)433dvb->frontend->ops.release(dvb->frontend);434return ret;435}436437return 0;438}439440441