?? dvb-ttusb-budget.c
字號:
/* * TTUSB DVB driver * * Copyright (c) 2002 Holger Waechtler <holger@convergence.de> * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. */#include <linux/init.h>#include <linux/slab.h>#include <linux/wait.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/usb.h>#include <linux/delay.h>#include <linux/time.h>#include <linux/errno.h>#include <linux/jiffies.h>#include <asm/semaphore.h>#include "dvb_frontend.h"#include "dmxdev.h"#include "dvb_demux.h"#include "dvb_net.h"#include "ves1820.h"#include "cx22700.h"#include "tda1004x.h"#include "stv0299.h"#include "tda8083.h"#include <linux/dvb/frontend.h>#include <linux/dvb/dmx.h>#include <linux/pci.h>/* TTUSB_HWSECTIONS: the DSP supports filtering in hardware, however, since the "muxstream" is a bit braindead (no matching channel masks or no matching filter mask), we won't support this - yet. it doesn't event support negative filters, so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just parse TS data. USB bandwith will be a problem when having large datastreams, especially for dvb-net, but hey, that's not my problem. TTUSB_DISEQC, TTUSB_TONE: let the STC do the diseqc/tone stuff. this isn't supported at least with my TTUSB, so let it undef'd unless you want to implement another frontend. never tested. DEBUG: define it to > 3 for really hardcore debugging. you probably don't want this unless the device doesn't load at all. > 2 for bandwidth statistics.*/static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0)#define ISO_BUF_COUNT 4#define FRAMES_PER_ISO_BUF 4#define ISO_FRAME_SIZE 912#define TTUSB_MAXCHANNEL 32#ifdef TTUSB_HWSECTIONS#define TTUSB_MAXFILTER 16 /* ??? */#endif#define TTUSB_REV_2_2 0x22#define TTUSB_BUDGET_NAME "ttusb_stc_fw"/** * since we're casting (struct ttusb*) <-> (struct dvb_demux*) around * the dvb_demux field must be the first in struct!! */struct ttusb { struct dvb_demux dvb_demux; struct dmxdev dmxdev; struct dvb_net dvbnet; /* and one for USB access. */ struct semaphore semi2c; struct semaphore semusb; struct dvb_adapter adapter; struct usb_device *dev; struct i2c_adapter i2c_adap; int disconnecting; int iso_streaming; unsigned int bulk_out_pipe; unsigned int bulk_in_pipe; unsigned int isoc_in_pipe; void *iso_buffer; dma_addr_t iso_dma_handle; struct urb *iso_urb[ISO_BUF_COUNT]; int running_feed_count; int last_channel; int last_filter; u8 c; /* transaction counter, wraps around... */ fe_sec_tone_mode_t tone; fe_sec_voltage_t voltage; int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack u8 mux_npacks; u8 muxpack[256 + 8]; int muxpack_ptr, muxpack_len; int insync; int cc; /* MuxCounter - will increment on EVERY MUX PACKET */ /* (including stuffing. yes. really.) */ u8 last_result[32]; int revision;#if 0 devfs_handle_t stc_devfs_handle;#endif struct dvb_frontend* fe;};/* ugly workaround ... don't know why it's neccessary to read *//* all result codes. */#define DEBUG 0static int ttusb_cmd(struct ttusb *ttusb, const u8 * data, int len, int needresult){ int actual_len; int err;#if DEBUG >= 3 int i; printk(">"); for (i = 0; i < len; ++i) printk(" %02x", data[i]); printk("\n");#endif if (down_interruptible(&ttusb->semusb) < 0) return -EAGAIN; err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe, (u8 *) data, len, &actual_len, 1000); if (err != 0) { dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n", __FUNCTION__, err); up(&ttusb->semusb); return err; } if (actual_len != len) { dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__, actual_len, len); up(&ttusb->semusb); return -1; } err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe, ttusb->last_result, 32, &actual_len, 1000); if (err != 0) { printk("%s: failed, receive error %d\n", __FUNCTION__, err); up(&ttusb->semusb); return err; }#if DEBUG >= 3 actual_len = ttusb->last_result[3] + 4; printk("<"); for (i = 0; i < actual_len; ++i) printk(" %02x", ttusb->last_result[i]); printk("\n");#endif if (!needresult) up(&ttusb->semusb); return 0;}static int ttusb_result(struct ttusb *ttusb, u8 * data, int len){ memcpy(data, ttusb->last_result, len); up(&ttusb->semusb); return 0;}static int ttusb_i2c_msg(struct ttusb *ttusb, u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf, u8 rcv_len){ u8 b[0x28]; u8 id = ++ttusb->c; int i, err; if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7) return -EINVAL; b[0] = 0xaa; b[1] = id; b[2] = 0x31; b[3] = snd_len + 3; b[4] = addr << 1; b[5] = snd_len; b[6] = rcv_len; for (i = 0; i < snd_len; i++) b[7 + i] = snd_buf[i]; err = ttusb_cmd(ttusb, b, snd_len + 7, 1); if (err) return -EREMOTEIO; err = ttusb_result(ttusb, b, 0x20); /* check if the i2c transaction was successful */ if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO; if (rcv_len > 0) { if (err || b[0] != 0x55 || b[1] != id) { dprintk ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ", __FUNCTION__, err, id); return -EREMOTEIO; } for (i = 0; i < rcv_len; i++) rcv_buf[i] = b[7 + i]; } return rcv_len;}static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num){ struct ttusb *ttusb = i2c_get_adapdata(adapter); int i = 0; int inc; if (down_interruptible(&ttusb->semi2c) < 0) return -EAGAIN; while (i < num) { u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; int err; if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) { addr = msg[i].addr; snd_buf = msg[i].buf; snd_len = msg[i].len; rcv_buf = msg[i + 1].buf; rcv_len = msg[i + 1].len; inc = 2; } else { addr = msg[i].addr; snd_buf = msg[i].buf; snd_len = msg[i].len; rcv_buf = NULL; rcv_len = 0; inc = 1; } err = ttusb_i2c_msg(ttusb, addr, snd_buf, snd_len, rcv_buf, rcv_len); if (err < rcv_len) { dprintk("%s: i == %i\n", __FUNCTION__, i); break; } i += inc; } up(&ttusb->semi2c); return i;}#include "dvb-ttusb-dspbootcode.h"static int ttusb_boot_dsp(struct ttusb *ttusb){ int i, err; u8 b[40]; /* BootBlock */ b[0] = 0xaa; b[2] = 0x13; b[3] = 28; /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ /* 32 is max packet size, no messages should be splitted. */ for (i = 0; i < sizeof(dsp_bootcode); i += 28) { memcpy(&b[4], &dsp_bootcode[i], 28); b[1] = ++ttusb->c; err = ttusb_cmd(ttusb, b, 32, 0); if (err) goto done; } /* last block ... */ b[1] = ++ttusb->c; b[2] = 0x13; b[3] = 0; err = ttusb_cmd(ttusb, b, 4, 0); if (err) goto done; /* BootEnd */ b[1] = ++ttusb->c; b[2] = 0x14; b[3] = 0; err = ttusb_cmd(ttusb, b, 4, 0); done: if (err) { dprintk("%s: usb_bulk_msg() failed, return value %i!\n", __FUNCTION__, err); } return err;}static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type, int pid){ int err; /* SetChannel */ u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type, (pid >> 8) & 0xff, pid & 0xff }; err = ttusb_cmd(ttusb, b, sizeof(b), 0); return err;}static int ttusb_del_channel(struct ttusb *ttusb, int channel_id){ int err; /* DelChannel */ u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id }; err = ttusb_cmd(ttusb, b, sizeof(b), 0); return err;}#ifdef TTUSB_HWSECTIONSstatic int ttusb_set_filter(struct ttusb *ttusb, int filter_id, int associated_chan, u8 filter[8], u8 mask[8]){ int err; /* SetFilter */ u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan, filter[0], filter[1], filter[2], filter[3], filter[4], filter[5], filter[6], filter[7], filter[8], filter[9], filter[10], filter[11], mask[0], mask[1], mask[2], mask[3], mask[4], mask[5], mask[6], mask[7], mask[8], mask[9], mask[10], mask[11] }; err = ttusb_cmd(ttusb, b, sizeof(b), 0); return err;}static int ttusb_del_filter(struct ttusb *ttusb, int filter_id){ int err; /* DelFilter */ u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id }; err = ttusb_cmd(ttusb, b, sizeof(b), 0); return err;}#endifstatic int ttusb_init_controller(struct ttusb *ttusb){ u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 }; u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 }; u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 }; /* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */ u8 b3[] = { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e }; u8 b4[] = { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e }; u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 }; u8 get_dsp_version[0x20] = { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 }; int err; /* reset board */ if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0))) return err; /* reset board (again?) */ if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0))) return err; ttusb_boot_dsp(ttusb); /* set i2c bit rate */ if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0))) return err; if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1))) return err; err = ttusb_result(ttusb, b4, sizeof(b4)); if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1))) return err; if ((err = ttusb_result(ttusb, get_version, sizeof(get_version)))) return err; dprintk("%s: stc-version: %c%c%c%c%c\n", __FUNCTION__, get_version[4], get_version[5], get_version[6], get_version[7], get_version[8]); if (memcmp(get_version + 4, "V 0.0", 5) && memcmp(get_version + 4, "V 1.1", 5) && memcmp(get_version + 4, "V 2.1", 5) && memcmp(get_version + 4, "V 2.2", 5)) { printk ("%s: unknown STC version %c%c%c%c%c, please report!\n", __FUNCTION__, get_version[4], get_version[5], get_version[6], get_version[7], get_version[8]); } ttusb->revision = ((get_version[6] - '0') << 4) | (get_version[8] - '0'); err = ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1); if (err) return err; err = ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version)); if (err) return err; printk("%s: dsp-version: %c%c%c\n", __FUNCTION__, get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]); return 0;}#ifdef TTUSB_DISEQCstatic int ttusb_send_diseqc(struct dvb_frontend* fe, const struct dvb_diseqc_master_cmd *cmd){ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; int err; b[3] = 4 + 2 + cmd->msg_len; b[4] = 0xFF; /* send diseqc master, not burst */ b[5] = cmd->msg_len; memcpy(b + 5, cmd->msg, cmd->msg_len); /* Diseqc */ if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) { dprintk("%s: usb_bulk_msg() failed, return value %i!\n", __FUNCTION__, err); } return err;}#endifstatic int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage){ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; int ret; u8 data[1]; struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) }; switch(voltage) { case SEC_VOLTAGE_OFF: data[0] = 0x00; break; case SEC_VOLTAGE_13: data[0] = 0x44; break; case SEC_VOLTAGE_18: data[0] = 0x4c; break; default: return -EINVAL; }; ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1); return (ret != 1) ? -EIO : 0;}static int ttusb_update_lnb(struct ttusb *ttusb){ u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1, ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1 }; int err; /* SetLNB */ if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) { dprintk("%s: usb_bulk_msg() failed, return value %i!\n", __FUNCTION__, err); } return err;}static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage){ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; ttusb->voltage = voltage; return ttusb_update_lnb(ttusb);}#ifdef TTUSB_TONEstatic int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone){ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; ttusb->tone = tone; return ttusb_update_lnb(ttusb);}#endif#if 0static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -