diff options
Diffstat (limited to 'drivers/media/dvb/firewire/firedtv-dvb.c')
-rw-r--r-- | drivers/media/dvb/firewire/firedtv-dvb.c | 328 |
1 files changed, 208 insertions, 120 deletions
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index 1823058696f2..9d308dd32a5c 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c | |||
@@ -10,75 +10,55 @@ | |||
10 | * the License, or (at your option) any later version. | 10 | * the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/bitops.h> | ||
14 | #include <linux/device.h> | ||
13 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
14 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/mod_devicetable.h> | ||
18 | #include <linux/module.h> | ||
15 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/slab.h> | ||
21 | #include <linux/string.h> | ||
16 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/wait.h> | ||
24 | #include <linux/workqueue.h> | ||
17 | 25 | ||
26 | #include <dmxdev.h> | ||
18 | #include <dvb_demux.h> | 27 | #include <dvb_demux.h> |
19 | #include <dvb_frontend.h> | ||
20 | #include <dvbdev.h> | 28 | #include <dvbdev.h> |
29 | #include <dvb_frontend.h> | ||
21 | 30 | ||
22 | #include "avc.h" | ||
23 | #include "firedtv.h" | 31 | #include "firedtv.h" |
24 | #include "firedtv-ci.h" | ||
25 | |||
26 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
27 | 32 | ||
28 | static struct firedtv_channel *fdtv_channel_allocate(struct firedtv *fdtv) | 33 | static int alloc_channel(struct firedtv *fdtv) |
29 | { | 34 | { |
30 | struct firedtv_channel *c = NULL; | 35 | int i; |
31 | int k; | ||
32 | 36 | ||
33 | if (mutex_lock_interruptible(&fdtv->demux_mutex)) | 37 | for (i = 0; i < 16; i++) |
34 | return NULL; | 38 | if (!__test_and_set_bit(i, &fdtv->channel_active)) |
35 | |||
36 | for (k = 0; k < 16; k++) | ||
37 | if (!fdtv->channel[k].active) { | ||
38 | fdtv->channel[k].active = true; | ||
39 | c = &fdtv->channel[k]; | ||
40 | break; | 39 | break; |
41 | } | 40 | return i; |
42 | |||
43 | mutex_unlock(&fdtv->demux_mutex); | ||
44 | return c; | ||
45 | } | 41 | } |
46 | 42 | ||
47 | static int fdtv_channel_collect(struct firedtv *fdtv, int *pidc, u16 pid[]) | 43 | static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[]) |
48 | { | 44 | { |
49 | int k, l = 0; | 45 | int i, n; |
50 | |||
51 | if (mutex_lock_interruptible(&fdtv->demux_mutex)) | ||
52 | return -EINTR; | ||
53 | |||
54 | for (k = 0; k < 16; k++) | ||
55 | if (fdtv->channel[k].active) | ||
56 | pid[l++] = fdtv->channel[k].pid; | ||
57 | |||
58 | mutex_unlock(&fdtv->demux_mutex); | ||
59 | 46 | ||
60 | *pidc = l; | 47 | for (i = 0, n = 0; i < 16; i++) |
61 | 48 | if (test_bit(i, &fdtv->channel_active)) | |
62 | return 0; | 49 | pid[n++] = fdtv->channel_pid[i]; |
50 | *pidc = n; | ||
63 | } | 51 | } |
64 | 52 | ||
65 | static int fdtv_channel_release(struct firedtv *fdtv, | 53 | static inline void dealloc_channel(struct firedtv *fdtv, int i) |
66 | struct firedtv_channel *channel) | ||
67 | { | 54 | { |
68 | if (mutex_lock_interruptible(&fdtv->demux_mutex)) | 55 | __clear_bit(i, &fdtv->channel_active); |
69 | return -EINTR; | ||
70 | |||
71 | channel->active = false; | ||
72 | |||
73 | mutex_unlock(&fdtv->demux_mutex); | ||
74 | return 0; | ||
75 | } | 56 | } |
76 | 57 | ||
77 | int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) | 58 | int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) |
78 | { | 59 | { |
79 | struct firedtv *fdtv = (struct firedtv*)dvbdmxfeed->demux->priv; | 60 | struct firedtv *fdtv = dvbdmxfeed->demux->priv; |
80 | struct firedtv_channel *channel; | 61 | int pidc, c, ret; |
81 | int pidc,k; | ||
82 | u16 pids[16]; | 62 | u16 pids[16]; |
83 | 63 | ||
84 | switch (dvbdmxfeed->type) { | 64 | switch (dvbdmxfeed->type) { |
@@ -86,11 +66,14 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
86 | case DMX_TYPE_SEC: | 66 | case DMX_TYPE_SEC: |
87 | break; | 67 | break; |
88 | default: | 68 | default: |
89 | printk(KERN_ERR "%s: invalid type %u\n", | 69 | dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n", |
90 | __func__, dvbdmxfeed->type); | 70 | dvbdmxfeed->type); |
91 | return -EINVAL; | 71 | return -EINVAL; |
92 | } | 72 | } |
93 | 73 | ||
74 | if (mutex_lock_interruptible(&fdtv->demux_mutex)) | ||
75 | return -EINTR; | ||
76 | |||
94 | if (dvbdmxfeed->type == DMX_TYPE_TS) { | 77 | if (dvbdmxfeed->type == DMX_TYPE_TS) { |
95 | switch (dvbdmxfeed->pes_type) { | 78 | switch (dvbdmxfeed->pes_type) { |
96 | case DMX_TS_PES_VIDEO: | 79 | case DMX_TS_PES_VIDEO: |
@@ -98,75 +81,64 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
98 | case DMX_TS_PES_TELETEXT: | 81 | case DMX_TS_PES_TELETEXT: |
99 | case DMX_TS_PES_PCR: | 82 | case DMX_TS_PES_PCR: |
100 | case DMX_TS_PES_OTHER: | 83 | case DMX_TS_PES_OTHER: |
101 | //Dirty fix to keep fdtv->channel pid-list up to date | 84 | c = alloc_channel(fdtv); |
102 | for(k=0;k<16;k++){ | ||
103 | if (!fdtv->channel[k].active) | ||
104 | fdtv->channel[k].pid = | ||
105 | dvbdmxfeed->pid; | ||
106 | break; | ||
107 | } | ||
108 | channel = fdtv_channel_allocate(fdtv); | ||
109 | break; | 85 | break; |
110 | default: | 86 | default: |
111 | printk(KERN_ERR "%s: invalid pes type %u\n", | 87 | dev_err(fdtv->device, |
112 | __func__, dvbdmxfeed->pes_type); | 88 | "can't start dmx feed: invalid pes type %u\n", |
113 | return -EINVAL; | 89 | dvbdmxfeed->pes_type); |
90 | ret = -EINVAL; | ||
91 | goto out; | ||
114 | } | 92 | } |
115 | } else { | 93 | } else { |
116 | channel = fdtv_channel_allocate(fdtv); | 94 | c = alloc_channel(fdtv); |
117 | } | 95 | } |
118 | 96 | ||
119 | if (!channel) { | 97 | if (c > 15) { |
120 | printk(KERN_ERR "%s: busy!\n", __func__); | 98 | dev_err(fdtv->device, "can't start dmx feed: busy\n"); |
121 | return -EBUSY; | 99 | ret = -EBUSY; |
100 | goto out; | ||
122 | } | 101 | } |
123 | 102 | ||
124 | dvbdmxfeed->priv = channel; | 103 | dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c; |
125 | channel->pid = dvbdmxfeed->pid; | 104 | fdtv->channel_pid[c] = dvbdmxfeed->pid; |
126 | 105 | collect_channels(fdtv, &pidc, pids); | |
127 | if (fdtv_channel_collect(fdtv, &pidc, pids)) { | ||
128 | fdtv_channel_release(fdtv, channel); | ||
129 | printk(KERN_ERR "%s: could not collect pids!\n", __func__); | ||
130 | return -EINTR; | ||
131 | } | ||
132 | 106 | ||
133 | if (dvbdmxfeed->pid == 8192) { | 107 | if (dvbdmxfeed->pid == 8192) { |
134 | k = avc_tuner_get_ts(fdtv); | 108 | ret = avc_tuner_get_ts(fdtv); |
135 | if (k) { | 109 | if (ret) { |
136 | fdtv_channel_release(fdtv, channel); | 110 | dealloc_channel(fdtv, c); |
137 | printk("%s: AVCTuner_GetTS failed with error %d\n", | 111 | dev_err(fdtv->device, "can't get TS\n"); |
138 | __func__, k); | 112 | goto out; |
139 | return k; | ||
140 | } | 113 | } |
141 | } else { | 114 | } else { |
142 | k = avc_tuner_set_pids(fdtv, pidc, pids); | 115 | ret = avc_tuner_set_pids(fdtv, pidc, pids); |
143 | if (k) { | 116 | if (ret) { |
144 | fdtv_channel_release(fdtv, channel); | 117 | dealloc_channel(fdtv, c); |
145 | printk("%s: AVCTuner_SetPIDs failed with error %d\n", | 118 | dev_err(fdtv->device, "can't set PIDs\n"); |
146 | __func__, k); | 119 | goto out; |
147 | return k; | ||
148 | } | 120 | } |
149 | } | 121 | } |
122 | out: | ||
123 | mutex_unlock(&fdtv->demux_mutex); | ||
150 | 124 | ||
151 | return 0; | 125 | return ret; |
152 | } | 126 | } |
153 | 127 | ||
154 | int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | 128 | int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) |
155 | { | 129 | { |
156 | struct dvb_demux *demux = dvbdmxfeed->demux; | 130 | struct dvb_demux *demux = dvbdmxfeed->demux; |
157 | struct firedtv *fdtv = (struct firedtv*)demux->priv; | 131 | struct firedtv *fdtv = demux->priv; |
158 | struct firedtv_channel *c = dvbdmxfeed->priv; | 132 | int pidc, c, ret; |
159 | int k, l; | ||
160 | u16 pids[16]; | 133 | u16 pids[16]; |
161 | 134 | ||
162 | if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && | 135 | if (dvbdmxfeed->type == DMX_TYPE_TS && |
163 | (demux->dmx.frontend->source != DMX_MEMORY_FE))) { | 136 | !((dvbdmxfeed->ts_type & TS_PACKET) && |
137 | (demux->dmx.frontend->source != DMX_MEMORY_FE))) { | ||
164 | 138 | ||
165 | if (dvbdmxfeed->ts_type & TS_DECODER) { | 139 | if (dvbdmxfeed->ts_type & TS_DECODER) { |
166 | |||
167 | if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || | 140 | if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || |
168 | !demux->pesfilter[dvbdmxfeed->pes_type]) | 141 | !demux->pesfilter[dvbdmxfeed->pes_type]) |
169 | |||
170 | return -EINVAL; | 142 | return -EINVAL; |
171 | 143 | ||
172 | demux->pids[dvbdmxfeed->pes_type] |= 0x8000; | 144 | demux->pids[dvbdmxfeed->pes_type] |= 0x8000; |
@@ -174,38 +146,32 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
174 | } | 146 | } |
175 | 147 | ||
176 | if (!(dvbdmxfeed->ts_type & TS_DECODER && | 148 | if (!(dvbdmxfeed->ts_type & TS_DECODER && |
177 | dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) | 149 | dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) |
178 | |||
179 | return 0; | 150 | return 0; |
180 | } | 151 | } |
181 | 152 | ||
182 | if (mutex_lock_interruptible(&fdtv->demux_mutex)) | 153 | if (mutex_lock_interruptible(&fdtv->demux_mutex)) |
183 | return -EINTR; | 154 | return -EINTR; |
184 | 155 | ||
185 | /* list except channel to be removed */ | 156 | c = (unsigned long)dvbdmxfeed->priv; |
186 | for (k = 0, l = 0; k < 16; k++) | 157 | dealloc_channel(fdtv, c); |
187 | if (fdtv->channel[k].active) { | 158 | collect_channels(fdtv, &pidc, pids); |
188 | if (&fdtv->channel[k] != c) | ||
189 | pids[l++] = fdtv->channel[k].pid; | ||
190 | else | ||
191 | fdtv->channel[k].active = false; | ||
192 | } | ||
193 | 159 | ||
194 | k = avc_tuner_set_pids(fdtv, l, pids); | 160 | ret = avc_tuner_set_pids(fdtv, pidc, pids); |
195 | if (!k) | ||
196 | c->active = false; | ||
197 | 161 | ||
198 | mutex_unlock(&fdtv->demux_mutex); | 162 | mutex_unlock(&fdtv->demux_mutex); |
199 | return k; | 163 | |
164 | return ret; | ||
200 | } | 165 | } |
201 | 166 | ||
202 | int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) | 167 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
168 | |||
169 | int fdtv_dvb_register(struct firedtv *fdtv) | ||
203 | { | 170 | { |
204 | int err; | 171 | int err; |
205 | 172 | ||
206 | err = DVB_REGISTER_ADAPTER(&fdtv->adapter, | 173 | err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type], |
207 | fdtv_model_names[fdtv->type], | 174 | THIS_MODULE, fdtv->device, adapter_nr); |
208 | THIS_MODULE, dev, adapter_nr); | ||
209 | if (err < 0) | 175 | if (err < 0) |
210 | goto fail_log; | 176 | goto fail_log; |
211 | 177 | ||
@@ -223,9 +189,9 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) | |||
223 | if (err) | 189 | if (err) |
224 | goto fail_unreg_adapter; | 190 | goto fail_unreg_adapter; |
225 | 191 | ||
226 | fdtv->dmxdev.filternum = 16; | 192 | fdtv->dmxdev.filternum = 16; |
227 | fdtv->dmxdev.demux = &fdtv->demux.dmx; | 193 | fdtv->dmxdev.demux = &fdtv->demux.dmx; |
228 | fdtv->dmxdev.capabilities = 0; | 194 | fdtv->dmxdev.capabilities = 0; |
229 | 195 | ||
230 | err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); | 196 | err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); |
231 | if (err) | 197 | if (err) |
@@ -233,13 +199,12 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) | |||
233 | 199 | ||
234 | fdtv->frontend.source = DMX_FRONTEND_0; | 200 | fdtv->frontend.source = DMX_FRONTEND_0; |
235 | 201 | ||
236 | err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, | 202 | err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend); |
237 | &fdtv->frontend); | ||
238 | if (err) | 203 | if (err) |
239 | goto fail_dmxdev_release; | 204 | goto fail_dmxdev_release; |
240 | 205 | ||
241 | err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, | 206 | err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, |
242 | &fdtv->frontend); | 207 | &fdtv->frontend); |
243 | if (err) | 208 | if (err) |
244 | goto fail_rem_frontend; | 209 | goto fail_rem_frontend; |
245 | 210 | ||
@@ -252,16 +217,15 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) | |||
252 | 217 | ||
253 | err = fdtv_ca_register(fdtv); | 218 | err = fdtv_ca_register(fdtv); |
254 | if (err) | 219 | if (err) |
255 | dev_info(dev, "Conditional Access Module not enabled\n"); | 220 | dev_info(fdtv->device, |
256 | 221 | "Conditional Access Module not enabled\n"); | |
257 | return 0; | 222 | return 0; |
258 | 223 | ||
259 | fail_net_release: | 224 | fail_net_release: |
260 | dvb_net_release(&fdtv->dvbnet); | 225 | dvb_net_release(&fdtv->dvbnet); |
261 | fdtv->demux.dmx.close(&fdtv->demux.dmx); | 226 | fdtv->demux.dmx.close(&fdtv->demux.dmx); |
262 | fail_rem_frontend: | 227 | fail_rem_frontend: |
263 | fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, | 228 | fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); |
264 | &fdtv->frontend); | ||
265 | fail_dmxdev_release: | 229 | fail_dmxdev_release: |
266 | dvb_dmxdev_release(&fdtv->dmxdev); | 230 | dvb_dmxdev_release(&fdtv->dmxdev); |
267 | fail_dmx_release: | 231 | fail_dmx_release: |
@@ -269,8 +233,132 @@ fail_dmx_release: | |||
269 | fail_unreg_adapter: | 233 | fail_unreg_adapter: |
270 | dvb_unregister_adapter(&fdtv->adapter); | 234 | dvb_unregister_adapter(&fdtv->adapter); |
271 | fail_log: | 235 | fail_log: |
272 | dev_err(dev, "DVB initialization failed\n"); | 236 | dev_err(fdtv->device, "DVB initialization failed\n"); |
273 | return err; | 237 | return err; |
274 | } | 238 | } |
275 | 239 | ||
240 | void fdtv_dvb_unregister(struct firedtv *fdtv) | ||
241 | { | ||
242 | fdtv_ca_release(fdtv); | ||
243 | dvb_unregister_frontend(&fdtv->fe); | ||
244 | dvb_net_release(&fdtv->dvbnet); | ||
245 | fdtv->demux.dmx.close(&fdtv->demux.dmx); | ||
246 | fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); | ||
247 | dvb_dmxdev_release(&fdtv->dmxdev); | ||
248 | dvb_dmx_release(&fdtv->demux); | ||
249 | dvb_unregister_adapter(&fdtv->adapter); | ||
250 | } | ||
251 | |||
252 | const char *fdtv_model_names[] = { | ||
253 | [FIREDTV_UNKNOWN] = "unknown type", | ||
254 | [FIREDTV_DVB_S] = "FireDTV S/CI", | ||
255 | [FIREDTV_DVB_C] = "FireDTV C/CI", | ||
256 | [FIREDTV_DVB_T] = "FireDTV T/CI", | ||
257 | [FIREDTV_DVB_S2] = "FireDTV S2 ", | ||
258 | }; | ||
259 | |||
260 | struct firedtv *fdtv_alloc(struct device *dev, | ||
261 | const struct firedtv_backend *backend, | ||
262 | const char *name, size_t name_len) | ||
263 | { | ||
264 | struct firedtv *fdtv; | ||
265 | int i; | ||
266 | |||
267 | fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); | ||
268 | if (!fdtv) | ||
269 | return NULL; | ||
270 | |||
271 | dev->driver_data = fdtv; | ||
272 | fdtv->device = dev; | ||
273 | fdtv->isochannel = -1; | ||
274 | fdtv->voltage = 0xff; | ||
275 | fdtv->tone = 0xff; | ||
276 | fdtv->backend = backend; | ||
277 | |||
278 | mutex_init(&fdtv->avc_mutex); | ||
279 | init_waitqueue_head(&fdtv->avc_wait); | ||
280 | fdtv->avc_reply_received = true; | ||
281 | mutex_init(&fdtv->demux_mutex); | ||
282 | INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); | ||
283 | |||
284 | for (i = ARRAY_SIZE(fdtv_model_names); --i; ) | ||
285 | if (strlen(fdtv_model_names[i]) <= name_len && | ||
286 | strncmp(name, fdtv_model_names[i], name_len) == 0) | ||
287 | break; | ||
288 | fdtv->type = i; | ||
289 | |||
290 | return fdtv; | ||
291 | } | ||
292 | |||
293 | #define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ | ||
294 | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) | ||
295 | |||
296 | #define DIGITAL_EVERYWHERE_OUI 0x001287 | ||
297 | #define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d | ||
298 | #define AVC_SW_VERSION_ENTRY 0x010001 | ||
299 | |||
300 | static struct ieee1394_device_id fdtv_id_table[] = { | ||
301 | { | ||
302 | /* FloppyDTV S/CI and FloppyDTV S2 */ | ||
303 | .match_flags = MATCH_FLAGS, | ||
304 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
305 | .model_id = 0x000024, | ||
306 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
307 | .version = AVC_SW_VERSION_ENTRY, | ||
308 | }, { | ||
309 | /* FloppyDTV T/CI */ | ||
310 | .match_flags = MATCH_FLAGS, | ||
311 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
312 | .model_id = 0x000025, | ||
313 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
314 | .version = AVC_SW_VERSION_ENTRY, | ||
315 | }, { | ||
316 | /* FloppyDTV C/CI */ | ||
317 | .match_flags = MATCH_FLAGS, | ||
318 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
319 | .model_id = 0x000026, | ||
320 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
321 | .version = AVC_SW_VERSION_ENTRY, | ||
322 | }, { | ||
323 | /* FireDTV S/CI and FloppyDTV S2 */ | ||
324 | .match_flags = MATCH_FLAGS, | ||
325 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
326 | .model_id = 0x000034, | ||
327 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
328 | .version = AVC_SW_VERSION_ENTRY, | ||
329 | }, { | ||
330 | /* FireDTV T/CI */ | ||
331 | .match_flags = MATCH_FLAGS, | ||
332 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
333 | .model_id = 0x000035, | ||
334 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
335 | .version = AVC_SW_VERSION_ENTRY, | ||
336 | }, { | ||
337 | /* FireDTV C/CI */ | ||
338 | .match_flags = MATCH_FLAGS, | ||
339 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
340 | .model_id = 0x000036, | ||
341 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
342 | .version = AVC_SW_VERSION_ENTRY, | ||
343 | }, {} | ||
344 | }; | ||
345 | MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); | ||
346 | |||
347 | static int __init fdtv_init(void) | ||
348 | { | ||
349 | return fdtv_1394_init(fdtv_id_table); | ||
350 | } | ||
351 | |||
352 | static void __exit fdtv_exit(void) | ||
353 | { | ||
354 | fdtv_1394_exit(); | ||
355 | } | ||
356 | |||
357 | module_init(fdtv_init); | ||
358 | module_exit(fdtv_exit); | ||
276 | 359 | ||
360 | MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>"); | ||
361 | MODULE_AUTHOR("Ben Backx <ben@bbackx.com>"); | ||
362 | MODULE_DESCRIPTION("FireDTV DVB Driver"); | ||
363 | MODULE_LICENSE("GPL"); | ||
364 | MODULE_SUPPORTED_DEVICE("FireDTV DVB"); | ||