diff options
author | Michel Ludwig <michel.ludwig@gmail.com> | 2007-08-21 16:37:22 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:39:37 -0400 |
commit | 3169c9b26fffa180bc3bc81dc247df2f4824ee7d (patch) | |
tree | c9792c64ae210fa879a42517431761b301599238 | |
parent | a4cf976c77ce0865ceaa0f08cc1667538894936c (diff) |
V4L/DVB (12788): tm6000: Add initial DVB-T support
Signed-off-by: Michel Ludwig <michel.ludwig@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/staging/tm6000/Makefile | 5 | ||||
-rw-r--r-- | drivers/staging/tm6000/hack.c | 251 | ||||
-rw-r--r-- | drivers/staging/tm6000/hack.h | 45 | ||||
-rw-r--r-- | drivers/staging/tm6000/tm6000-cards.c | 19 | ||||
-rw-r--r-- | drivers/staging/tm6000/tm6000-core.c | 29 | ||||
-rw-r--r-- | drivers/staging/tm6000/tm6000-dvb.c | 303 | ||||
-rw-r--r-- | drivers/staging/tm6000/tm6000.h | 28 |
7 files changed, 677 insertions, 3 deletions
diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile index 1efc583c10a4..1fefe057d4e8 100644 --- a/drivers/staging/tm6000/Makefile +++ b/drivers/staging/tm6000/Makefile | |||
@@ -1,7 +1,10 @@ | |||
1 | tm6000-objs := tm6000-cards.o \ | 1 | tm6000-objs := tm6000-cards.o \ |
2 | tm6000-core.o \ | 2 | tm6000-core.o \ |
3 | tm6000-i2c.o \ | 3 | tm6000-i2c.o \ |
4 | tm6000-video.o | 4 | tm6000-video.o \ |
5 | tm6000-dvb.o \ | ||
6 | hack.o \ | ||
7 | |||
5 | 8 | ||
6 | obj-$(CONFIG_VIDEO_TM6000) += tm6000.o | 9 | obj-$(CONFIG_VIDEO_TM6000) += tm6000.o |
7 | 10 | ||
diff --git a/drivers/staging/tm6000/hack.c b/drivers/staging/tm6000/hack.c new file mode 100644 index 000000000000..87f3f498e8eb --- /dev/null +++ b/drivers/staging/tm6000/hack.c | |||
@@ -0,0 +1,251 @@ | |||
1 | |||
2 | |||
3 | |||
4 | |||
5 | |||
6 | |||
7 | /* | ||
8 | hack.h - hackish code that needs to be improved (or removed) at a | ||
9 | later point | ||
10 | |||
11 | Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> | ||
12 | |||
13 | This program is free software; you can redistribute it and/or modify | ||
14 | it under the terms of the GNU General Public License as published by | ||
15 | the Free Software Foundation version 2 | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include "hack.h" | ||
28 | |||
29 | #include "tm6000.h" | ||
30 | |||
31 | #include <linux/usb.h> | ||
32 | |||
33 | static inline int tm6000_snd_control_msg(struct tm6000_core *dev, __u8 request, __u16 value, __u16 index, void *data, __u16 size) | ||
34 | { | ||
35 | return tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, request, value, index, data, size); | ||
36 | } | ||
37 | |||
38 | static int pseudo_zl10353_pll(struct tm6000_core *tm6000_dev, struct dvb_frontend_parameters *p) | ||
39 | { | ||
40 | int ret; | ||
41 | u8 *data = kzalloc(50*sizeof(u8), GFP_KERNEL); | ||
42 | |||
43 | printk(KERN_ALERT "should set frequency %u\n", p->frequency); | ||
44 | printk(KERN_ALERT "and bandwith %u\n", p->u.ofdm.bandwidth); | ||
45 | |||
46 | if(tm6000_dev->dvb->frontend->ops.tuner_ops.set_params) { | ||
47 | tm6000_dev->dvb->frontend->ops.tuner_ops.set_params(tm6000_dev->dvb->frontend, p); | ||
48 | } | ||
49 | else { | ||
50 | printk(KERN_ALERT "pseudo zl10353: couldn't set tuner parameters\n"); | ||
51 | } | ||
52 | |||
53 | // init ZL10353 | ||
54 | data[0] = 0x0b; | ||
55 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x501e, 0x00, data, 0x1); | ||
56 | msleep(15); | ||
57 | data[0] = 0x80; | ||
58 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x551e, 0x00, data, 0x1); | ||
59 | msleep(100); | ||
60 | data[0] = 0x01; | ||
61 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0xea1e, 0x00, data, 0x1); | ||
62 | msleep(100); | ||
63 | data[0] = 0x00; | ||
64 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0xea1e, 0x00, data, 0x1); | ||
65 | msleep(15); | ||
66 | data[0] = 0x1c; | ||
67 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x561e, 0x00, data, 0x1); | ||
68 | msleep(15); | ||
69 | data[0] = 0x40; | ||
70 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5e1e, 0x00, data, 0x1); | ||
71 | msleep(15); | ||
72 | data[0] = 0x36; | ||
73 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1); | ||
74 | msleep(15); | ||
75 | data[0] = 0x67; | ||
76 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1); | ||
77 | msleep(15); | ||
78 | data[0] = 0xe5; | ||
79 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1); | ||
80 | msleep(15); | ||
81 | data[0] = 0x19; | ||
82 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1); | ||
83 | msleep(15); | ||
84 | data[0] = 0xe9; | ||
85 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1); | ||
86 | msleep(15); | ||
87 | data[0] = 0x44; | ||
88 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1); | ||
89 | msleep(15); | ||
90 | data[0] = 0x46; | ||
91 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1); | ||
92 | msleep(15); | ||
93 | data[0] = 0x15; | ||
94 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1); | ||
95 | msleep(15); | ||
96 | data[0] = 0x0f; | ||
97 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1); | ||
98 | msleep(15); | ||
99 | data[0] = 0x75; | ||
100 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1); | ||
101 | msleep(15); | ||
102 | data[0] = 0x01; | ||
103 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1); | ||
104 | msleep(15); | ||
105 | data[0] = 0x00; | ||
106 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1); | ||
107 | msleep(15); | ||
108 | |||
109 | msleep(50); | ||
110 | |||
111 | switch(p->u.ofdm.bandwidth) { | ||
112 | case BANDWIDTH_8_MHZ: | ||
113 | data[0] = 0x00; | ||
114 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1); | ||
115 | msleep(15); | ||
116 | data[0] = 0x36; | ||
117 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1); | ||
118 | msleep(15); | ||
119 | data[0] = 0x67; | ||
120 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1); | ||
121 | msleep(15); | ||
122 | data[0] = 0xe5; | ||
123 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1); | ||
124 | msleep(15); | ||
125 | data[0] = 0x19; | ||
126 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1); | ||
127 | msleep(15); | ||
128 | data[0] = 0xe9; | ||
129 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1); | ||
130 | msleep(15); | ||
131 | data[0] = 0x44; | ||
132 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1); | ||
133 | msleep(15); | ||
134 | data[0] = 0x46; | ||
135 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1); | ||
136 | msleep(15); | ||
137 | data[0] = 0x15; | ||
138 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1); | ||
139 | msleep(15); | ||
140 | data[0] = 0x0f; | ||
141 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1); | ||
142 | msleep(15); | ||
143 | data[0] = 0x75; | ||
144 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1); | ||
145 | msleep(15); | ||
146 | data[0] = 0x01; | ||
147 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1); | ||
148 | msleep(15); | ||
149 | break; | ||
150 | |||
151 | default: | ||
152 | printk(KERN_ALERT "tm6000: bandwidth not supported\n"); | ||
153 | case BANDWIDTH_7_MHZ: | ||
154 | data[0] = 0x00; | ||
155 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1); | ||
156 | msleep(15); | ||
157 | data[0] = 0x35; | ||
158 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1); | ||
159 | msleep(15); | ||
160 | data[0] = 0x5a; | ||
161 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1); | ||
162 | msleep(15); | ||
163 | data[0] = 0xe9; | ||
164 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1); | ||
165 | msleep(15); | ||
166 | data[0] = 0x19; | ||
167 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1); | ||
168 | msleep(15); | ||
169 | data[0] = 0xe9; | ||
170 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1); | ||
171 | msleep(15); | ||
172 | data[0] = 0x44; | ||
173 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1); | ||
174 | msleep(15); | ||
175 | data[0] = 0x46; | ||
176 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1); | ||
177 | msleep(15); | ||
178 | data[0] = 0x15; | ||
179 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1); | ||
180 | msleep(15); | ||
181 | data[0] = 0x0f; | ||
182 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1); | ||
183 | msleep(15); | ||
184 | data[0] = 0x86; | ||
185 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1); | ||
186 | msleep(15); | ||
187 | data[0] = 0x01; | ||
188 | ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1); | ||
189 | msleep(15); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | kfree(data); | ||
194 | |||
195 | return 0; | ||
196 | }; | ||
197 | |||
198 | |||
199 | |||
200 | int pseudo_zl10353_set_frontend(struct dvb_frontend *fe, | ||
201 | struct dvb_frontend_parameters *p) | ||
202 | { | ||
203 | struct tm6000_core *tm6000_dev = fe->dvb->priv; | ||
204 | u32 status; | ||
205 | |||
206 | if(p != NULL) { | ||
207 | // mutex_lock(&tm6000_dev->mutex); | ||
208 | pseudo_zl10353_pll(tm6000_dev, p); | ||
209 | // mutex_unlock(&tm6000_dev->mutex); | ||
210 | } | ||
211 | |||
212 | if(tm6000_dev->dvb->frontend->ops.read_status) { | ||
213 | tm6000_dev->dvb->frontend->ops.read_status(tm6000_dev->dvb->frontend, &status); | ||
214 | printk(KERN_ALERT "demodulator status: FE_HAS_CARRIER %i \n", (status & FE_HAS_CARRIER)); | ||
215 | printk(KERN_ALERT "demodulator status: FE_HAS_VITERBI %i \n", (status & FE_HAS_VITERBI)); | ||
216 | printk(KERN_ALERT "demodulator status: FE_HAS_LOCK %i \n", (status & FE_HAS_LOCK)); | ||
217 | printk(KERN_ALERT "demodulator status: FE_HAS_SYNC %i \n", (status & FE_HAS_SYNC)); | ||
218 | printk(KERN_ALERT "demodulator status: FE_HAS_SIGNAL %i \n", (status & FE_HAS_SIGNAL)); | ||
219 | } | ||
220 | else { | ||
221 | printk(KERN_ALERT "pseudo zl10353: couldn't read demodulator status\n"); | ||
222 | } | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | int pseudo_zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
227 | { | ||
228 | |||
229 | *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK | FE_HAS_SIGNAL; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | struct dvb_frontend* pseudo_zl10353_attach(struct tm6000_core *dev, | ||
235 | const struct zl10353_config *config, | ||
236 | struct i2c_adapter *i2c) | ||
237 | { | ||
238 | struct tm6000_dvb *dvb = dev->dvb; | ||
239 | |||
240 | dvb->frontend = zl10353_attach(config, i2c); | ||
241 | if(!dvb->frontend) { | ||
242 | return NULL; | ||
243 | } | ||
244 | |||
245 | /* override some functions with our implementations */ | ||
246 | dvb->frontend->ops.set_frontend = pseudo_zl10353_set_frontend; | ||
247 | dvb->frontend->ops.read_status = pseudo_zl10353_read_status; | ||
248 | dvb->frontend->frontend_priv = dev; | ||
249 | |||
250 | return dvb->frontend; | ||
251 | } | ||
diff --git a/drivers/staging/tm6000/hack.h b/drivers/staging/tm6000/hack.h new file mode 100644 index 000000000000..96f1b61df682 --- /dev/null +++ b/drivers/staging/tm6000/hack.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | hack.h - hackish code that needs to be improved (or removed) at a | ||
3 | later point | ||
4 | |||
5 | Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation version 2 | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef HACK_H | ||
22 | #define HACK_H | ||
23 | |||
24 | #include <linux/i2c.h> | ||
25 | |||
26 | #include "zl10353.h" | ||
27 | #include "dvb_frontend.h" | ||
28 | |||
29 | struct tm6000_core; | ||
30 | |||
31 | int pseudo_zl103530_init(struct dvb_frontend *fe); | ||
32 | |||
33 | int pseudo_zl10353_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); | ||
34 | |||
35 | int pseudo_zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status); | ||
36 | |||
37 | int pseudo_zl10353_read_signal_strength(struct dvb_frontend* fe, u16* strength); | ||
38 | |||
39 | int pseudo_zl10353_read_snr(struct dvb_frontend *fe, u16 *snr); | ||
40 | |||
41 | struct dvb_frontend* pseudo_zl10353_attach(struct tm6000_core *dev, | ||
42 | const struct zl10353_config *config, | ||
43 | struct i2c_adapter *i2c); | ||
44 | |||
45 | #endif | ||
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index e8f88ea5ded9..b41b3a46779f 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c | |||
@@ -185,7 +185,19 @@ static int tm6000_init_dev(struct tm6000_core *dev) | |||
185 | dev->freq = f.frequency; | 185 | dev->freq = f.frequency; |
186 | 186 | ||
187 | tm6000_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); | 187 | tm6000_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); |
188 | 188 | if(dev->caps.has_dvb) { | |
189 | dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL); | ||
190 | if(!dev->dvb) { | ||
191 | rc = -ENOMEM; | ||
192 | goto err; | ||
193 | } | ||
194 | rc = tm6000_dvb_register(dev); | ||
195 | if(rc < 0) { | ||
196 | kfree(dev->dvb); | ||
197 | dev->dvb = NULL; | ||
198 | goto err; | ||
199 | } | ||
200 | } | ||
189 | err: | 201 | err: |
190 | mutex_unlock(&dev->lock); | 202 | mutex_unlock(&dev->lock); |
191 | return rc; | 203 | return rc; |
@@ -389,6 +401,11 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) | |||
389 | 401 | ||
390 | mutex_lock(&dev->lock); | 402 | mutex_lock(&dev->lock); |
391 | 403 | ||
404 | if(dev->dvb) { | ||
405 | tm6000_dvb_unregister(dev); | ||
406 | kfree(dev->dvb); | ||
407 | } | ||
408 | |||
392 | tm6000_v4l2_unregister(dev); | 409 | tm6000_v4l2_unregister(dev); |
393 | 410 | ||
394 | tm6000_i2c_unregister(dev); | 411 | tm6000_i2c_unregister(dev); |
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 6becde2eace6..5e9325582bde 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c | |||
@@ -3,6 +3,9 @@ | |||
3 | 3 | ||
4 | Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> | 4 | Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> |
5 | 5 | ||
6 | Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> | ||
7 | - DVB-T support | ||
8 | |||
6 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation version 2 | 11 | the Free Software Foundation version 2 |
@@ -207,6 +210,32 @@ int tm6000_init_analog_mode (struct tm6000_core *dev) | |||
207 | return 0; | 210 | return 0; |
208 | } | 211 | } |
209 | 212 | ||
213 | int tm6000_init_digital_mode (struct tm6000_core *dev) | ||
214 | { | ||
215 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08); | ||
216 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00); | ||
217 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01); | ||
218 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08); | ||
219 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c); | ||
220 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff); | ||
221 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8); | ||
222 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40); | ||
223 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0); | ||
224 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09); | ||
225 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37); | ||
226 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8); | ||
227 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0); | ||
228 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60); | ||
229 | msleep(50); | ||
230 | |||
231 | tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); | ||
232 | tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01); | ||
233 | tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); | ||
234 | |||
235 | msleep(100); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
210 | 239 | ||
211 | /* The meaning of those initializations are unknown */ | 240 | /* The meaning of those initializations are unknown */ |
212 | u8 init_tab[][2] = { | 241 | u8 init_tab[][2] = { |
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c new file mode 100644 index 000000000000..d2ec6ca766cb --- /dev/null +++ b/drivers/staging/tm6000/tm6000-dvb.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | tm6000-dvb.c - dvb-t support for TM5600/TM6000 USB video capture devices | ||
3 | |||
4 | Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation version 2 | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/usb.h> | ||
21 | |||
22 | #include "tm6000.h" | ||
23 | #include "tm6000-regs.h" | ||
24 | |||
25 | #include "hack.h" | ||
26 | |||
27 | #include "zl10353.h" | ||
28 | |||
29 | #include <media/tuner.h> | ||
30 | |||
31 | static void tm6000_urb_received(struct urb *urb) | ||
32 | { | ||
33 | int ret; | ||
34 | struct tm6000_core* dev = urb->context; | ||
35 | |||
36 | if(urb->status != 0){ | ||
37 | printk(KERN_ERR "tm6000: status != 0\n"); | ||
38 | } | ||
39 | else if(urb->actual_length>0){ | ||
40 | dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, | ||
41 | urb->actual_length); | ||
42 | } | ||
43 | |||
44 | if(dev->dvb->streams > 0) { | ||
45 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
46 | if(ret < 0) { | ||
47 | printk(KERN_ERR "tm6000: error %s\n", __FUNCTION__); | ||
48 | kfree(urb->transfer_buffer); | ||
49 | usb_free_urb(urb); | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | int tm6000_start_stream(struct tm6000_core *dev) | ||
55 | { | ||
56 | int ret; | ||
57 | unsigned int pipe, maxPaketSize; | ||
58 | struct tm6000_dvb *dvb = dev->dvb; | ||
59 | |||
60 | printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__); | ||
61 | |||
62 | tm6000_init_digital_mode(dev); | ||
63 | |||
64 | // ret = usb_set_interface(dev->udev, 0, 1); | ||
65 | // if (ret<0) | ||
66 | // return ret; | ||
67 | |||
68 | /* | ||
69 | ret = tm6000_set_led_status(tm6000_dev, 0x1); | ||
70 | if(ret < 0) { | ||
71 | return -1; | ||
72 | } | ||
73 | */ | ||
74 | |||
75 | dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
76 | if(dvb->bulk_urb == NULL) { | ||
77 | printk(KERN_ERR "tm6000: couldn't allocate urb\n"); | ||
78 | return -ENOMEM; | ||
79 | } | ||
80 | |||
81 | maxPaketSize = dev->bulk_in->desc.wMaxPacketSize; | ||
82 | |||
83 | dvb->bulk_urb->transfer_buffer = kzalloc(maxPaketSize, GFP_KERNEL); | ||
84 | if(dvb->bulk_urb->transfer_buffer == NULL) { | ||
85 | usb_free_urb(dvb->bulk_urb); | ||
86 | printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n"); | ||
87 | return -ENOMEM; | ||
88 | } | ||
89 | |||
90 | pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress | ||
91 | & USB_ENDPOINT_NUMBER_MASK); | ||
92 | |||
93 | usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe, | ||
94 | dvb->bulk_urb->transfer_buffer, | ||
95 | maxPaketSize, | ||
96 | tm6000_urb_received, dev); | ||
97 | ret = usb_clear_halt(dev->udev, pipe); | ||
98 | if(ret < 0) { | ||
99 | printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__); | ||
100 | // return ret; | ||
101 | } | ||
102 | else { | ||
103 | printk(KERN_ERR "tm6000: pipe resetted\n"); | ||
104 | } | ||
105 | |||
106 | // mutex_lock(&tm6000_driver.open_close_mutex); | ||
107 | ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL); | ||
108 | |||
109 | |||
110 | // mutex_unlock(&tm6000_driver.open_close_mutex); | ||
111 | if (ret) { | ||
112 | printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret); | ||
113 | |||
114 | kfree(dvb->bulk_urb->transfer_buffer); | ||
115 | usb_free_urb(dvb->bulk_urb); | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | void tm6000_stop_stream(struct tm6000_core *dev) | ||
123 | { | ||
124 | struct tm6000_dvb *dvb = dev->dvb; | ||
125 | |||
126 | // tm6000_set_led_status(tm6000_dev, 0x0); | ||
127 | |||
128 | if(dvb->bulk_urb) { | ||
129 | usb_kill_urb(dvb->bulk_urb); | ||
130 | kfree(dvb->bulk_urb->transfer_buffer); | ||
131 | usb_free_urb(dvb->bulk_urb); | ||
132 | dvb->bulk_urb = NULL; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | int tm6000_start_feed(struct dvb_demux_feed *feed) | ||
137 | { | ||
138 | struct dvb_demux *demux = feed->demux; | ||
139 | struct tm6000_core *dev = demux->priv; | ||
140 | struct tm6000_dvb *dvb = dev->dvb; | ||
141 | printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__); | ||
142 | |||
143 | mutex_lock(&dvb->mutex); | ||
144 | if(dvb->streams == 0) { | ||
145 | dvb->streams = 1; | ||
146 | // mutex_init(&tm6000_dev->streaming_mutex); | ||
147 | tm6000_start_stream(dev); | ||
148 | } | ||
149 | else { | ||
150 | ++(dvb->streams); | ||
151 | } | ||
152 | mutex_unlock(&dvb->mutex); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | int tm6000_stop_feed(struct dvb_demux_feed *feed) { | ||
158 | struct dvb_demux *demux = feed->demux; | ||
159 | struct tm6000_core *dev = demux->priv; | ||
160 | struct tm6000_dvb *dvb = dev->dvb; | ||
161 | |||
162 | printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__); | ||
163 | |||
164 | mutex_lock(&dvb->mutex); | ||
165 | --dvb->streams; | ||
166 | |||
167 | if(0 == dvb->streams) { | ||
168 | tm6000_stop_stream(dev); | ||
169 | // mutex_destroy(&tm6000_dev->streaming_mutex); | ||
170 | } | ||
171 | mutex_unlock(&dvb->mutex); | ||
172 | // mutex_destroy(&tm6000_dev->streaming_mutex); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | int tm6000_dvb_attach_frontend(struct tm6000_core *dev) | ||
178 | { | ||
179 | struct tm6000_dvb *dvb = dev->dvb; | ||
180 | |||
181 | if(dev->caps.has_zl10353) { | ||
182 | struct zl10353_config config = | ||
183 | {.demod_address = dev->demod_addr >> 1, | ||
184 | .no_tuner = 1, | ||
185 | // .input_frequency = 0x19e9, | ||
186 | // .r56_agc_targets = 0x1c, | ||
187 | }; | ||
188 | |||
189 | dvb->frontend = pseudo_zl10353_attach(dev, &config, | ||
190 | &dev->i2c_adap); | ||
191 | } | ||
192 | else { | ||
193 | printk(KERN_ERR "tm6000: no frontend defined for the device!\n"); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | if(dvb->frontend) { | ||
198 | return 0; | ||
199 | } | ||
200 | else { | ||
201 | return -1; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | int tm6000_dvb_register(struct tm6000_core *dev) | ||
206 | { | ||
207 | int ret = -1; | ||
208 | struct tm6000_dvb *dvb = dev->dvb; | ||
209 | |||
210 | mutex_init(&dvb->mutex); | ||
211 | |||
212 | dvb->streams = 0; | ||
213 | |||
214 | /* attach the frontend */ | ||
215 | ret = tm6000_dvb_attach_frontend(dev); | ||
216 | if(ret < 0) { | ||
217 | printk(KERN_ERR "tm6000: couldn't attach the frontend!\n"); | ||
218 | // goto err; | ||
219 | } | ||
220 | |||
221 | ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", | ||
222 | THIS_MODULE, &dev->udev->dev); | ||
223 | dvb->adapter.priv = dev; | ||
224 | |||
225 | if(dvb->frontend) { | ||
226 | ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); | ||
227 | if(ret < 0) { | ||
228 | printk("tm6000: couldn't register frontend\n"); | ||
229 | goto adapter_err; | ||
230 | } | ||
231 | |||
232 | // attach the tuner like this for now | ||
233 | tm6000_i2c_call_clients(dev, VIDIOC_INT_DVB_TUNER_ATTACH, dvb->frontend); | ||
234 | |||
235 | printk("tm6000: XC2028/3028 asked to be attached to frontend!\n"); | ||
236 | } | ||
237 | else { | ||
238 | printk("tm6000: no frontend found\n"); | ||
239 | } | ||
240 | |||
241 | dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | ||
242 | | DMX_MEMORY_BASED_FILTERING; | ||
243 | dvb->demux.priv = dev; | ||
244 | dvb->demux.filternum = 256; | ||
245 | dvb->demux.feednum = 256; | ||
246 | dvb->demux.start_feed = tm6000_start_feed; | ||
247 | dvb->demux.stop_feed = tm6000_stop_feed; | ||
248 | dvb->demux.write_to_decoder = NULL; | ||
249 | ret = dvb_dmx_init(&dvb->demux); | ||
250 | if(ret < 0) { | ||
251 | printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret); | ||
252 | goto frontend_err; | ||
253 | } | ||
254 | |||
255 | dvb->dmxdev.filternum = dev->dvb->demux.filternum; | ||
256 | dvb->dmxdev.demux = &dev->dvb->demux.dmx; | ||
257 | dvb->dmxdev.capabilities = 0; | ||
258 | |||
259 | ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); | ||
260 | if(ret < 0) { | ||
261 | printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); | ||
262 | goto dvb_dmx_err; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | |||
267 | dvb_dmx_err: | ||
268 | dvb_dmx_release(&dvb->demux); | ||
269 | frontend_err: | ||
270 | if(dvb->frontend) { | ||
271 | dvb_unregister_frontend(dvb->frontend); | ||
272 | } | ||
273 | adapter_err: | ||
274 | dvb_unregister_adapter(&dvb->adapter); | ||
275 | err: | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | void tm6000_dvb_unregister(struct tm6000_core *dev) | ||
280 | { | ||
281 | struct tm6000_dvb *dvb = dev->dvb; | ||
282 | |||
283 | if(dvb->bulk_urb != NULL) { | ||
284 | struct urb *bulk_urb = dvb->bulk_urb; | ||
285 | |||
286 | kfree(bulk_urb->transfer_buffer); | ||
287 | bulk_urb->transfer_buffer = NULL; | ||
288 | usb_unlink_urb(bulk_urb); | ||
289 | usb_free_urb(bulk_urb); | ||
290 | } | ||
291 | |||
292 | // mutex_lock(&tm6000_driver.open_close_mutex); | ||
293 | if(dvb->frontend) { | ||
294 | dvb_unregister_frontend(dvb->frontend); | ||
295 | } | ||
296 | |||
297 | dvb_dmxdev_release(&dvb->dmxdev); | ||
298 | dvb_dmx_release(&dvb->demux); | ||
299 | dvb_unregister_adapter(&dvb->adapter); | ||
300 | mutex_destroy(&dvb->mutex); | ||
301 | // mutex_unlock(&tm6000_driver.open_close_mutex); | ||
302 | |||
303 | } | ||
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 27bee627d3b7..3556fa4c403d 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h | |||
@@ -3,6 +3,9 @@ | |||
3 | 3 | ||
4 | Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> | 4 | Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> |
5 | 5 | ||
6 | Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> | ||
7 | - DVB-T support | ||
8 | |||
6 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation version 2 | 11 | the Free Software Foundation version 2 |
@@ -27,6 +30,11 @@ | |||
27 | #include <linux/i2c.h> | 30 | #include <linux/i2c.h> |
28 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
29 | 32 | ||
33 | #include <linux/dvb/frontend.h> | ||
34 | #include "dvb_demux.h" | ||
35 | #include "dvb_frontend.h" | ||
36 | #include "dmxdev.h" | ||
37 | |||
30 | #define TM6000_VERSION KERNEL_VERSION(0, 0, 1) | 38 | #define TM6000_VERSION KERNEL_VERSION(0, 0, 1) |
31 | 39 | ||
32 | /* Inputs */ | 40 | /* Inputs */ |
@@ -97,12 +105,23 @@ struct tm6000_capabilities { | |||
97 | unsigned int has_eeprom:1; | 105 | unsigned int has_eeprom:1; |
98 | }; | 106 | }; |
99 | 107 | ||
108 | struct tm6000_dvb { | ||
109 | struct dvb_adapter adapter; | ||
110 | struct dvb_demux demux; | ||
111 | struct dvb_frontend *frontend; | ||
112 | struct dmxdev dmxdev; | ||
113 | unsigned int streams; | ||
114 | struct urb *bulk_urb; | ||
115 | struct mutex mutex; | ||
116 | }; | ||
117 | |||
100 | struct tm6000_core { | 118 | struct tm6000_core { |
101 | /* generic device properties */ | 119 | /* generic device properties */ |
102 | char name[30]; /* name (including minor) of the device */ | 120 | char name[30]; /* name (including minor) of the device */ |
103 | int model; /* index in the device_data struct */ | 121 | int model; /* index in the device_data struct */ |
104 | int devno; /* marks the number of this device */ | 122 | int devno; /* marks the number of this device */ |
105 | v4l2_std_id norm; /* Current norm */ | 123 | |
124 | v4l2_std_id norm; /* Current norm */ | ||
106 | 125 | ||
107 | enum tm6000_core_state state; | 126 | enum tm6000_core_state state; |
108 | 127 | ||
@@ -136,6 +155,9 @@ struct tm6000_core { | |||
136 | 155 | ||
137 | enum tm6000_mode mode; | 156 | enum tm6000_mode mode; |
138 | 157 | ||
158 | /* DVB-T support */ | ||
159 | struct tm6000_dvb *dvb; | ||
160 | |||
139 | /* locks */ | 161 | /* locks */ |
140 | struct mutex lock; | 162 | struct mutex lock; |
141 | 163 | ||
@@ -181,9 +203,13 @@ int tm6000_init (struct tm6000_core *dev); | |||
181 | int tm6000_init_after_firmware (struct tm6000_core *dev); | 203 | int tm6000_init_after_firmware (struct tm6000_core *dev); |
182 | 204 | ||
183 | int tm6000_init_analog_mode (struct tm6000_core *dev); | 205 | int tm6000_init_analog_mode (struct tm6000_core *dev); |
206 | int tm6000_init_digital_mode (struct tm6000_core *dev); | ||
184 | int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm); | 207 | int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm); |
185 | int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate); | 208 | int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate); |
186 | 209 | ||
210 | int tm6000_dvb_register(struct tm6000_core *dev); | ||
211 | void tm6000_dvb_unregister(struct tm6000_core *dev); | ||
212 | |||
187 | int tm6000_v4l2_register(struct tm6000_core *dev); | 213 | int tm6000_v4l2_register(struct tm6000_core *dev); |
188 | int tm6000_v4l2_unregister(struct tm6000_core *dev); | 214 | int tm6000_v4l2_unregister(struct tm6000_core *dev); |
189 | int tm6000_v4l2_exit(void); | 215 | int tm6000_v4l2_exit(void); |