Commit | Line | Data |
---|---|---|
5740f4e7 HV |
1 | /* |
2 | * tw68-core.c | |
3 | * Core functions for the Techwell 68xx driver | |
4 | * | |
5 | * Much of this code is derived from the cx88 and sa7134 drivers, which | |
6 | * were in turn derived from the bt87x driver. The original work was by | |
7 | * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, | |
8 | * Hans Verkuil, Andy Walls and many others. Their work is gratefully | |
9 | * acknowledged. Full credit goes to them - any problems within this code | |
10 | * are mine. | |
11 | * | |
12 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or | |
17 | * (at your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License along | |
25 | * with this program; if not, write to the Free Software Foundation, Inc., | |
26 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
27 | */ | |
28 | ||
29 | #include <linux/init.h> | |
30 | #include <linux/list.h> | |
31 | #include <linux/module.h> | |
32 | #include <linux/kernel.h> | |
33 | #include <linux/slab.h> | |
34 | #include <linux/kmod.h> | |
35 | #include <linux/sound.h> | |
36 | #include <linux/interrupt.h> | |
37 | #include <linux/delay.h> | |
38 | #include <linux/mutex.h> | |
39 | #include <linux/dma-mapping.h> | |
40 | #include <linux/pm.h> | |
41 | ||
42 | #include <media/v4l2-dev.h> | |
43 | #include "tw68.h" | |
44 | #include "tw68-reg.h" | |
45 | ||
46 | MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); | |
47 | MODULE_AUTHOR("William M. Brack <wbrack@mmm.com.hk>"); | |
48 | MODULE_LICENSE("GPL"); | |
49 | ||
50 | static unsigned int core_debug; | |
51 | module_param(core_debug, int, 0644); | |
52 | MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); | |
53 | ||
54 | static unsigned int gpio_tracking; | |
55 | module_param(gpio_tracking, int, 0644); | |
56 | MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]"); | |
57 | ||
58 | static unsigned int alsa = 1; | |
59 | module_param(alsa, int, 0644); | |
60 | MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]"); | |
61 | ||
62 | static unsigned int latency = UNSET; | |
63 | module_param(latency, int, 0444); | |
64 | MODULE_PARM_DESC(latency, "pci latency timer"); | |
65 | ||
66 | static unsigned int nocomb; | |
67 | module_param(nocomb, int, 0644); | |
68 | MODULE_PARM_DESC(nocomb, "disable comb filter"); | |
69 | ||
70 | static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; | |
71 | static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; | |
72 | static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; | |
73 | static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; | |
74 | static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; | |
75 | ||
76 | module_param_array(video_nr, int, NULL, 0444); | |
77 | module_param_array(vbi_nr, int, NULL, 0444); | |
78 | module_param_array(radio_nr, int, NULL, 0444); | |
79 | module_param_array(tuner, int, NULL, 0444); | |
80 | module_param_array(card, int, NULL, 0444); | |
81 | ||
82 | MODULE_PARM_DESC(video_nr, "video device number"); | |
83 | MODULE_PARM_DESC(vbi_nr, "vbi device number"); | |
84 | MODULE_PARM_DESC(radio_nr, "radio device number"); | |
85 | MODULE_PARM_DESC(tuner, "tuner type"); | |
86 | MODULE_PARM_DESC(card, "card type"); | |
87 | ||
88 | LIST_HEAD(tw68_devlist); | |
89 | EXPORT_SYMBOL(tw68_devlist); | |
90 | DEFINE_MUTEX(tw68_devlist_lock); | |
91 | EXPORT_SYMBOL(tw68_devlist_lock); | |
92 | static LIST_HEAD(mops_list); | |
93 | static unsigned int tw68_devcount; /* curr tot num of devices present */ | |
94 | ||
95 | int (*tw68_dmasound_init)(struct tw68_dev *dev); | |
96 | EXPORT_SYMBOL(tw68_dmasound_init); | |
97 | int (*tw68_dmasound_exit)(struct tw68_dev *dev); | |
98 | EXPORT_SYMBOL(tw68_dmasound_exit); | |
99 | ||
100 | #define dprintk(level, fmt, arg...) if (core_debug & (level)) \ | |
101 | printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) | |
102 | ||
103 | /* ------------------------------------------------------------------ */ | |
104 | ||
105 | void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf) | |
106 | { | |
107 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | |
108 | ||
109 | if (core_debug & DBG_FLOW) | |
110 | printk(KERN_DEBUG "%s: called\n", __func__); | |
111 | BUG_ON(in_interrupt()); | |
112 | ||
113 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) | |
114 | videobuf_waiton(&buf->vb, 0, 0); | |
115 | #else | |
116 | videobuf_waiton(q, &buf->vb, 0, 0); | |
117 | #endif | |
118 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) | |
119 | videobuf_dma_unmap(q, dma); | |
120 | #else | |
121 | videobuf_dma_unmap(q->dev, dma); | |
122 | #endif | |
123 | videobuf_dma_free(dma); | |
124 | /* if no risc area allocated, btcx_riscmem_free just returns */ | |
125 | btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); | |
126 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | |
127 | } | |
128 | ||
129 | /* ------------------------------------------------------------------ */ | |
130 | /* ------------- placeholders for later development ----------------- */ | |
131 | ||
132 | static int tw68_input_init1(struct tw68_dev *dev) | |
133 | { | |
134 | return 0; | |
135 | } | |
136 | ||
137 | static void tw68_input_fini(struct tw68_dev *dev) | |
138 | { | |
139 | return; | |
140 | } | |
141 | ||
142 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) | |
143 | static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir) | |
144 | { | |
145 | return; | |
146 | } | |
147 | ||
148 | static void tw68_ir_stop(struct tw68_dev *dev) | |
149 | { | |
150 | return; | |
151 | } | |
152 | #endif | |
153 | ||
154 | /* ------------------------------------------------------------------ */ | |
155 | /* | |
156 | * Buffer handling routines | |
157 | * | |
158 | * These routines are "generic", i.e. are intended to be used by more | |
159 | * than one module, e.g. the video and the transport stream modules. | |
160 | * To accomplish this generality, callbacks are used whenever some | |
161 | * module-specific test or action is required. | |
162 | */ | |
163 | ||
164 | /* resends a current buffer in queue after resume */ | |
165 | int tw68_buffer_requeue(struct tw68_dev *dev, | |
166 | struct tw68_dmaqueue *q) | |
167 | { | |
168 | struct tw68_buf *buf, *prev; | |
169 | ||
170 | dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); | |
171 | if (!list_empty(&q->active)) { | |
172 | buf = list_entry(q->active.next, struct tw68_buf, vb.queue); | |
173 | dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__, | |
174 | buf, buf->vb.i); | |
175 | q->start_dma(dev, q, buf); | |
176 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | |
177 | return 0; | |
178 | } | |
179 | ||
180 | prev = NULL; | |
181 | for (;;) { | |
182 | if (list_empty(&q->queued)) | |
183 | return 0; | |
184 | buf = list_entry(q->queued.next, struct tw68_buf, vb.queue); | |
185 | /* if nothing precedes this one */ | |
186 | if (NULL == prev) { | |
187 | list_move_tail(&buf->vb.queue, &q->active); | |
188 | q->start_dma(dev, q, buf); | |
189 | buf->activate(dev, buf, NULL); | |
190 | dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", | |
191 | __func__, buf, buf->vb.i); | |
192 | ||
193 | } else if (q->buf_compat(prev, buf) && | |
194 | (prev->fmt == buf->fmt)) { | |
195 | list_move_tail(&buf->vb.queue, &q->active); | |
196 | buf->activate(dev, buf, NULL); | |
197 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | |
198 | dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n", | |
199 | __func__, buf, buf->vb.i); | |
200 | } else { | |
201 | dprintk(DBG_BUFF, "%s: no action taken\n", __func__); | |
202 | return 0; | |
203 | } | |
204 | prev = buf; | |
205 | } | |
206 | } | |
207 | ||
208 | /* nr of (tw68-)pages for the given buffer size */ | |
209 | static int tw68_buffer_pages(int size) | |
210 | { | |
211 | size = PAGE_ALIGN(size); | |
212 | size += PAGE_SIZE; /* for non-page-aligned buffers */ | |
213 | size /= 4096; | |
214 | return size; | |
215 | } | |
216 | ||
217 | /* calc max # of buffers from size (must not exceed the 4MB virtual | |
218 | * address space per DMA channel) */ | |
219 | int tw68_buffer_count(unsigned int size, unsigned int count) | |
220 | { | |
221 | unsigned int maxcount; | |
222 | ||
223 | maxcount = 1024 / tw68_buffer_pages(size); | |
224 | if (count > maxcount) | |
225 | count = maxcount; | |
226 | return count; | |
227 | } | |
228 | ||
229 | /* | |
230 | * tw68_wakeup | |
231 | * | |
232 | * Called when the driver completes filling a buffer, and tasks waiting | |
233 | * for the data need to be awakened. | |
234 | */ | |
235 | void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc) | |
236 | { | |
237 | struct tw68_dev *dev = q->dev; | |
238 | struct tw68_buf *buf; | |
239 | ||
240 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
241 | if (list_empty(&q->active)) { | |
242 | dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty", | |
243 | __func__); | |
244 | del_timer(&q->timeout); | |
245 | return; | |
246 | } | |
247 | buf = list_entry(q->active.next, struct tw68_buf, vb.queue); | |
248 | do_gettimeofday(&buf->vb.ts); | |
249 | buf->vb.field_count = (*fc)++; | |
250 | dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n", | |
251 | __func__, buf, buf->vb.i, *fc); | |
252 | buf->vb.state = VIDEOBUF_DONE; | |
253 | list_del(&buf->vb.queue); | |
254 | wake_up(&buf->vb.done); | |
255 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | |
256 | } | |
257 | ||
258 | /* | |
259 | * tw68_buffer_queue | |
260 | * | |
261 | * Add specified buffer to specified queue | |
262 | */ | |
263 | void tw68_buffer_queue(struct tw68_dev *dev, | |
264 | struct tw68_dmaqueue *q, | |
265 | struct tw68_buf *buf) | |
266 | { | |
267 | struct tw68_buf *prev; | |
268 | ||
269 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
270 | assert_spin_locked(&dev->slock); | |
271 | dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf); | |
272 | ||
273 | /* append a 'JUMP to stopper' to the buffer risc program */ | |
274 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT); | |
275 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | |
276 | ||
277 | /* if this buffer is not "compatible" (in dimensions and format) | |
278 | * with the currently active chain of buffers, we must change | |
279 | * settings before filling it; if a previous buffer has already | |
280 | * been determined to require changes, this buffer must follow | |
281 | * it. To do this, we maintain a "queued" chain. If that | |
282 | * chain exists, append this buffer to it */ | |
283 | if (!list_empty(&q->queued)) { | |
284 | list_add_tail(&buf->vb.queue, &q->queued); | |
285 | buf->vb.state = VIDEOBUF_QUEUED; | |
286 | dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n", | |
287 | __func__, buf, buf->vb.i); | |
288 | ||
289 | /* else if the 'active' chain doesn't yet exist we create it now */ | |
290 | } else if (list_empty(&q->active)) { | |
291 | dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", | |
292 | __func__, buf, buf->vb.i); | |
293 | list_add_tail(&buf->vb.queue, &q->active); | |
294 | q->start_dma(dev, q, buf); /* 1st one - start dma */ | |
295 | /* TODO - why have we removed buf->count and q->count? */ | |
296 | buf->activate(dev, buf, NULL); | |
297 | ||
298 | /* else we would like to put this buffer on the tail of the | |
299 | * active chain, provided it is "compatible". */ | |
300 | } else { | |
301 | /* "compatibility" depends upon the type of buffer */ | |
302 | prev = list_entry(q->active.prev, struct tw68_buf, vb.queue); | |
303 | if (q->buf_compat(prev, buf)) { | |
304 | /* If "compatible", append to active chain */ | |
305 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | |
306 | /* the param 'prev' is only for debug printing */ | |
307 | buf->activate(dev, buf, prev); | |
308 | list_add_tail(&buf->vb.queue, &q->active); | |
309 | dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n", | |
310 | __func__, buf, buf->vb.i); | |
311 | } else { | |
312 | /* If "incompatible", append to queued chain */ | |
313 | list_add_tail(&buf->vb.queue, &q->queued); | |
314 | buf->vb.state = VIDEOBUF_QUEUED; | |
315 | dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended " | |
316 | "to queued\n", __func__, buf, buf->vb.i); | |
317 | } | |
318 | } | |
319 | } | |
320 | ||
321 | /* | |
322 | * tw68_buffer_timeout | |
323 | * | |
324 | * This routine is set as the video_q.timeout.function | |
325 | * | |
326 | * Log the event, try to reset the h/w. | |
327 | * Flag the current buffer as failed, try to start again with next buff | |
328 | */ | |
329 | void tw68_buffer_timeout(unsigned long data) | |
330 | { | |
331 | struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data; | |
332 | struct tw68_dev *dev = q->dev; | |
333 | struct tw68_buf *buf; | |
334 | unsigned long flags; | |
335 | ||
336 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
337 | spin_lock_irqsave(&dev->slock, flags); | |
338 | ||
339 | /* flag all current active buffers as failed */ | |
340 | while (!list_empty(&q->active)) { | |
341 | buf = list_entry(q->active.next, struct tw68_buf, vb.queue); | |
342 | list_del(&buf->vb.queue); | |
343 | buf->vb.state = VIDEOBUF_ERROR; | |
344 | wake_up(&buf->vb.done); | |
345 | printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n", | |
346 | dev->name, buf, buf->vb.i, | |
347 | (unsigned long)buf->risc.dma); | |
348 | } | |
349 | tw68_buffer_requeue(dev, q); | |
350 | spin_unlock_irqrestore(&dev->slock, flags); | |
351 | } | |
352 | ||
353 | /* ------------------------------------------------------------------ */ | |
354 | /* early init (no i2c, no irq) */ | |
355 | ||
356 | /* Called from tw68_hw_init1 and tw68_resume */ | |
357 | static int tw68_hw_enable1(struct tw68_dev *dev) | |
358 | { | |
359 | return 0; | |
360 | } | |
361 | ||
362 | /* | |
363 | * The device is given a "soft reset". According to the specifications, | |
364 | * after this "all register content remain unchanged", so we also write | |
365 | * to all specified registers manually as well (mostly to manufacturer's | |
366 | * specified reset values) | |
367 | */ | |
368 | static int tw68_hw_init1(struct tw68_dev *dev) | |
369 | { | |
370 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
371 | /* Assure all interrupts are disabled */ | |
372 | tw_writel(TW68_INTMASK, 0); /* 020 */ | |
373 | /* Clear any pending interrupts */ | |
374 | tw_writel(TW68_INTSTAT, 0xffffffff); /* 01C */ | |
375 | /* Stop risc processor, set default buffer level */ | |
376 | tw_writel(TW68_DMAC, 0x1600); | |
377 | ||
378 | tw_writeb(TW68_ACNTL, 0x80); /* 218 soft reset */ | |
379 | msleep(100); | |
380 | ||
381 | tw_writeb(TW68_INFORM, 0x40); /* 208 mux0, 27mhz xtal */ | |
382 | tw_writeb(TW68_OPFORM, 0x04); /* 20C analog line-lock */ | |
383 | tw_writeb(TW68_HSYNC, 0); /* 210 color-killer high sens */ | |
384 | tw_writeb(TW68_ACNTL, 0x42); /* 218 int vref #2, chroma adc off */ | |
385 | ||
386 | tw_writeb(TW68_CROP_HI, 0x02); /* 21C Hactive m.s. bits */ | |
387 | tw_writeb(TW68_VDELAY_LO, 0x12);/* 220 Mfg specified reset value */ | |
388 | tw_writeb(TW68_VACTIVE_LO, 0xf0); | |
389 | tw_writeb(TW68_HDELAY_LO, 0x0f); | |
390 | tw_writeb(TW68_HACTIVE_LO, 0xd0); | |
391 | ||
392 | tw_writeb(TW68_CNTRL1, 0xcd); /* 230 Wide Chroma BPF B/W | |
393 | * Secam reduction, Adap comb for | |
394 | * NTSC, Op Mode 1 */ | |
395 | ||
396 | tw_writeb(TW68_VSCALE_LO, 0); /* 234 */ | |
397 | tw_writeb(TW68_SCALE_HI, 0x11); /* 238 */ | |
398 | tw_writeb(TW68_HSCALE_LO, 0); /* 23c */ | |
399 | tw_writeb(TW68_BRIGHT, 0); /* 240 */ | |
400 | tw_writeb(TW68_CONTRAST, 0x5c); /* 244 */ | |
401 | tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */ | |
402 | tw_writeb(TW68_SAT_U, 0x80); /* 24C */ | |
403 | tw_writeb(TW68_SAT_V, 0x80); /* 250 */ | |
404 | tw_writeb(TW68_HUE, 0x00); /* 254 */ | |
405 | ||
406 | /* TODO - Check that none of these are set by control defaults */ | |
407 | tw_writeb(TW68_SHARP2, 0x53); /* 258 Mfg specified reset val */ | |
408 | tw_writeb(TW68_VSHARP, 0x80); /* 25C Sharpness Coring val 8 */ | |
409 | tw_writeb(TW68_CORING, 0x44); /* 260 CTI and Vert Peak coring */ | |
410 | tw_writeb(TW68_CNTRL2, 0x00); /* 268 No power saving enabled */ | |
411 | tw_writeb(TW68_SDT, 0x07); /* 270 Enable shadow reg, auto-det */ | |
412 | tw_writeb(TW68_SDTR, 0x7f); /* 274 All stds recog, don't start */ | |
413 | tw_writeb(TW68_CLMPG, 0x50); /* 280 Clamp end at 40 sys clocks */ | |
414 | tw_writeb(TW68_IAGC, 0x22); /* 284 Mfg specified reset val */ | |
415 | tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ | |
416 | tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ | |
417 | tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ | |
418 | // tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ | |
419 | tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ | |
420 | tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ | |
421 | tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ | |
422 | /* Bit DETV of VCNTL1 helps sync multi cams/chip board */ | |
423 | tw_writeb(TW68_VCNTL1, 0x04); /* 2A0 */ | |
424 | tw_writeb(TW68_VCNTL2, 0); /* 2A4 */ | |
425 | tw_writeb(TW68_CKILL, 0x68); /* 2A8 Mfg specified reset val */ | |
426 | tw_writeb(TW68_COMB, 0x44); /* 2AC Mfg specified reset val */ | |
427 | tw_writeb(TW68_LDLY, 0x30); /* 2B0 Max positive luma delay */ | |
428 | tw_writeb(TW68_MISC1, 0x14); /* 2B4 Mfg specified reset val */ | |
429 | tw_writeb(TW68_LOOP, 0xa5); /* 2B8 Mfg specified reset val */ | |
430 | tw_writeb(TW68_MISC2, 0xe0); /* 2BC Enable colour killer */ | |
431 | tw_writeb(TW68_MVSN, 0); /* 2C0 */ | |
432 | tw_writeb(TW68_CLMD, 0x05); /* 2CC slice level auto, clamp med. */ | |
433 | tw_writeb(TW68_IDCNTL, 0); /* 2D0 Writing zero to this register | |
434 | * selects NTSC ID detection, | |
435 | * but doesn't change the | |
436 | * sensitivity (which has a reset | |
437 | * value of 1E). Since we are | |
438 | * not doing auto-detection, it | |
439 | * has no real effect */ | |
440 | tw_writeb(TW68_CLCNTL1, 0); /* 2D4 */ | |
441 | tw_writel(TW68_VBIC, 0x03); /* 010 */ | |
442 | tw_writel(TW68_CAP_CTL, 0x03); /* 040 Enable both even & odd flds */ | |
443 | tw_writel(TW68_DMAC, 0x2000); /* patch set had 0x2080 */ | |
444 | tw_writel(TW68_TESTREG, 0); /* 02C */ | |
445 | ||
446 | /* | |
447 | * Some common boards, especially inexpensive single-chip models, | |
448 | * use the GPIO bits 0-3 to control an on-board video-output mux. | |
449 | * For these boards, we need to set up the GPIO register into | |
450 | * "normal" mode, set bits 0-3 as output, and then set those bits | |
451 | * zero. | |
452 | * | |
453 | * Eventually, it would be nice if we could identify these boards | |
454 | * uniquely, and only do this initialisation if the board has been | |
455 | * identify. For the moment, however, it shouldn't hurt anything | |
456 | * to do these steps. | |
457 | */ | |
458 | tw_writel(TW68_GPIOC, 0); /* Set the GPIO to "normal", no ints */ | |
459 | tw_writel(TW68_GPOE, 0x0f); /* Set bits 0-3 to "output" */ | |
460 | tw_writel(TW68_GPDATA, 0); /* Set all bits to low state */ | |
461 | ||
462 | /* Initialize the device control structures */ | |
463 | mutex_init(&dev->lock); | |
464 | spin_lock_init(&dev->slock); | |
465 | ||
466 | /* Initialize any subsystems */ | |
467 | tw68_video_init1(dev); | |
468 | tw68_vbi_init1(dev); | |
469 | if (card_has_mpeg(dev)) | |
470 | tw68_ts_init1(dev); | |
471 | tw68_input_init1(dev); | |
472 | ||
473 | /* Do any other h/w early initialisation at this point */ | |
474 | tw68_hw_enable1(dev); | |
475 | ||
476 | return 0; | |
477 | } | |
478 | ||
479 | /* late init (with i2c + irq) */ | |
480 | static int tw68_hw_enable2(struct tw68_dev *dev) | |
481 | { | |
482 | ||
483 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
484 | #ifdef TW68_TESTING | |
485 | dev->pci_irqmask |= TW68_I2C_INTS; | |
486 | #endif | |
487 | tw_setl(TW68_INTMASK, dev->pci_irqmask); | |
488 | return 0; | |
489 | } | |
490 | ||
491 | static int tw68_hw_init2(struct tw68_dev *dev) | |
492 | { | |
493 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
494 | tw68_video_init2(dev); /* initialise video function first */ | |
495 | tw68_tvaudio_init2(dev);/* audio next */ | |
496 | ||
497 | /* all other board-related things, incl. enabling interrupts */ | |
498 | tw68_hw_enable2(dev); | |
499 | return 0; | |
500 | } | |
501 | ||
502 | /* shutdown */ | |
503 | static int tw68_hwfini(struct tw68_dev *dev) | |
504 | { | |
505 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
506 | if (card_has_mpeg(dev)) | |
507 | tw68_ts_fini(dev); | |
508 | tw68_input_fini(dev); | |
509 | tw68_vbi_fini(dev); | |
510 | tw68_tvaudio_fini(dev); | |
511 | return 0; | |
512 | } | |
513 | ||
514 | static void __devinit must_configure_manually(void) | |
515 | { | |
516 | unsigned int i, p; | |
517 | ||
518 | printk(KERN_WARNING | |
519 | "tw68: <rant>\n" | |
520 | "tw68: Congratulations! Your TV card vendor saved a few\n" | |
521 | "tw68: cents for a eeprom, thus your pci board has no\n" | |
522 | "tw68: subsystem ID and I can't identify it automatically\n" | |
523 | "tw68: </rant>\n" | |
524 | "tw68: I feel better now. Ok, here is the good news:\n" | |
525 | "tw68: You can use the card=<nr> insmod option to specify\n" | |
526 | "tw68: which board you have. The list:\n"); | |
527 | for (i = 0; i < tw68_bcount; i++) { | |
528 | printk(KERN_WARNING "tw68: card=%d -> %-40.40s", | |
529 | i, tw68_boards[i].name); | |
530 | for (p = 0; tw68_pci_tbl[p].driver_data; p++) { | |
531 | if (tw68_pci_tbl[p].driver_data != i) | |
532 | continue; | |
533 | printk(" %04x:%04x", | |
534 | tw68_pci_tbl[p].subvendor, | |
535 | tw68_pci_tbl[p].subdevice); | |
536 | } | |
537 | printk("\n"); | |
538 | } | |
539 | } | |
540 | ||
541 | ||
542 | static irqreturn_t tw68_irq(int irq, void *dev_id) | |
543 | { | |
544 | struct tw68_dev *dev = dev_id; | |
545 | u32 status, orig; | |
546 | int loop; | |
547 | ||
548 | status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; | |
549 | /* Check if anything to do */ | |
550 | if (0 == status) | |
551 | return IRQ_RETVAL(0); /* Nope - return */ | |
552 | for (loop = 0; loop < 10; loop++) { | |
553 | if (status & dev->board_virqmask) /* video interrupt */ | |
554 | tw68_irq_video_done(dev, status); | |
555 | #ifdef TW68_TESTING | |
556 | if (status & TW68_I2C_INTS) | |
557 | tw68_irq_i2c(dev, status); | |
558 | #endif | |
559 | status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; | |
560 | if (0 == status) | |
561 | goto out; | |
562 | } | |
563 | dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" | |
564 | " (orig 0x%08x, cur 0x%08x)", | |
565 | dev->name, orig, tw_readl(TW68_INTSTAT)); | |
566 | dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " | |
567 | "0x%08x ****\n", dev->name, | |
568 | dev->pci_irqmask, dev->board_virqmask); | |
569 | tw_clearl(TW68_INTMASK, dev->pci_irqmask); | |
570 | out: | |
571 | return IRQ_RETVAL(1); | |
572 | } | |
573 | ||
574 | int tw68_set_dmabits(struct tw68_dev *dev) | |
575 | { | |
576 | return 0; | |
577 | } | |
578 | ||
579 | static struct video_device *vdev_init(struct tw68_dev *dev, | |
580 | struct video_device *template, | |
581 | char *type) | |
582 | { | |
583 | struct video_device *vfd; | |
584 | ||
585 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
586 | vfd = video_device_alloc(); | |
587 | if (NULL == vfd) | |
588 | return NULL; | |
589 | *vfd = *template; | |
590 | vfd->minor = -1; | |
591 | vfd->parent = &dev->pci->dev; | |
592 | vfd->release = video_device_release; | |
593 | /* vfd->debug = tw_video_debug; */ | |
594 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | |
595 | dev->name, type, tw68_boards[dev->board].name); | |
596 | return vfd; | |
597 | } | |
598 | ||
599 | static void tw68_unregister_video(struct tw68_dev *dev) | |
600 | { | |
601 | ||
602 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
603 | if (dev->video_dev) { | |
604 | if (-1 != dev->video_dev->minor) | |
605 | video_unregister_device(dev->video_dev); | |
606 | else | |
607 | video_device_release(dev->video_dev); | |
608 | dev->video_dev = NULL; | |
609 | } | |
610 | if (dev->vbi_dev) { | |
611 | if (-1 != dev->vbi_dev->minor) | |
612 | video_unregister_device(dev->vbi_dev); | |
613 | else | |
614 | video_device_release(dev->vbi_dev); | |
615 | dev->vbi_dev = NULL; | |
616 | } | |
617 | if (dev->radio_dev) { | |
618 | if (-1 != dev->radio_dev->minor) | |
619 | video_unregister_device(dev->radio_dev); | |
620 | else | |
621 | video_device_release(dev->radio_dev); | |
622 | dev->radio_dev = NULL; | |
623 | } | |
624 | } | |
625 | ||
626 | static void mpeg_ops_attach(struct tw68_mpeg_ops *ops, | |
627 | struct tw68_dev *dev) | |
628 | { | |
629 | int err; | |
630 | ||
631 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
632 | if (NULL != dev->mops) | |
633 | return; | |
634 | if (tw68_boards[dev->board].mpeg != ops->type) | |
635 | return; | |
636 | err = ops->init(dev); | |
637 | if (0 != err) | |
638 | return; | |
639 | dev->mops = ops; | |
640 | } | |
641 | ||
642 | static void mpeg_ops_detach(struct tw68_mpeg_ops *ops, | |
643 | struct tw68_dev *dev) | |
644 | { | |
645 | ||
646 | if (NULL == dev->mops) | |
647 | return; | |
648 | if (dev->mops != ops) | |
649 | return; | |
650 | dev->mops->fini(dev); | |
651 | dev->mops = NULL; | |
652 | } | |
653 | ||
654 | static int __devinit tw68_initdev(struct pci_dev *pci_dev, | |
655 | const struct pci_device_id *pci_id) | |
656 | { | |
657 | struct tw68_dev *dev; | |
658 | struct tw68_mpeg_ops *mops; | |
659 | int err; | |
660 | ||
661 | if (tw68_devcount == TW68_MAXBOARDS) | |
662 | return -ENOMEM; | |
663 | ||
664 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |
665 | if (NULL == dev) | |
666 | return -ENOMEM; | |
667 | ||
668 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); | |
669 | if (err) | |
670 | goto fail0; | |
671 | ||
672 | /* pci init */ | |
673 | dev->pci = pci_dev; | |
674 | if (pci_enable_device(pci_dev)) { | |
675 | err = -EIO; | |
676 | goto fail1; | |
677 | } | |
678 | ||
679 | dev->nr = tw68_devcount; | |
680 | sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); | |
681 | ||
682 | /* pci quirks */ | |
683 | if (pci_pci_problems) { | |
684 | if (pci_pci_problems & PCIPCI_TRITON) | |
685 | printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", | |
686 | dev->name); | |
687 | if (pci_pci_problems & PCIPCI_NATOMA) | |
688 | printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", | |
689 | dev->name); | |
690 | if (pci_pci_problems & PCIPCI_VIAETBF) | |
691 | printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", | |
692 | dev->name); | |
693 | if (pci_pci_problems & PCIPCI_VSFX) | |
694 | printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n", | |
695 | dev->name); | |
696 | #ifdef PCIPCI_ALIMAGIK | |
697 | if (pci_pci_problems & PCIPCI_ALIMAGIK) { | |
698 | printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK " | |
699 | "-- latency fixup\n", dev->name); | |
700 | latency = 0x0A; | |
701 | } | |
702 | #endif | |
703 | } | |
704 | if (UNSET != latency) { | |
705 | printk(KERN_INFO "%s: setting pci latency timer to %d\n", | |
706 | dev->name, latency); | |
707 | pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); | |
708 | } | |
709 | ||
710 | /* print pci info */ | |
711 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | |
712 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | |
713 | printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " | |
714 | "latency: %d, mmio: 0x%llx\n", dev->name, | |
715 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, | |
716 | (unsigned long long)pci_resource_start(pci_dev, 0)); | |
717 | pci_set_master(pci_dev); | |
718 | if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { | |
719 | printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); | |
720 | err = -EIO; | |
721 | goto fail1; | |
722 | } | |
723 | ||
724 | switch (pci_id->device) { | |
725 | case PCI_DEVICE_ID_6800: /* TW6800 */ | |
726 | dev->vdecoder = TW6800; | |
727 | dev->board_virqmask = TW68_VID_INTS; | |
728 | break; | |
729 | case PCI_DEVICE_ID_6801: /* Video decoder for TW6802 */ | |
730 | dev->vdecoder = TW6801; | |
731 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; | |
732 | break; | |
733 | case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ | |
734 | dev->vdecoder = TW6804; | |
735 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; | |
736 | break; | |
737 | default: | |
738 | dev->vdecoder = TWXXXX; /* To be announced */ | |
739 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; | |
740 | break; | |
741 | } | |
742 | /* board config */ | |
743 | dev->board = pci_id->driver_data; | |
744 | if (card[dev->nr] >= 0 && | |
745 | card[dev->nr] < tw68_bcount) | |
746 | dev->board = card[dev->nr]; | |
747 | if (TW68_BOARD_NOAUTO == dev->board) { | |
748 | must_configure_manually(); | |
749 | dev->board = TW68_BOARD_UNKNOWN; | |
750 | } | |
751 | dev->autodetected = card[dev->nr] != dev->board; | |
752 | dev->tuner_type = tw68_boards[dev->board].tuner_type; | |
753 | dev->tuner_addr = tw68_boards[dev->board].tuner_addr; | |
754 | dev->radio_type = tw68_boards[dev->board].radio_type; | |
755 | dev->radio_addr = tw68_boards[dev->board].radio_addr; | |
756 | dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf; | |
757 | if (UNSET != tuner[dev->nr]) | |
758 | dev->tuner_type = tuner[dev->nr]; | |
759 | printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", | |
760 | dev->name, pci_dev->subsystem_vendor, | |
761 | pci_dev->subsystem_device, tw68_boards[dev->board].name, | |
762 | dev->board, dev->autodetected ? | |
763 | "autodetected" : "insmod option"); | |
764 | ||
765 | /* get mmio */ | |
766 | if (!request_mem_region(pci_resource_start(pci_dev, 0), | |
767 | pci_resource_len(pci_dev, 0), | |
768 | dev->name)) { | |
769 | err = -EBUSY; | |
770 | printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", | |
771 | dev->name, | |
772 | (unsigned long long)pci_resource_start(pci_dev, 0)); | |
773 | goto fail1; | |
774 | } | |
775 | dev->lmmio = ioremap(pci_resource_start(pci_dev, 0), | |
776 | pci_resource_len(pci_dev, 0)); | |
777 | dev->bmmio = (__u8 __iomem *)dev->lmmio; | |
778 | if (NULL == dev->lmmio) { | |
779 | err = -EIO; | |
780 | printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", | |
781 | dev->name); | |
782 | goto fail2; | |
783 | } | |
784 | /* initialize hardware #1 */ | |
785 | /* First, take care of anything unique to a particular card */ | |
786 | tw68_board_init1(dev); | |
787 | /* Then do any initialisation wanted before interrupts are on */ | |
788 | tw68_hw_init1(dev); | |
789 | ||
790 | /* get irq */ | |
791 | err = request_irq(pci_dev->irq, tw68_irq, | |
792 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | |
793 | if (err < 0) { | |
794 | printk(KERN_ERR "%s: can't get IRQ %d\n", | |
795 | dev->name, pci_dev->irq); | |
796 | goto fail3; | |
797 | } | |
798 | ||
799 | #ifdef TW68_TESTING | |
800 | dev->pci_irqmask |= TW68_SBDONE; | |
801 | tw_setl(TW68_INTMASK, dev->pci_irqmask); | |
802 | printk(KERN_INFO "Calling tw68_i2c_register\n"); | |
803 | /* Register the i2c bus */ | |
804 | tw68_i2c_register(dev); | |
805 | #endif | |
806 | ||
807 | /* | |
808 | * Now do remainder of initialisation, first for | |
809 | * things unique for this card, then for general board | |
810 | */ | |
811 | tw68_board_init2(dev); | |
812 | ||
813 | tw68_hw_init2(dev); | |
814 | ||
815 | #if 0 | |
816 | /* load i2c helpers */ | |
817 | if (card_is_empress(dev)) { | |
818 | struct v4l2_subdev *sd = | |
819 | v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", | |
820 | "saa6752hs", 0x20); | |
821 | ||
822 | if (sd) | |
823 | sd->grp_id = GRP_EMPRESS; | |
824 | } | |
825 | ||
826 | request_submodules(dev); | |
827 | #endif | |
828 | ||
829 | v4l2_prio_init(&dev->prio); | |
830 | ||
831 | mutex_lock(&tw68_devlist_lock); | |
832 | list_for_each_entry(mops, &mops_list, next) | |
833 | mpeg_ops_attach(mops, dev); | |
834 | list_add_tail(&dev->devlist, &tw68_devlist); | |
835 | mutex_unlock(&tw68_devlist_lock); | |
836 | ||
837 | /* check for signal */ | |
838 | tw68_irq_video_signalchange(dev); | |
839 | ||
840 | #if 0 | |
841 | if (TUNER_ABSENT != dev->tuner_type) | |
842 | tw_call_all(dev, core, s_standby, 0); | |
843 | #endif | |
844 | ||
845 | dev->video_dev = vdev_init(dev, &tw68_video_template, "video"); | |
846 | err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, | |
847 | video_nr[dev->nr]); | |
848 | if (err < 0) { | |
849 | printk(KERN_INFO "%s: can't register video device\n", | |
850 | dev->name); | |
851 | goto fail4; | |
852 | } | |
853 | printk(KERN_INFO "%s: registered device video%d [v4l2]\n", | |
854 | dev->name, dev->video_dev->num); | |
855 | ||
856 | dev->vbi_dev = vdev_init(dev, &tw68_video_template, "vbi"); | |
857 | ||
858 | err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, | |
859 | vbi_nr[dev->nr]); | |
860 | if (err < 0) { | |
861 | printk(KERN_INFO "%s: can't register vbi device\n", | |
862 | dev->name); | |
863 | goto fail4; | |
864 | } | |
865 | printk(KERN_INFO "%s: registered device vbi%d\n", | |
866 | dev->name, dev->vbi_dev->num); | |
867 | ||
868 | if (card_has_radio(dev)) { | |
869 | dev->radio_dev = vdev_init(dev, &tw68_radio_template, | |
870 | "radio"); | |
871 | err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, | |
872 | radio_nr[dev->nr]); | |
873 | if (err < 0) { | |
874 | /* TODO - need to unregister vbi? */ | |
875 | printk(KERN_INFO "%s: can't register radio device\n", | |
876 | dev->name); | |
877 | goto fail4; | |
878 | } | |
879 | printk(KERN_INFO "%s: registered device radio%d\n", | |
880 | dev->name, dev->radio_dev->num); | |
881 | } | |
882 | ||
883 | /* everything worked */ | |
884 | tw68_devcount++; | |
885 | ||
886 | if (tw68_dmasound_init && !dev->dmasound.priv_data) | |
887 | tw68_dmasound_init(dev); | |
888 | ||
889 | return 0; | |
890 | ||
891 | fail4: | |
892 | tw68_unregister_video(dev); | |
893 | #ifdef TW68_TESTING | |
894 | tw68_i2c_unregister(dev); | |
895 | #endif | |
896 | free_irq(pci_dev->irq, dev); | |
897 | fail3: | |
898 | tw68_hwfini(dev); | |
899 | iounmap(dev->lmmio); | |
900 | fail2: | |
901 | release_mem_region(pci_resource_start(pci_dev, 0), | |
902 | pci_resource_len(pci_dev, 0)); | |
903 | fail1: | |
904 | v4l2_device_unregister(&dev->v4l2_dev); | |
905 | fail0: | |
906 | kfree(dev); | |
907 | return err; | |
908 | } | |
909 | ||
910 | static void __devexit tw68_finidev(struct pci_dev *pci_dev) | |
911 | { | |
912 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | |
913 | struct tw68_dev *dev = | |
914 | container_of(v4l2_dev, struct tw68_dev, v4l2_dev); | |
915 | struct tw68_mpeg_ops *mops; | |
916 | ||
917 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
918 | /* Release DMA sound modules if present */ | |
919 | if (tw68_dmasound_exit && dev->dmasound.priv_data) | |
920 | tw68_dmasound_exit(dev); | |
921 | ||
922 | /* shutdown subsystems */ | |
923 | tw68_hwfini(dev); | |
924 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | |
925 | tw_writel(TW68_INTMASK, 0); | |
926 | ||
927 | /* unregister */ | |
928 | mutex_lock(&tw68_devlist_lock); | |
929 | list_del(&dev->devlist); | |
930 | list_for_each_entry(mops, &mops_list, next) | |
931 | mpeg_ops_detach(mops, dev); | |
932 | mutex_unlock(&tw68_devlist_lock); | |
933 | tw68_devcount--; | |
934 | ||
935 | #ifdef TW68_TESTING | |
936 | tw68_i2c_unregister(dev); | |
937 | #endif | |
938 | tw68_unregister_video(dev); | |
939 | ||
940 | ||
941 | /* the DMA sound modules should be unloaded before reaching | |
942 | this, but just in case they are still present... */ | |
943 | if (dev->dmasound.priv_data != NULL) { | |
944 | free_irq(pci_dev->irq, &dev->dmasound); | |
945 | dev->dmasound.priv_data = NULL; | |
946 | } | |
947 | ||
948 | ||
949 | /* release resources */ | |
950 | free_irq(pci_dev->irq, dev); | |
951 | iounmap(dev->lmmio); | |
952 | release_mem_region(pci_resource_start(pci_dev, 0), | |
953 | pci_resource_len(pci_dev, 0)); | |
954 | ||
955 | v4l2_device_unregister(&dev->v4l2_dev); | |
956 | ||
957 | /* free memory */ | |
958 | kfree(dev); | |
959 | } | |
960 | ||
961 | #ifdef CONFIG_PM | |
962 | ||
963 | static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) | |
964 | { | |
965 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | |
966 | struct tw68_dev *dev = container_of(v4l2_dev, | |
967 | struct tw68_dev, v4l2_dev); | |
968 | ||
969 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
970 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | |
971 | dev->pci_irqmask &= ~TW68_VID_INTS; | |
972 | tw_writel(TW68_INTMASK, 0); | |
973 | ||
974 | dev->insuspend = 1; | |
975 | synchronize_irq(pci_dev->irq); | |
976 | ||
977 | /* Disable timeout timers - if we have active buffers, we will | |
978 | fill them on resume*/ | |
979 | ||
980 | del_timer(&dev->video_q.timeout); | |
981 | del_timer(&dev->vbi_q.timeout); | |
982 | del_timer(&dev->ts_q.timeout); | |
983 | ||
984 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) | |
985 | if (dev->remote) | |
986 | tw68_ir_stop(dev); | |
987 | #endif | |
988 | ||
989 | pci_save_state(pci_dev); | |
990 | pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); | |
991 | ||
992 | return 0; | |
993 | } | |
994 | ||
995 | static int tw68_resume(struct pci_dev *pci_dev) | |
996 | { | |
997 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | |
998 | struct tw68_dev *dev = container_of(v4l2_dev, | |
999 | struct tw68_dev, v4l2_dev); | |
1000 | unsigned long flags; | |
1001 | ||
1002 | dprintk(DBG_FLOW, "%s: called\n", __func__); | |
1003 | pci_set_power_state(pci_dev, PCI_D0); | |
1004 | pci_restore_state(pci_dev); | |
1005 | ||
1006 | /* Do things that are done in tw68_initdev , | |
1007 | except of initializing memory structures.*/ | |
1008 | ||
1009 | tw68_board_init1(dev); | |
1010 | ||
1011 | /* tw68_hw_init1 */ | |
1012 | if (tw68_boards[dev->board].video_out) | |
1013 | tw68_videoport_init(dev); | |
1014 | if (card_has_mpeg(dev)) | |
1015 | tw68_ts_init_hw(dev); | |
1016 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) | |
1017 | if (dev->remote) | |
1018 | tw68_ir_start(dev, dev->remote); | |
1019 | #endif | |
1020 | tw68_hw_enable1(dev); | |
1021 | ||
1022 | msleep(100); | |
1023 | ||
1024 | tw68_board_init2(dev); | |
1025 | ||
1026 | /*tw68_hw_init2*/ | |
1027 | tw68_set_tvnorm_hw(dev); | |
1028 | tw68_tvaudio_setmute(dev); | |
1029 | /* tw68_tvaudio_setvolume(dev, dev->ctl_volume); */ | |
1030 | tw68_tvaudio_init(dev); | |
1031 | tw68_irq_video_signalchange(dev); | |
1032 | ||
1033 | /*resume unfinished buffer(s)*/ | |
1034 | spin_lock_irqsave(&dev->slock, flags); | |
1035 | tw68_buffer_requeue(dev, &dev->video_q); | |
1036 | tw68_buffer_requeue(dev, &dev->vbi_q); | |
1037 | tw68_buffer_requeue(dev, &dev->ts_q); | |
1038 | ||
1039 | /* FIXME: Disable DMA audio sound - temporary till proper support | |
1040 | is implemented*/ | |
1041 | ||
1042 | dev->dmasound.dma_running = 0; | |
1043 | ||
1044 | /* start DMA now*/ | |
1045 | dev->insuspend = 0; | |
1046 | smp_wmb(); | |
1047 | tw68_set_dmabits(dev); | |
1048 | spin_unlock_irqrestore(&dev->slock, flags); | |
1049 | ||
1050 | return 0; | |
1051 | } | |
1052 | #endif | |
1053 | ||
1054 | /* ----------------------------------------------------------- */ | |
1055 | ||
1056 | static struct pci_driver tw68_pci_driver = { | |
1057 | .name = "tw68", | |
1058 | .id_table = tw68_pci_tbl, | |
1059 | .probe = tw68_initdev, | |
1060 | .remove = __devexit_p(tw68_finidev), | |
1061 | #ifdef CONFIG_PM | |
1062 | .suspend = tw68_suspend, | |
1063 | .resume = tw68_resume | |
1064 | #endif | |
1065 | }; | |
1066 | ||
1067 | static int tw68_init(void) | |
1068 | { | |
1069 | if (core_debug & DBG_FLOW) | |
1070 | printk(KERN_DEBUG "%s: called\n", __func__); | |
1071 | INIT_LIST_HEAD(&tw68_devlist); | |
1072 | printk(KERN_INFO "tw68: v4l2 driver version %d.%d.%d loaded\n", | |
1073 | (TW68_VERSION_CODE >> 16) & 0xff, | |
1074 | (TW68_VERSION_CODE >> 8) & 0xff, | |
1075 | TW68_VERSION_CODE & 0xff); | |
1076 | #if 0 | |
1077 | printk(KERN_INFO "tw68: snapshot date %04d-%02d-%02d\n", | |
1078 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | |
1079 | #endif | |
1080 | return pci_register_driver(&tw68_pci_driver); | |
1081 | } | |
1082 | ||
1083 | static void module_cleanup(void) | |
1084 | { | |
1085 | if (core_debug & DBG_FLOW) | |
1086 | printk(KERN_DEBUG "%s: called\n", __func__); | |
1087 | pci_unregister_driver(&tw68_pci_driver); | |
1088 | } | |
1089 | ||
1090 | module_init(tw68_init); | |
1091 | module_exit(module_cleanup); |