diff options
-rw-r--r-- | drivers/media/pci/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/pci/tw68/Kconfig | 10 | ||||
-rw-r--r-- | drivers/media/pci/tw68/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-cards.c | 172 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-core.c | 801 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-i2c.c | 245 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-reg.h | 10 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-risc.c | 156 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-ts.c | 66 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-tvaudio.c | 80 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-vbi.c | 76 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68-video.c | 1906 | ||||
-rw-r--r-- | drivers/media/pci/tw68/tw68.h | 435 |
14 files changed, 558 insertions, 3404 deletions
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 5c16c9c2203e..933280740176 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig | |||
@@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig" | |||
20 | source "drivers/media/pci/zoran/Kconfig" | 20 | source "drivers/media/pci/zoran/Kconfig" |
21 | source "drivers/media/pci/saa7146/Kconfig" | 21 | source "drivers/media/pci/saa7146/Kconfig" |
22 | source "drivers/media/pci/solo6x10/Kconfig" | 22 | source "drivers/media/pci/solo6x10/Kconfig" |
23 | source "drivers/media/pci/tw68/Kconfig" | ||
23 | endif | 24 | endif |
24 | 25 | ||
25 | if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT | 26 | if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT |
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index dc2ebbe27306..73d9c0f11127 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile | |||
@@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ | |||
21 | obj-$(CONFIG_VIDEO_BT848) += bt8xx/ | 21 | obj-$(CONFIG_VIDEO_BT848) += bt8xx/ |
22 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ | 22 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ |
23 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ | 23 | obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ |
24 | obj-$(CONFIG_VIDEO_TW68) += tw68/ | ||
24 | obj-$(CONFIG_VIDEO_MEYE) += meye/ | 25 | obj-$(CONFIG_VIDEO_MEYE) += meye/ |
25 | obj-$(CONFIG_STA2X11_VIP) += sta2x11/ | 26 | obj-$(CONFIG_STA2X11_VIP) += sta2x11/ |
26 | obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ | 27 | obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ |
diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig new file mode 100644 index 000000000000..5425ba1e320d --- /dev/null +++ b/drivers/media/pci/tw68/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | config VIDEO_TW68 | ||
2 | tristate "Techwell tw68x Video For Linux" | ||
3 | depends on VIDEO_DEV && PCI && VIDEO_V4L2 | ||
4 | select I2C_ALGOBIT | ||
5 | select VIDEOBUF2_DMA_SG | ||
6 | ---help--- | ||
7 | Support for Techwell tw68xx based frame grabber boards. | ||
8 | |||
9 | To compile this driver as a module, choose M here: the | ||
10 | module will be called tw68. | ||
diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile new file mode 100644 index 000000000000..3d02f28b14fb --- /dev/null +++ b/drivers/media/pci/tw68/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | tw68-objs := tw68-core.o tw68-video.o tw68-risc.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_TW68) += tw68.o | ||
diff --git a/drivers/media/pci/tw68/tw68-cards.c b/drivers/media/pci/tw68/tw68-cards.c deleted file mode 100644 index 62aec4faa0d1..000000000000 --- a/drivers/media/pci/tw68/tw68-cards.c +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | /* | ||
2 | * device driver for Techwell 68xx based cards | ||
3 | * | ||
4 | * Much of this code is derived from the cx88 and sa7134 drivers, which | ||
5 | * were in turn derived from the bt87x driver. The original work was by | ||
6 | * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, | ||
7 | * Hans Verkuil, Andy Walls and many others. Their work is gratefully | ||
8 | * acknowledged. Full credit goes to them - any problems within this code | ||
9 | * are mine. | ||
10 | * | ||
11 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | ||
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; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/init.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/i2c.h> /* must appear before i2c-algo-bit.h */ | ||
31 | #include <linux/i2c-algo-bit.h> | ||
32 | |||
33 | #include <media/v4l2-common.h> | ||
34 | #include <media/tveeprom.h> | ||
35 | |||
36 | #include "tw68.h" | ||
37 | #include "tw68-reg.h" | ||
38 | |||
39 | /* commly used strings */ | ||
40 | #if 0 | ||
41 | static char name_mute[] = "mute"; | ||
42 | static char name_radio[] = "Radio"; | ||
43 | static char name_tv[] = "Television"; | ||
44 | static char name_tv_mono[] = "TV (mono only)"; | ||
45 | static char name_svideo[] = "S-Video"; | ||
46 | static char name_comp[] = "Composite"; | ||
47 | #endif | ||
48 | static char name_comp1[] = "Composite1"; | ||
49 | static char name_comp2[] = "Composite2"; | ||
50 | static char name_comp3[] = "Composite3"; | ||
51 | static char name_comp4[] = "Composite4"; | ||
52 | |||
53 | /* ------------------------------------------------------------------ */ | ||
54 | /* board config info */ | ||
55 | |||
56 | /* If radio_type !=UNSET, radio_addr should be specified | ||
57 | */ | ||
58 | |||
59 | struct tw68_board tw68_boards[] = { | ||
60 | [TW68_BOARD_UNKNOWN] = { | ||
61 | .name = "GENERIC", | ||
62 | .tuner_type = TUNER_ABSENT, | ||
63 | .radio_type = UNSET, | ||
64 | .tuner_addr = ADDR_UNSET, | ||
65 | .radio_addr = ADDR_UNSET, | ||
66 | |||
67 | .inputs = { | ||
68 | { | ||
69 | .name = name_comp1, | ||
70 | .vmux = 0, | ||
71 | }, { | ||
72 | .name = name_comp2, | ||
73 | .vmux = 1, | ||
74 | }, { | ||
75 | .name = name_comp3, | ||
76 | .vmux = 2, | ||
77 | }, { | ||
78 | .name = name_comp4, | ||
79 | .vmux = 3, | ||
80 | }, { /* Must have a NULL entry at end of list */ | ||
81 | .name = NULL, | ||
82 | .vmux = 0, | ||
83 | } | ||
84 | }, | ||
85 | }, | ||
86 | }; | ||
87 | |||
88 | const unsigned int tw68_bcount = ARRAY_SIZE(tw68_boards); | ||
89 | |||
90 | /* | ||
91 | * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps | ||
92 | * the PCI ID database up to date. Note that the entries must be | ||
93 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. | ||
94 | */ | ||
95 | struct pci_device_id tw68_pci_tbl[] = { | ||
96 | { | ||
97 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
98 | .device = PCI_DEVICE_ID_6800, | ||
99 | .subvendor = PCI_ANY_ID, | ||
100 | .subdevice = PCI_ANY_ID, | ||
101 | .driver_data = TW68_BOARD_UNKNOWN, | ||
102 | }, { | ||
103 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
104 | .device = PCI_DEVICE_ID_6801, | ||
105 | .subvendor = PCI_ANY_ID, | ||
106 | .subdevice = PCI_ANY_ID, | ||
107 | .driver_data = TW68_BOARD_UNKNOWN, | ||
108 | }, { | ||
109 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
110 | .device = PCI_DEVICE_ID_6804, | ||
111 | .subvendor = PCI_ANY_ID, | ||
112 | .subdevice = PCI_ANY_ID, | ||
113 | .driver_data = TW68_BOARD_UNKNOWN, | ||
114 | }, { | ||
115 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
116 | .device = PCI_DEVICE_ID_6816_1, | ||
117 | .subvendor = PCI_ANY_ID, | ||
118 | .subdevice = PCI_ANY_ID, | ||
119 | .driver_data = TW68_BOARD_UNKNOWN, | ||
120 | }, { | ||
121 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
122 | .device = PCI_DEVICE_ID_6816_2, | ||
123 | .subvendor = PCI_ANY_ID, | ||
124 | .subdevice = PCI_ANY_ID, | ||
125 | .driver_data = TW68_BOARD_UNKNOWN, | ||
126 | }, { | ||
127 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
128 | .device = PCI_DEVICE_ID_6816_3, | ||
129 | .subvendor = PCI_ANY_ID, | ||
130 | .subdevice = PCI_ANY_ID, | ||
131 | .driver_data = TW68_BOARD_UNKNOWN, | ||
132 | }, { | ||
133 | .vendor = PCI_VENDOR_ID_TECHWELL, | ||
134 | .device = PCI_DEVICE_ID_6816_4, | ||
135 | .subvendor = PCI_ANY_ID, | ||
136 | .subdevice = PCI_ANY_ID, | ||
137 | .driver_data = TW68_BOARD_UNKNOWN, | ||
138 | }, { | ||
139 | /* end of list */ | ||
140 | } | ||
141 | }; | ||
142 | MODULE_DEVICE_TABLE(pci, tw68_pci_tbl); | ||
143 | |||
144 | /* ------------------------------------------------------------ */ | ||
145 | /* stuff done before i2c enabled */ | ||
146 | int tw68_board_init1(struct tw68_dev *dev) | ||
147 | { | ||
148 | /* Clear GPIO outputs */ | ||
149 | tw_writel(TW68_GPOE, 0); | ||
150 | /* Remainder of setup according to board ID */ | ||
151 | switch (dev->board) { | ||
152 | case TW68_BOARD_UNKNOWN: | ||
153 | printk(KERN_INFO "%s: Unable to determine board type, " | ||
154 | "using generic values\n", dev->name); | ||
155 | break; | ||
156 | } | ||
157 | dev->input = dev->hw_input = &card_in(dev,0); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | int tw68_tuner_setup(struct tw68_dev *dev) | ||
162 | { | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /* stuff which needs working i2c */ | ||
167 | int tw68_board_init2(struct tw68_dev *dev) | ||
168 | { | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | |||
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 2c5d7a5f3f8e..baf93af1d764 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c | |||
@@ -9,7 +9,11 @@ | |||
9 | * acknowledged. Full credit goes to them - any problems within this code | 9 | * acknowledged. Full credit goes to them - any problems within this code |
10 | * are mine. | 10 | * are mine. |
11 | * | 11 | * |
12 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | 12 | * Copyright (C) 2009 William M. Brack |
13 | * | ||
14 | * Refactored and updated to the latest v4l core frameworks: | ||
15 | * | ||
16 | * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> | ||
13 | * | 17 | * |
14 | * This program is free software; you can redistribute it and/or modify | 18 | * 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 | 19 | * it under the terms of the GNU General Public License as published by |
@@ -20,10 +24,6 @@ | |||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. | 26 | * 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 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
@@ -44,320 +44,44 @@ | |||
44 | #include "tw68-reg.h" | 44 | #include "tw68-reg.h" |
45 | 45 | ||
46 | MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); | 46 | MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); |
47 | MODULE_AUTHOR("William M. Brack <wbrack@mmm.com.hk>"); | 47 | MODULE_AUTHOR("William M. Brack"); |
48 | MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); | ||
48 | MODULE_LICENSE("GPL"); | 49 | MODULE_LICENSE("GPL"); |
49 | 50 | ||
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; | 51 | static unsigned int latency = UNSET; |
63 | module_param(latency, int, 0444); | 52 | module_param(latency, int, 0444); |
64 | MODULE_PARM_DESC(latency, "pci latency timer"); | 53 | MODULE_PARM_DESC(latency, "pci latency timer"); |
65 | 54 | ||
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 }; | 55 | 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); | 56 | 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"); | 57 | 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 | 58 | ||
95 | int (*tw68_dmasound_init)(struct tw68_dev *dev); | 59 | static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; |
96 | EXPORT_SYMBOL(tw68_dmasound_init); | 60 | module_param_array(card, int, NULL, 0444); |
97 | int (*tw68_dmasound_exit)(struct tw68_dev *dev); | 61 | MODULE_PARM_DESC(card, "card type"); |
98 | EXPORT_SYMBOL(tw68_dmasound_exit); | ||
99 | 62 | ||
100 | #define dprintk(level, fmt, arg...) if (core_debug & (level)) \ | 63 | static atomic_t tw68_instance = ATOMIC_INIT(0); |
101 | printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) | ||
102 | 64 | ||
103 | /* ------------------------------------------------------------------ */ | 65 | /* ------------------------------------------------------------------ */ |
104 | 66 | ||
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 | /* | 67 | /* |
156 | * Buffer handling routines | 68 | * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps |
157 | * | 69 | * the PCI ID database up to date. Note that the entries must be |
158 | * These routines are "generic", i.e. are intended to be used by more | 70 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. |
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 | */ | 71 | */ |
163 | 72 | struct pci_device_id tw68_pci_tbl[] = { | |
164 | /* resends a current buffer in queue after resume */ | 73 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)}, |
165 | int tw68_buffer_requeue(struct tw68_dev *dev, | 74 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)}, |
166 | struct tw68_dmaqueue *q) | 75 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)}, |
167 | { | 76 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)}, |
168 | struct tw68_buf *buf, *prev; | 77 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)}, |
169 | 78 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)}, | |
170 | dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); | 79 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)}, |
171 | if (!list_empty(&q->active)) { | 80 | {0,} |
172 | buf = list_entry(q->active.next, struct tw68_buf, vb.queue); | 81 | }; |
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 | 82 | ||
353 | /* ------------------------------------------------------------------ */ | 83 | /* ------------------------------------------------------------------ */ |
354 | /* early init (no i2c, no irq) */ | ||
355 | 84 | ||
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 | 85 | ||
362 | /* | 86 | /* |
363 | * The device is given a "soft reset". According to the specifications, | 87 | * The device is given a "soft reset". According to the specifications, |
@@ -367,7 +91,6 @@ static int tw68_hw_enable1(struct tw68_dev *dev) | |||
367 | */ | 91 | */ |
368 | static int tw68_hw_init1(struct tw68_dev *dev) | 92 | static int tw68_hw_init1(struct tw68_dev *dev) |
369 | { | 93 | { |
370 | dprintk(DBG_FLOW, "%s: called\n", __func__); | ||
371 | /* Assure all interrupts are disabled */ | 94 | /* Assure all interrupts are disabled */ |
372 | tw_writel(TW68_INTMASK, 0); /* 020 */ | 95 | tw_writel(TW68_INTMASK, 0); /* 020 */ |
373 | /* Clear any pending interrupts */ | 96 | /* Clear any pending interrupts */ |
@@ -415,7 +138,7 @@ static int tw68_hw_init1(struct tw68_dev *dev) | |||
415 | tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ | 138 | tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ |
416 | tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ | 139 | tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ |
417 | tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ | 140 | tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ |
418 | // tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ | 141 | /* tw_writeb(TW68_SYNCT, 0x38);*/ /* 294 Sync amplitude */ |
419 | tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ | 142 | tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ |
420 | tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ | 143 | tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ |
421 | tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ | 144 | tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ |
@@ -465,80 +188,9 @@ static int tw68_hw_init1(struct tw68_dev *dev) | |||
465 | 188 | ||
466 | /* Initialize any subsystems */ | 189 | /* Initialize any subsystems */ |
467 | tw68_video_init1(dev); | 190 | 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; | 191 | return 0; |
489 | } | 192 | } |
490 | 193 | ||
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) | 194 | static irqreturn_t tw68_irq(int irq, void *dev_id) |
543 | { | 195 | { |
544 | struct tw68_dev *dev = dev_id; | 196 | struct tw68_dev *dev = dev_id; |
@@ -548,126 +200,39 @@ static irqreturn_t tw68_irq(int irq, void *dev_id) | |||
548 | status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; | 200 | status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; |
549 | /* Check if anything to do */ | 201 | /* Check if anything to do */ |
550 | if (0 == status) | 202 | if (0 == status) |
551 | return IRQ_RETVAL(0); /* Nope - return */ | 203 | return IRQ_NONE; /* Nope - return */ |
552 | for (loop = 0; loop < 10; loop++) { | 204 | for (loop = 0; loop < 10; loop++) { |
553 | if (status & dev->board_virqmask) /* video interrupt */ | 205 | if (status & dev->board_virqmask) /* video interrupt */ |
554 | tw68_irq_video_done(dev, status); | 206 | 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; | 207 | status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; |
560 | if (0 == status) | 208 | if (0 == status) |
561 | goto out; | 209 | return IRQ_HANDLED; |
562 | } | 210 | } |
563 | dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" | 211 | dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)", |
564 | " (orig 0x%08x, cur 0x%08x)", | 212 | dev->name, orig, tw_readl(TW68_INTSTAT)); |
565 | dev->name, orig, tw_readl(TW68_INTSTAT)); | 213 | dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n", |
566 | dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " | 214 | dev->name, dev->pci_irqmask, dev->board_virqmask); |
567 | "0x%08x ****\n", dev->name, | ||
568 | dev->pci_irqmask, dev->board_virqmask); | ||
569 | tw_clearl(TW68_INTMASK, dev->pci_irqmask); | 215 | tw_clearl(TW68_INTMASK, dev->pci_irqmask); |
570 | out: | 216 | return IRQ_HANDLED; |
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 | } | 217 | } |
598 | 218 | ||
599 | static void tw68_unregister_video(struct tw68_dev *dev) | 219 | static int tw68_initdev(struct pci_dev *pci_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) | 220 | const struct pci_device_id *pci_id) |
656 | { | 221 | { |
657 | struct tw68_dev *dev; | 222 | struct tw68_dev *dev; |
658 | struct tw68_mpeg_ops *mops; | 223 | int vidnr = -1; |
659 | int err; | 224 | int err; |
660 | 225 | ||
661 | if (tw68_devcount == TW68_MAXBOARDS) | 226 | dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL); |
662 | return -ENOMEM; | ||
663 | |||
664 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
665 | if (NULL == dev) | 227 | if (NULL == dev) |
666 | return -ENOMEM; | 228 | return -ENOMEM; |
667 | 229 | ||
230 | dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68", | ||
231 | &tw68_instance); | ||
232 | |||
668 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); | 233 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); |
669 | if (err) | 234 | if (err) |
670 | goto fail0; | 235 | return err; |
671 | 236 | ||
672 | /* pci init */ | 237 | /* pci init */ |
673 | dev->pci = pci_dev; | 238 | dev->pci = pci_dev; |
@@ -676,33 +241,10 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, | |||
676 | goto fail1; | 241 | goto fail1; |
677 | } | 242 | } |
678 | 243 | ||
679 | dev->nr = tw68_devcount; | 244 | dev->name = dev->v4l2_dev.name; |
680 | sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); | ||
681 | 245 | ||
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) { | 246 | if (UNSET != latency) { |
705 | printk(KERN_INFO "%s: setting pci latency timer to %d\n", | 247 | pr_info("%s: setting pci latency timer to %d\n", |
706 | dev->name, latency); | 248 | dev->name, latency); |
707 | pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); | 249 | pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); |
708 | } | 250 | } |
@@ -710,13 +252,12 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, | |||
710 | /* print pci info */ | 252 | /* print pci info */ |
711 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 253 | 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); | 254 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); |
713 | printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " | 255 | pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", |
714 | "latency: %d, mmio: 0x%llx\n", dev->name, | 256 | dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, |
715 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, | 257 | dev->pci_lat, (u64)pci_resource_start(pci_dev, 0)); |
716 | (unsigned long long)pci_resource_start(pci_dev, 0)); | ||
717 | pci_set_master(pci_dev); | 258 | pci_set_master(pci_dev); |
718 | if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { | 259 | if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { |
719 | printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); | 260 | pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name); |
720 | err = -EIO; | 261 | err = -EIO; |
721 | goto fail1; | 262 | goto fail1; |
722 | } | 263 | } |
@@ -730,7 +271,7 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, | |||
730 | dev->vdecoder = TW6801; | 271 | dev->vdecoder = TW6801; |
731 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; | 272 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; |
732 | break; | 273 | break; |
733 | case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ | 274 | case PCI_DEVICE_ID_6804: /* Video decoder for TW6804 */ |
734 | dev->vdecoder = TW6804; | 275 | dev->vdecoder = TW6804; |
735 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; | 276 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; |
736 | break; | 277 | break; |
@@ -739,35 +280,13 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, | |||
739 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; | 280 | dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; |
740 | break; | 281 | break; |
741 | } | 282 | } |
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 | 283 | ||
765 | /* get mmio */ | 284 | /* get mmio */ |
766 | if (!request_mem_region(pci_resource_start(pci_dev, 0), | 285 | if (!request_mem_region(pci_resource_start(pci_dev, 0), |
767 | pci_resource_len(pci_dev, 0), | 286 | pci_resource_len(pci_dev, 0), |
768 | dev->name)) { | 287 | dev->name)) { |
769 | err = -EBUSY; | 288 | err = -EBUSY; |
770 | printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", | 289 | pr_err("%s: can't get MMIO memory @ 0x%llx\n", |
771 | dev->name, | 290 | dev->name, |
772 | (unsigned long long)pci_resource_start(pci_dev, 0)); | 291 | (unsigned long long)pci_resource_start(pci_dev, 0)); |
773 | goto fail1; | 292 | goto fail1; |
@@ -777,185 +296,75 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, | |||
777 | dev->bmmio = (__u8 __iomem *)dev->lmmio; | 296 | dev->bmmio = (__u8 __iomem *)dev->lmmio; |
778 | if (NULL == dev->lmmio) { | 297 | if (NULL == dev->lmmio) { |
779 | err = -EIO; | 298 | err = -EIO; |
780 | printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", | 299 | pr_err("%s: can't ioremap() MMIO memory\n", |
781 | dev->name); | 300 | dev->name); |
782 | goto fail2; | 301 | goto fail2; |
783 | } | 302 | } |
784 | /* initialize hardware #1 */ | 303 | /* 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 */ | 304 | /* Then do any initialisation wanted before interrupts are on */ |
788 | tw68_hw_init1(dev); | 305 | tw68_hw_init1(dev); |
789 | 306 | ||
790 | /* get irq */ | 307 | /* get irq */ |
791 | err = request_irq(pci_dev->irq, tw68_irq, | 308 | err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, |
792 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | 309 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); |
793 | if (err < 0) { | 310 | if (err < 0) { |
794 | printk(KERN_ERR "%s: can't get IRQ %d\n", | 311 | pr_err("%s: can't get IRQ %d\n", |
795 | dev->name, pci_dev->irq); | 312 | dev->name, pci_dev->irq); |
796 | goto fail3; | 313 | goto fail3; |
797 | } | 314 | } |
798 | 315 | ||
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 | /* | 316 | /* |
808 | * Now do remainder of initialisation, first for | 317 | * Now do remainder of initialisation, first for |
809 | * things unique for this card, then for general board | 318 | * things unique for this card, then for general board |
810 | */ | 319 | */ |
811 | tw68_board_init2(dev); | 320 | if (dev->instance < TW68_MAXBOARDS) |
812 | 321 | vidnr = video_nr[dev->instance]; | |
813 | tw68_hw_init2(dev); | 322 | /* initialise video function first */ |
814 | 323 | err = tw68_video_init2(dev, vidnr); | |
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) { | 324 | if (err < 0) { |
849 | printk(KERN_INFO "%s: can't register video device\n", | 325 | pr_err("%s: can't register video device\n", |
850 | dev->name); | 326 | dev->name); |
851 | goto fail4; | 327 | goto fail4; |
852 | } | 328 | } |
853 | printk(KERN_INFO "%s: registered device video%d [v4l2]\n", | 329 | tw_setl(TW68_INTMASK, dev->pci_irqmask); |
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 | 330 | ||
886 | if (tw68_dmasound_init && !dev->dmasound.priv_data) | 331 | pr_info("%s: registered device %s\n", |
887 | tw68_dmasound_init(dev); | 332 | dev->name, video_device_node_name(&dev->vdev)); |
888 | 333 | ||
889 | return 0; | 334 | return 0; |
890 | 335 | ||
891 | fail4: | 336 | fail4: |
892 | tw68_unregister_video(dev); | 337 | video_unregister_device(&dev->vdev); |
893 | #ifdef TW68_TESTING | 338 | fail3: |
894 | tw68_i2c_unregister(dev); | ||
895 | #endif | ||
896 | free_irq(pci_dev->irq, dev); | ||
897 | fail3: | ||
898 | tw68_hwfini(dev); | ||
899 | iounmap(dev->lmmio); | 339 | iounmap(dev->lmmio); |
900 | fail2: | 340 | fail2: |
901 | release_mem_region(pci_resource_start(pci_dev, 0), | 341 | release_mem_region(pci_resource_start(pci_dev, 0), |
902 | pci_resource_len(pci_dev, 0)); | 342 | pci_resource_len(pci_dev, 0)); |
903 | fail1: | 343 | fail1: |
904 | v4l2_device_unregister(&dev->v4l2_dev); | 344 | v4l2_device_unregister(&dev->v4l2_dev); |
905 | fail0: | ||
906 | kfree(dev); | ||
907 | return err; | 345 | return err; |
908 | } | 346 | } |
909 | 347 | ||
910 | static void __devexit tw68_finidev(struct pci_dev *pci_dev) | 348 | static void tw68_finidev(struct pci_dev *pci_dev) |
911 | { | 349 | { |
912 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | 350 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); |
913 | struct tw68_dev *dev = | 351 | struct tw68_dev *dev = |
914 | container_of(v4l2_dev, struct tw68_dev, v4l2_dev); | 352 | 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 | 353 | ||
922 | /* shutdown subsystems */ | 354 | /* shutdown subsystems */ |
923 | tw68_hwfini(dev); | ||
924 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | 355 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); |
925 | tw_writel(TW68_INTMASK, 0); | 356 | tw_writel(TW68_INTMASK, 0); |
926 | 357 | ||
927 | /* unregister */ | 358 | /* unregister */ |
928 | mutex_lock(&tw68_devlist_lock); | 359 | video_unregister_device(&dev->vdev); |
929 | list_del(&dev->devlist); | 360 | v4l2_ctrl_handler_free(&dev->hdl); |
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 | 361 | ||
949 | /* release resources */ | 362 | /* release resources */ |
950 | free_irq(pci_dev->irq, dev); | ||
951 | iounmap(dev->lmmio); | 363 | iounmap(dev->lmmio); |
952 | release_mem_region(pci_resource_start(pci_dev, 0), | 364 | release_mem_region(pci_resource_start(pci_dev, 0), |
953 | pci_resource_len(pci_dev, 0)); | 365 | pci_resource_len(pci_dev, 0)); |
954 | 366 | ||
955 | v4l2_device_unregister(&dev->v4l2_dev); | 367 | v4l2_device_unregister(&dev->v4l2_dev); |
956 | |||
957 | /* free memory */ | ||
958 | kfree(dev); | ||
959 | } | 368 | } |
960 | 369 | ||
961 | #ifdef CONFIG_PM | 370 | #ifdef CONFIG_PM |
@@ -966,28 +375,15 @@ static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) | |||
966 | struct tw68_dev *dev = container_of(v4l2_dev, | 375 | struct tw68_dev *dev = container_of(v4l2_dev, |
967 | struct tw68_dev, v4l2_dev); | 376 | struct tw68_dev, v4l2_dev); |
968 | 377 | ||
969 | dprintk(DBG_FLOW, "%s: called\n", __func__); | ||
970 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | 378 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); |
971 | dev->pci_irqmask &= ~TW68_VID_INTS; | 379 | dev->pci_irqmask &= ~TW68_VID_INTS; |
972 | tw_writel(TW68_INTMASK, 0); | 380 | tw_writel(TW68_INTMASK, 0); |
973 | 381 | ||
974 | dev->insuspend = 1; | ||
975 | synchronize_irq(pci_dev->irq); | 382 | synchronize_irq(pci_dev->irq); |
976 | 383 | ||
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); | 384 | pci_save_state(pci_dev); |
990 | pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); | 385 | pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); |
386 | vb2_discard_done(&dev->vidq); | ||
991 | 387 | ||
992 | return 0; | 388 | return 0; |
993 | } | 389 | } |
@@ -997,54 +393,25 @@ static int tw68_resume(struct pci_dev *pci_dev) | |||
997 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | 393 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); |
998 | struct tw68_dev *dev = container_of(v4l2_dev, | 394 | struct tw68_dev *dev = container_of(v4l2_dev, |
999 | struct tw68_dev, v4l2_dev); | 395 | struct tw68_dev, v4l2_dev); |
396 | struct tw68_buf *buf; | ||
1000 | unsigned long flags; | 397 | unsigned long flags; |
1001 | 398 | ||
1002 | dprintk(DBG_FLOW, "%s: called\n", __func__); | ||
1003 | pci_set_power_state(pci_dev, PCI_D0); | 399 | pci_set_power_state(pci_dev, PCI_D0); |
1004 | pci_restore_state(pci_dev); | 400 | pci_restore_state(pci_dev); |
1005 | 401 | ||
1006 | /* Do things that are done in tw68_initdev , | 402 | /* Do things that are done in tw68_initdev , |
1007 | except of initializing memory structures.*/ | 403 | except of initializing memory structures.*/ |
1008 | 404 | ||
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); | 405 | msleep(100); |
1023 | 406 | ||
1024 | tw68_board_init2(dev); | ||
1025 | |||
1026 | /*tw68_hw_init2*/ | ||
1027 | tw68_set_tvnorm_hw(dev); | 407 | 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 | 408 | ||
1033 | /*resume unfinished buffer(s)*/ | 409 | /*resume unfinished buffer(s)*/ |
1034 | spin_lock_irqsave(&dev->slock, flags); | 410 | spin_lock_irqsave(&dev->slock, flags); |
1035 | tw68_buffer_requeue(dev, &dev->video_q); | 411 | buf = container_of(dev->active.next, struct tw68_buf, list); |
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 | 412 | ||
1042 | dev->dmasound.dma_running = 0; | 413 | tw68_video_start_dma(dev, buf); |
1043 | 414 | ||
1044 | /* start DMA now*/ | ||
1045 | dev->insuspend = 0; | ||
1046 | smp_wmb(); | ||
1047 | tw68_set_dmabits(dev); | ||
1048 | spin_unlock_irqrestore(&dev->slock, flags); | 415 | spin_unlock_irqrestore(&dev->slock, flags); |
1049 | 416 | ||
1050 | return 0; | 417 | return 0; |
@@ -1057,35 +424,11 @@ static struct pci_driver tw68_pci_driver = { | |||
1057 | .name = "tw68", | 424 | .name = "tw68", |
1058 | .id_table = tw68_pci_tbl, | 425 | .id_table = tw68_pci_tbl, |
1059 | .probe = tw68_initdev, | 426 | .probe = tw68_initdev, |
1060 | .remove = __devexit_p(tw68_finidev), | 427 | .remove = tw68_finidev, |
1061 | #ifdef CONFIG_PM | 428 | #ifdef CONFIG_PM |
1062 | .suspend = tw68_suspend, | 429 | .suspend = tw68_suspend, |
1063 | .resume = tw68_resume | 430 | .resume = tw68_resume |
1064 | #endif | 431 | #endif |
1065 | }; | 432 | }; |
1066 | 433 | ||
1067 | static int tw68_init(void) | 434 | module_pci_driver(tw68_pci_driver); |
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); | ||
diff --git a/drivers/media/pci/tw68/tw68-i2c.c b/drivers/media/pci/tw68/tw68-i2c.c deleted file mode 100644 index 38659d0b1e18..000000000000 --- a/drivers/media/pci/tw68/tw68-i2c.c +++ /dev/null | |||
@@ -1,245 +0,0 @@ | |||
1 | /* | ||
2 | * tw68 code to handle the i2c interface. | ||
3 | * | ||
4 | * Much of this code is derived from the bt87x driver. The original | ||
5 | * work was by Gerd Knorr; more recently the code was enhanced by Mauro | ||
6 | * Carvalho Chehab. Their work is gratefully acknowledged. Full credit | ||
7 | * goes to them - any problems within this code are mine. | ||
8 | * | ||
9 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License along | ||
22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/delay.h> | ||
32 | |||
33 | #include "tw68.h" | ||
34 | #include <media/v4l2-common.h> | ||
35 | #include <linux/i2c-algo-bit.h> | ||
36 | |||
37 | /*----------------------------------------------------------------*/ | ||
38 | |||
39 | static unsigned int i2c_debug; | ||
40 | module_param(i2c_debug, int, 0644); | ||
41 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | ||
42 | |||
43 | #if 0 | ||
44 | static unsigned int i2c_scan; | ||
45 | module_param(i2c_scan, int, 0444); | ||
46 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | ||
47 | #endif | ||
48 | |||
49 | #define d1printk if (1 == i2c_debug) printk | ||
50 | |||
51 | #define I2C_CLOCK 0xa6 /* 99.4 kHz */ | ||
52 | |||
53 | /*----------------------------------------------------------------------*/ | ||
54 | /* Although the TW68xx i2c controller has a "hardware" mode, where all of | ||
55 | * the low-level i2c/smbbus is handled by the chip, it appears that mode | ||
56 | * is not suitable for linux i2c handling routines because extended "bursts" | ||
57 | * of data (sequences of bytes without intervening START/STOP bits) are | ||
58 | * not possible. Instead, we put the chip into "software" mode, and handle | ||
59 | * the i2c bus at a low level. To accomplish this, we use the routines | ||
60 | * from the i2c modules. | ||
61 | * | ||
62 | * Because the particular boards which I had for testing did not have any | ||
63 | * devices attached to the i2c bus, I have been unable to test these | ||
64 | * routines. | ||
65 | */ | ||
66 | |||
67 | /*----------------------------------------------------------------------*/ | ||
68 | /* I2C functions - "bit-banging" adapter (software i2c) */ | ||
69 | |||
70 | /* tw68_bit_setcl | ||
71 | * Handles "toggling" the i2c clock bit | ||
72 | */ | ||
73 | static void tw68_bit_setscl(void *data, int state) | ||
74 | { | ||
75 | struct tw68_dev *dev = data; | ||
76 | |||
77 | tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSCLK, TW68_SSCLK_B); | ||
78 | } | ||
79 | |||
80 | /* tw68_bit_setsda | ||
81 | * Handles "toggling" the i2c data bit | ||
82 | */ | ||
83 | static void tw68_bit_setsda(void *data, int state) | ||
84 | { | ||
85 | struct tw68_dev *dev = data; | ||
86 | |||
87 | tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSDAT, TW68_SSDAT_B); | ||
88 | } | ||
89 | |||
90 | /* tw68_bit_getscl | ||
91 | * | ||
92 | * Returns the current state of the clock bit | ||
93 | */ | ||
94 | static int tw68_bit_getscl(void *data) | ||
95 | { | ||
96 | struct tw68_dev *dev = data; | ||
97 | |||
98 | return (tw_readb(TW68_SBUSC) & TW68_SSCLK_B) ? 1 : 0; | ||
99 | } | ||
100 | |||
101 | /* tw68_bit_getsda | ||
102 | * | ||
103 | * Returns the current state of the data bit | ||
104 | */ | ||
105 | static int tw68_bit_getsda(void *data) | ||
106 | { | ||
107 | struct tw68_dev *dev = data; | ||
108 | |||
109 | return (tw_readb(TW68_SBUSC) & TW68_SSDAT_B) ? 1 : 0; | ||
110 | } | ||
111 | |||
112 | static struct i2c_algo_bit_data __devinitdata tw68_i2c_algo_bit_template = { | ||
113 | .setsda = tw68_bit_setsda, | ||
114 | .setscl = tw68_bit_setscl, | ||
115 | .getsda = tw68_bit_getsda, | ||
116 | .getscl = tw68_bit_getscl, | ||
117 | .udelay = 16, | ||
118 | .timeout = 200, | ||
119 | }; | ||
120 | |||
121 | static struct i2c_client tw68_client_template = { | ||
122 | .name = "tw68 internal", | ||
123 | }; | ||
124 | |||
125 | /*----------------------------------------------------------------*/ | ||
126 | |||
127 | static int attach_inform(struct i2c_client *client) | ||
128 | { | ||
129 | /* struct tw68_dev *dev = client->adapter->algo_data; */ | ||
130 | |||
131 | d1printk("%s i2c attach [addr=0x%x,client=%s]\n", | ||
132 | client->driver->driver.name, client->addr, client->name); | ||
133 | |||
134 | switch (client->addr) { | ||
135 | /* No info yet on what addresses to expect */ | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static struct i2c_adapter tw68_adap_sw_template = { | ||
142 | .owner = THIS_MODULE, | ||
143 | .name = "tw68_sw", | ||
144 | .client_register = attach_inform, | ||
145 | }; | ||
146 | |||
147 | static int tw68_i2c_eeprom(struct tw68_dev *dev, unsigned char *eedata, | ||
148 | int len) | ||
149 | { | ||
150 | unsigned char buf; | ||
151 | int i, err; | ||
152 | |||
153 | dev->i2c_client.addr = 0xa0 >> 1; | ||
154 | buf = 256 - len; | ||
155 | |||
156 | err = i2c_master_send(&dev->i2c_client, &buf, 1); | ||
157 | if (1 != err) { | ||
158 | printk(KERN_INFO "%s: Huh, no eeprom present (err = %d)?\n", | ||
159 | dev->name, err); | ||
160 | return -1; | ||
161 | } | ||
162 | err = i2c_master_recv(&dev->i2c_client, eedata, len); | ||
163 | if (len != err) { | ||
164 | printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", | ||
165 | dev->name, err); | ||
166 | return -1; | ||
167 | } | ||
168 | |||
169 | for (i = 0; i < len; i++) { | ||
170 | if (0 == (i % 16)) | ||
171 | printk(KERN_INFO "%s: i2c eeprom %02x:", | ||
172 | dev->name, i); | ||
173 | printk(KERN_INFO " %02x", eedata[i]); | ||
174 | if (15 == (i % 16)) | ||
175 | printk("\n"); | ||
176 | } | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | #if 0 | ||
181 | static char *i2c_devs[128] = { | ||
182 | [0xa0 >> 1] = "eeprom", | ||
183 | }; | ||
184 | |||
185 | static void do_i2c_scan(char *name, struct i2c_client *c) | ||
186 | { | ||
187 | unsigned char buf; | ||
188 | int i, rc; | ||
189 | |||
190 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { | ||
191 | c->addr = i; | ||
192 | rc = i2c_master_recv(c, &buf, 1); | ||
193 | if (rc < 0) | ||
194 | continue; | ||
195 | printk(KERN_INFO "%s: i2c scan: found device " | ||
196 | "@ 0x%x [%s]\n", name, i << 1, | ||
197 | i2c_devs[i] ? i2c_devs[i] : "???"); | ||
198 | } | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | int __devinit tw68_i2c_register(struct tw68_dev *dev) | ||
203 | { | ||
204 | int rc; | ||
205 | |||
206 | printk(KERN_DEBUG "%s: Registering i2c module\n", __func__); | ||
207 | tw_writeb(TW68_I2C_RST, 1); /* reset the i2c module */ | ||
208 | |||
209 | memcpy(&dev->i2c_client, &tw68_client_template, | ||
210 | sizeof(tw68_client_template)); | ||
211 | |||
212 | memcpy(&dev->i2c_adap, &tw68_adap_sw_template, | ||
213 | sizeof(tw68_adap_sw_template)); | ||
214 | dev->i2c_adap.algo_data = &dev->i2c_algo; | ||
215 | dev->i2c_adap.dev.parent = &dev->pci->dev; | ||
216 | |||
217 | memcpy(&dev->i2c_algo, &tw68_i2c_algo_bit_template, | ||
218 | sizeof(tw68_i2c_algo_bit_template)); | ||
219 | dev->i2c_algo.data = dev; | ||
220 | /* TODO - may want to set better name (see bttv code) */ | ||
221 | |||
222 | i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); | ||
223 | dev->i2c_client.adapter = &dev->i2c_adap; | ||
224 | |||
225 | /* Assure chip is in "software" mode */ | ||
226 | tw_writel(TW68_SBUSC, TW68_SSDAT | TW68_SSCLK); | ||
227 | tw68_bit_setscl(dev, 1); | ||
228 | tw68_bit_setsda(dev, 1); | ||
229 | |||
230 | rc = i2c_bit_add_bus(&dev->i2c_adap); | ||
231 | |||
232 | tw68_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); | ||
233 | #if 0 | ||
234 | if (i2c_scan) | ||
235 | do_i2c_scan(dev->name, &dev->i2c_client); | ||
236 | #endif | ||
237 | |||
238 | return rc; | ||
239 | } | ||
240 | |||
241 | int tw68_i2c_unregister(struct tw68_dev *dev) | ||
242 | { | ||
243 | i2c_del_adapter(&dev->i2c_adap); | ||
244 | return 0; | ||
245 | } | ||
diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h index 314bc43cd9d3..f60b3a896fa7 100644 --- a/drivers/media/pci/tw68/tw68-reg.h +++ b/drivers/media/pci/tw68/tw68-reg.h | |||
@@ -8,7 +8,11 @@ | |||
8 | * acknowledged. Full credit goes to them - any problems within this code | 8 | * acknowledged. Full credit goes to them - any problems within this code |
9 | * are mine. | 9 | * are mine. |
10 | * | 10 | * |
11 | * Copyright (C) William M. Brack <wbrack@mmm.com.hk> | 11 | * Copyright (C) William M. Brack |
12 | * | ||
13 | * Refactored and updated to the latest v4l core frameworks: | ||
14 | * | ||
15 | * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> | ||
12 | * | 16 | * |
13 | * This program is free software; you can redistribute it and/or modify | 17 | * 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 | 18 | * it under the terms of the GNU General Public License as published by |
@@ -19,10 +23,6 @@ | |||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 25 | * GNU General Public License for more details. |
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #ifndef _TW68_REG_H_ | 28 | #ifndef _TW68_REG_H_ |
diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c index 66273bbd51c5..7439db212a69 100644 --- a/drivers/media/pci/tw68/tw68-risc.c +++ b/drivers/media/pci/tw68/tw68-risc.c | |||
@@ -9,7 +9,11 @@ | |||
9 | * acknowledged. Full credit goes to them - any problems within this code | 9 | * acknowledged. Full credit goes to them - any problems within this code |
10 | * are mine. | 10 | * are mine. |
11 | * | 11 | * |
12 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | 12 | * Copyright (C) 2009 William M. Brack |
13 | * | ||
14 | * Refactored and updated to the latest v4l core frameworks: | ||
15 | * | ||
16 | * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> | ||
13 | * | 17 | * |
14 | * This program is free software; you can redistribute it and/or modify | 18 | * 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 | 19 | * it under the terms of the GNU General Public License as published by |
@@ -20,16 +24,10 @@ | |||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. | 26 | * 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 | */ | 27 | */ |
28 | 28 | ||
29 | #include "tw68.h" | 29 | #include "tw68.h" |
30 | 30 | ||
31 | #define NO_SYNC_LINE (-1U) | ||
32 | |||
33 | /** | 31 | /** |
34 | * @rp pointer to current risc program position | 32 | * @rp pointer to current risc program position |
35 | * @sglist pointer to "scatter-gather list" of buffer pointers | 33 | * @sglist pointer to "scatter-gather list" of buffer pointers |
@@ -38,32 +36,35 @@ | |||
38 | * @bpl number of bytes per scan line | 36 | * @bpl number of bytes per scan line |
39 | * @padding number of bytes of padding to add | 37 | * @padding number of bytes of padding to add |
40 | * @lines number of lines in field | 38 | * @lines number of lines in field |
41 | * @lpi lines per IRQ, or 0 to not generate irqs | 39 | * @jump insert a jump at the start |
42 | * Note: IRQ to be generated _after_ lpi lines are transferred | ||
43 | */ | 40 | */ |
44 | static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, | 41 | static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, |
45 | unsigned int offset, u32 sync_line, | 42 | unsigned int offset, u32 sync_line, |
46 | unsigned int bpl, unsigned int padding, | 43 | unsigned int bpl, unsigned int padding, |
47 | unsigned int lines, unsigned int lpi) | 44 | unsigned int lines, bool jump) |
48 | { | 45 | { |
49 | struct scatterlist *sg; | 46 | struct scatterlist *sg; |
50 | unsigned int line, todo, done; | 47 | unsigned int line, todo, done; |
51 | 48 | ||
52 | /* sync instruction */ | 49 | if (jump) { |
53 | if (sync_line != NO_SYNC_LINE) { | 50 | *(rp++) = cpu_to_le32(RISC_JUMP); |
54 | if (sync_line == 1) | ||
55 | *(rp++) = cpu_to_le32(RISC_SYNCO); | ||
56 | else | ||
57 | *(rp++) = cpu_to_le32(RISC_SYNCE); | ||
58 | *(rp++) = 0; | 51 | *(rp++) = 0; |
59 | } | 52 | } |
53 | |||
54 | /* sync instruction */ | ||
55 | if (sync_line == 1) | ||
56 | *(rp++) = cpu_to_le32(RISC_SYNCO); | ||
57 | else | ||
58 | *(rp++) = cpu_to_le32(RISC_SYNCE); | ||
59 | *(rp++) = 0; | ||
60 | |||
60 | /* scan lines */ | 61 | /* scan lines */ |
61 | sg = sglist; | 62 | sg = sglist; |
62 | for (line = 0; line < lines; line++) { | 63 | for (line = 0; line < lines; line++) { |
63 | /* calculate next starting position */ | 64 | /* calculate next starting position */ |
64 | while (offset && offset >= sg_dma_len(sg)) { | 65 | while (offset && offset >= sg_dma_len(sg)) { |
65 | offset -= sg_dma_len(sg); | 66 | offset -= sg_dma_len(sg); |
66 | sg++; | 67 | sg = sg_next(sg); |
67 | } | 68 | } |
68 | if (bpl <= sg_dma_len(sg) - offset) { | 69 | if (bpl <= sg_dma_len(sg) - offset) { |
69 | /* fits into current chunk */ | 70 | /* fits into current chunk */ |
@@ -86,7 +87,7 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, | |||
86 | done); | 87 | done); |
87 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); | 88 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); |
88 | todo -= done; | 89 | todo -= done; |
89 | sg++; | 90 | sg = sg_next(sg); |
90 | /* succeeding fragments have no offset */ | 91 | /* succeeding fragments have no offset */ |
91 | while (todo > sg_dma_len(sg)) { | 92 | while (todo > sg_dma_len(sg)) { |
92 | *(rp++) = cpu_to_le32(RISC_INLINE | | 93 | *(rp++) = cpu_to_le32(RISC_INLINE | |
@@ -94,7 +95,7 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, | |||
94 | sg_dma_len(sg)); | 95 | sg_dma_len(sg)); |
95 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | 96 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
96 | todo -= sg_dma_len(sg); | 97 | todo -= sg_dma_len(sg); |
97 | sg++; | 98 | sg = sg_next(sg); |
98 | done += sg_dma_len(sg); | 99 | done += sg_dma_len(sg); |
99 | } | 100 | } |
100 | if (todo) { | 101 | if (todo) { |
@@ -107,9 +108,6 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, | |||
107 | offset = todo; | 108 | offset = todo; |
108 | } | 109 | } |
109 | offset += padding; | 110 | offset += padding; |
110 | /* If this line needs an interrupt, put it in */ | ||
111 | if (lpi && line > 0 && !(line % lpi)) | ||
112 | *(rp-2) |= RISC_INT_BIT; | ||
113 | } | 111 | } |
114 | 112 | ||
115 | return rp; | 113 | return rp; |
@@ -118,25 +116,25 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, | |||
118 | /** | 116 | /** |
119 | * tw68_risc_buffer | 117 | * tw68_risc_buffer |
120 | * | 118 | * |
121 | * This routine is called by tw68-video. It allocates | 119 | * This routine is called by tw68-video. It allocates |
122 | * memory for the dma controller "program" and then fills in that | 120 | * memory for the dma controller "program" and then fills in that |
123 | * memory with the appropriate "instructions". | 121 | * memory with the appropriate "instructions". |
124 | * | 122 | * |
125 | * @pci_dev structure with info about the pci | 123 | * @pci_dev structure with info about the pci |
126 | * slot which our device is in. | 124 | * slot which our device is in. |
127 | * @risc structure with info about the memory | 125 | * @risc structure with info about the memory |
128 | * used for our controller program. | 126 | * used for our controller program. |
129 | * @sglist scatter-gather list entry | 127 | * @sglist scatter-gather list entry |
130 | * @top_offset offset within the risc program area for the | 128 | * @top_offset offset within the risc program area for the |
131 | * first odd frame line | 129 | * first odd frame line |
132 | * @bottom_offset offset within the risc program area for the | 130 | * @bottom_offset offset within the risc program area for the |
133 | * first even frame line | 131 | * first even frame line |
134 | * @bpl number of data bytes per scan line | 132 | * @bpl number of data bytes per scan line |
135 | * @padding number of extra bytes to add at end of line | 133 | * @padding number of extra bytes to add at end of line |
136 | * @lines number of scan lines | 134 | * @lines number of scan lines |
137 | */ | 135 | */ |
138 | int tw68_risc_buffer(struct pci_dev *pci, | 136 | int tw68_risc_buffer(struct pci_dev *pci, |
139 | struct btcx_riscmem *risc, | 137 | struct tw68_buf *buf, |
140 | struct scatterlist *sglist, | 138 | struct scatterlist *sglist, |
141 | unsigned int top_offset, | 139 | unsigned int top_offset, |
142 | unsigned int bottom_offset, | 140 | unsigned int bottom_offset, |
@@ -146,7 +144,6 @@ int tw68_risc_buffer(struct pci_dev *pci, | |||
146 | { | 144 | { |
147 | u32 instructions, fields; | 145 | u32 instructions, fields; |
148 | __le32 *rp; | 146 | __le32 *rp; |
149 | int rc; | ||
150 | 147 | ||
151 | fields = 0; | 148 | fields = 0; |
152 | if (UNSET != top_offset) | 149 | if (UNSET != top_offset) |
@@ -155,29 +152,31 @@ int tw68_risc_buffer(struct pci_dev *pci, | |||
155 | fields++; | 152 | fields++; |
156 | /* | 153 | /* |
157 | * estimate risc mem: worst case is one write per page border + | 154 | * estimate risc mem: worst case is one write per page border + |
158 | * one write per scan line + syncs + jump (all 2 dwords). | 155 | * one write per scan line + syncs + 2 jumps (all 2 dwords). |
159 | * Padding can cause next bpl to start close to a page border. | 156 | * Padding can cause next bpl to start close to a page border. |
160 | * First DMA region may be smaller than PAGE_SIZE | 157 | * First DMA region may be smaller than PAGE_SIZE |
161 | */ | 158 | */ |
162 | instructions = fields * (1 + (((bpl + padding) * lines) / | 159 | instructions = fields * (1 + (((bpl + padding) * lines) / |
163 | PAGE_SIZE) + lines) + 2; | 160 | PAGE_SIZE) + lines) + 4; |
164 | rc = btcx_riscmem_alloc(pci, risc, instructions * 8); | 161 | buf->size = instructions * 8; |
165 | if (rc < 0) | 162 | buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma); |
166 | return rc; | 163 | if (buf->cpu == NULL) |
164 | return -ENOMEM; | ||
167 | 165 | ||
168 | /* write risc instructions */ | 166 | /* write risc instructions */ |
169 | rp = risc->cpu; | 167 | rp = buf->cpu; |
170 | if (UNSET != top_offset) /* generates SYNCO */ | 168 | if (UNSET != top_offset) /* generates SYNCO */ |
171 | rp = tw68_risc_field(rp, sglist, top_offset, 1, | 169 | rp = tw68_risc_field(rp, sglist, top_offset, 1, |
172 | bpl, padding, lines, 0); | 170 | bpl, padding, lines, true); |
173 | if (UNSET != bottom_offset) /* generates SYNCE */ | 171 | if (UNSET != bottom_offset) /* generates SYNCE */ |
174 | rp = tw68_risc_field(rp, sglist, bottom_offset, 2, | 172 | rp = tw68_risc_field(rp, sglist, bottom_offset, 2, |
175 | bpl, padding, lines, 0); | 173 | bpl, padding, lines, top_offset == UNSET); |
176 | 174 | ||
177 | /* save pointer to jmp instruction address */ | 175 | /* save pointer to jmp instruction address */ |
178 | risc->jmp = rp; | 176 | buf->jmp = rp; |
177 | buf->cpu[1] = cpu_to_le32(buf->dma + 8); | ||
179 | /* assure risc buffer hasn't overflowed */ | 178 | /* assure risc buffer hasn't overflowed */ |
180 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | 179 | BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size); |
181 | return 0; | 180 | return 0; |
182 | } | 181 | } |
183 | 182 | ||
@@ -204,65 +203,28 @@ static void tw68_risc_decode(u32 risc, u32 addr) | |||
204 | 203 | ||
205 | p = RISC_OP(risc); | 204 | p = RISC_OP(risc); |
206 | if (!(risc & 0x80000000) || !instr[p].name) { | 205 | if (!(risc & 0x80000000) || !instr[p].name) { |
207 | printk(KERN_DEBUG "0x%08x [ INVALID ]\n", risc); | 206 | pr_debug("0x%08x [ INVALID ]\n", risc); |
208 | return; | 207 | return; |
209 | } | 208 | } |
210 | printk(KERN_DEBUG "0x%08x %-9s IRQ=%d", | 209 | pr_debug("0x%08x %-9s IRQ=%d", |
211 | risc, instr[p].name, (risc >> 27) & 1); | 210 | risc, instr[p].name, (risc >> 27) & 1); |
212 | if (instr[p].has_data_type) | 211 | if (instr[p].has_data_type) |
213 | printk(KERN_DEBUG " Type=%d", (risc >> 24) & 7); | 212 | pr_debug(" Type=%d", (risc >> 24) & 7); |
214 | if (instr[p].has_byte_info) | 213 | if (instr[p].has_byte_info) |
215 | printk(KERN_DEBUG " Start=0x%03x Count=%03u", | 214 | pr_debug(" Start=0x%03x Count=%03u", |
216 | (risc >> 12) & 0xfff, risc & 0xfff); | 215 | (risc >> 12) & 0xfff, risc & 0xfff); |
217 | if (instr[p].has_addr) | 216 | if (instr[p].has_addr) |
218 | printk(KERN_DEBUG " StartAddr=0x%08x", addr); | 217 | pr_debug(" StartAddr=0x%08x", addr); |
219 | printk(KERN_DEBUG "\n"); | 218 | pr_debug("\n"); |
220 | } | 219 | } |
221 | 220 | ||
222 | void tw68_risc_program_dump(struct tw68_core *core, | 221 | void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf) |
223 | struct btcx_riscmem *risc) | ||
224 | { | 222 | { |
225 | __le32 *addr; | 223 | const __le32 *addr; |
226 | 224 | ||
227 | printk(KERN_DEBUG "%s: risc_program_dump: risc=%p, " | 225 | pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n", |
228 | "risc->cpu=0x%p, risc->jmp=0x%p\n", | 226 | core->name, buf, buf->cpu, buf->jmp); |
229 | core->name, risc, risc->cpu, risc->jmp); | 227 | for (addr = buf->cpu; addr <= buf->jmp; addr += 2) |
230 | for (addr = risc->cpu; addr <= risc->jmp; addr += 2) | ||
231 | tw68_risc_decode(*addr, *(addr+1)); | 228 | tw68_risc_decode(*addr, *(addr+1)); |
232 | } | 229 | } |
233 | EXPORT_SYMBOL_GPL(tw68_risc_program_dump); | ||
234 | #endif | 230 | #endif |
235 | |||
236 | /* | ||
237 | * tw68_risc_stopper | ||
238 | * Normally, the risc code generated for a buffer ends with a | ||
239 | * JUMP instruction to direct the DMAP processor to the code for | ||
240 | * the next buffer. However, when there is no additional buffer | ||
241 | * currently available, the code instead jumps to this routine. | ||
242 | * | ||
243 | * My first try for a "stopper" program was just a simple | ||
244 | * "jump to self" instruction. Unfortunately, this caused the | ||
245 | * video FIFO to overflow. My next attempt was to just disable | ||
246 | * the DMAP processor. Unfortunately, this caused the video | ||
247 | * decoder to lose its synchronization. The solution to this was to | ||
248 | * add a "Sync-Odd" instruction, which "eats" all the video data | ||
249 | * until the start of the next odd field. | ||
250 | */ | ||
251 | int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc) | ||
252 | { | ||
253 | __le32 *rp; | ||
254 | int rc; | ||
255 | |||
256 | rc = btcx_riscmem_alloc(pci, risc, 8*4); | ||
257 | if (rc < 0) | ||
258 | return rc; | ||
259 | |||
260 | /* write risc inststructions */ | ||
261 | rp = risc->cpu; | ||
262 | *(rp++) = cpu_to_le32(RISC_SYNCO); | ||
263 | *(rp++) = 0; | ||
264 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
265 | *(rp++) = cpu_to_le32(risc->dma); | ||
266 | risc->jmp = risc->cpu; | ||
267 | return 0; | ||
268 | } | ||
diff --git a/drivers/media/pci/tw68/tw68-ts.c b/drivers/media/pci/tw68/tw68-ts.c deleted file mode 100644 index dacd6e621bae..000000000000 --- a/drivers/media/pci/tw68/tw68-ts.c +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /* | ||
2 | * tw68_ts.c | ||
3 | * Part of the device driver for Techwell 68xx based cards | ||
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 "tw68.h" | ||
30 | |||
31 | int tw68_ts_init1(struct tw68_dev *dev) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | int tw68_ts_ini(struct tw68_dev *dev) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | int tw68_ts_fini(struct tw68_dev *dev) | ||
42 | { | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status) | ||
47 | { | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | int tw68_ts_register(struct tw68_mpeg_ops *ops) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | void tw68_ts_unregister(struct tw68_mpeg_ops *ops) | ||
57 | { | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | int tw68_ts_init_hw(struct tw68_dev *dev) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | |||
diff --git a/drivers/media/pci/tw68/tw68-tvaudio.c b/drivers/media/pci/tw68/tw68-tvaudio.c deleted file mode 100644 index 656d462196f4..000000000000 --- a/drivers/media/pci/tw68/tw68-tvaudio.c +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | /* | ||
2 | * tw68_controls.c | ||
3 | * Part of the device driver for Techwell 68xx based cards | ||
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 "tw68.h" | ||
30 | |||
31 | int tw68_tvaudio_rx2mode(u32 rx) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | void tw68_tvaudio_setmute(struct tw68_dev *dev) | ||
37 | { | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | void tw68_tvaudio_setinput(struct tw68_dev *dev, struct tw68_input *in) | ||
42 | { | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level) | ||
47 | { | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | int tw68_tvaudio_getstereo(struct tw68_dev *dev) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | void tw68_tvaudio_init(struct tw68_dev *dev) | ||
57 | { | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | int tw68_tvaudio_init2(struct tw68_dev *dev) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | int tw68_tvaudio_fini(struct tw68_dev *dev) | ||
67 | { | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int tw68_tvaudio_do_scan(struct tw68_dev *dev) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | void tw68_enable_i2s(struct tw68_dev *dev) | ||
77 | { | ||
78 | return; | ||
79 | } | ||
80 | |||
diff --git a/drivers/media/pci/tw68/tw68-vbi.c b/drivers/media/pci/tw68/tw68-vbi.c deleted file mode 100644 index fbad3b998848..000000000000 --- a/drivers/media/pci/tw68/tw68-vbi.c +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /* | ||
2 | * tw68_controls.c | ||
3 | * Part of the device driver for Techwell 68xx based cards | ||
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 "tw68.h" | ||
30 | |||
31 | static int buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
32 | unsigned int *size) { | ||
33 | printk(KERN_INFO "%s: shouldn't be here!\n", __func__); | ||
34 | return 0; | ||
35 | } | ||
36 | static int buffer_prepare(struct videobuf_queue *q, | ||
37 | struct videobuf_buffer *vb, | ||
38 | enum v4l2_field field) | ||
39 | { | ||
40 | printk(KERN_INFO "%s: shouldn't be here!\n", __func__); | ||
41 | return 0; | ||
42 | } | ||
43 | static void buffer_queue(struct videobuf_queue *q, | ||
44 | struct videobuf_buffer *vb) | ||
45 | { | ||
46 | printk(KERN_INFO "%s: shouldn't be here!\n", __func__); | ||
47 | } | ||
48 | static void buffer_release(struct videobuf_queue *q, | ||
49 | struct videobuf_buffer *vb) | ||
50 | { | ||
51 | printk(KERN_INFO "%s: shouldn't be here!\n", __func__); | ||
52 | } | ||
53 | struct videobuf_queue_ops tw68_vbi_qops = { | ||
54 | .buf_setup = buffer_setup, | ||
55 | .buf_prepare = buffer_prepare, | ||
56 | .buf_queue = buffer_queue, | ||
57 | .buf_release = buffer_release, | ||
58 | }; | ||
59 | |||
60 | /* ------------------------------------------------------------------ */ | ||
61 | |||
62 | int tw68_vbi_init1(struct tw68_dev *dev) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | int tw68_vbi_fini(struct tw68_dev *dev) | ||
68 | { | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status) | ||
73 | { | ||
74 | return; | ||
75 | } | ||
76 | |||
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index ca08ca38d3bd..66fae2345fdd 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c | |||
@@ -8,7 +8,11 @@ | |||
8 | * acknowledged. Full credit goes to them - any problems within this code | 8 | * acknowledged. Full credit goes to them - any problems within this code |
9 | * are mine. | 9 | * are mine. |
10 | * | 10 | * |
11 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | 11 | * Copyright (C) 2009 William M. Brack |
12 | * | ||
13 | * Refactored and updated to the latest v4l core frameworks: | ||
14 | * | ||
15 | * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> | ||
12 | * | 16 | * |
13 | * This program is free software; you can redistribute it and/or modify | 17 | * 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 | 18 | * it under the terms of the GNU General Public License as published by |
@@ -19,39 +23,16 @@ | |||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 25 | * GNU General Public License for more details. |
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <media/v4l2-common.h> | 29 | #include <media/v4l2-common.h> |
30 | #include <linux/sort.h> | 30 | #include <media/v4l2-event.h> |
31 | #include <media/videobuf2-dma-sg.h> | ||
31 | 32 | ||
32 | #include "tw68.h" | 33 | #include "tw68.h" |
33 | #include "tw68-reg.h" | 34 | #include "tw68-reg.h" |
34 | 35 | ||
35 | unsigned int video_debug; | ||
36 | |||
37 | static unsigned int gbuffers = 8; | ||
38 | static unsigned int noninterlaced; /* 0 */ | ||
39 | static unsigned int gbufsz = 768*576*4; | ||
40 | static unsigned int gbufsz_max = 768*576*4; | ||
41 | static char secam[] = "--"; | ||
42 | |||
43 | module_param(video_debug, int, 0644); | ||
44 | MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); | ||
45 | module_param(gbuffers, int, 0444); | ||
46 | MODULE_PARM_DESC(gbuffers, "number of capture buffers, range 2-32"); | ||
47 | module_param(noninterlaced, int, 0644); | ||
48 | MODULE_PARM_DESC(noninterlaced, "capture non interlaced video"); | ||
49 | module_param_string(secam, secam, sizeof(secam), 0644); | ||
50 | MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); | ||
51 | |||
52 | #define dprintk(level, fmt, arg...) if (video_debug & (level)) \ | ||
53 | printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) | ||
54 | |||
55 | /* ------------------------------------------------------------------ */ | 36 | /* ------------------------------------------------------------------ */ |
56 | /* data structs for video */ | 37 | /* data structs for video */ |
57 | /* | 38 | /* |
@@ -60,7 +41,7 @@ MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); | |||
60 | * as "planar". These affect overlay mode, and are flagged with a field | 41 | * as "planar". These affect overlay mode, and are flagged with a field |
61 | * ".planar" in the format. Do we need to implement this in this driver? | 42 | * ".planar" in the format. Do we need to implement this in this driver? |
62 | */ | 43 | */ |
63 | static struct tw68_format formats[] = { | 44 | static const struct tw68_format formats[] = { |
64 | { | 45 | { |
65 | .name = "15 bpp RGB, le", | 46 | .name = "15 bpp RGB, le", |
66 | .fourcc = V4L2_PIX_FMT_RGB555, | 47 | .fourcc = V4L2_PIX_FMT_RGB555, |
@@ -145,47 +126,8 @@ static struct tw68_format formats[] = { | |||
145 | * match, then for an entry which contains the desired id. The table | 126 | * match, then for an entry which contains the desired id. The table |
146 | * entries should therefore be ordered in ascending order of specificity. | 127 | * entries should therefore be ordered in ascending order of specificity. |
147 | */ | 128 | */ |
148 | static struct tw68_tvnorm tvnorms[] = { | 129 | static const struct tw68_tvnorm tvnorms[] = { |
149 | { | 130 | { |
150 | .name = "PAL-BG", | ||
151 | .id = V4L2_STD_PAL_BG, | ||
152 | NORM_625_50, | ||
153 | |||
154 | .sync_control = 0x18, | ||
155 | .luma_control = 0x40, | ||
156 | .chroma_ctrl1 = 0x81, | ||
157 | .chroma_gain = 0x2a, | ||
158 | .chroma_ctrl2 = 0x06, | ||
159 | .vgate_misc = 0x1c, | ||
160 | .format = VideoFormatPALBDGHI, | ||
161 | |||
162 | }, { | ||
163 | .name = "PAL-I", | ||
164 | .id = V4L2_STD_PAL_I, | ||
165 | NORM_625_50, | ||
166 | |||
167 | .sync_control = 0x18, | ||
168 | .luma_control = 0x40, | ||
169 | .chroma_ctrl1 = 0x81, | ||
170 | .chroma_gain = 0x2a, | ||
171 | .chroma_ctrl2 = 0x06, | ||
172 | .vgate_misc = 0x1c, | ||
173 | .format = VideoFormatPALBDGHI, | ||
174 | |||
175 | }, { | ||
176 | .name = "PAL-DK", | ||
177 | .id = V4L2_STD_PAL_DK, | ||
178 | NORM_625_50, | ||
179 | |||
180 | .sync_control = 0x18, | ||
181 | .luma_control = 0x40, | ||
182 | .chroma_ctrl1 = 0x81, | ||
183 | .chroma_gain = 0x2a, | ||
184 | .chroma_ctrl2 = 0x06, | ||
185 | .vgate_misc = 0x1c, | ||
186 | .format = VideoFormatPALBDGHI, | ||
187 | |||
188 | }, { | ||
189 | .name = "PAL", /* autodetect */ | 131 | .name = "PAL", /* autodetect */ |
190 | .id = V4L2_STD_PAL, | 132 | .id = V4L2_STD_PAL, |
191 | NORM_625_50, | 133 | NORM_625_50, |
@@ -197,7 +139,6 @@ static struct tw68_tvnorm tvnorms[] = { | |||
197 | .chroma_ctrl2 = 0x06, | 139 | .chroma_ctrl2 = 0x06, |
198 | .vgate_misc = 0x1c, | 140 | .vgate_misc = 0x1c, |
199 | .format = VideoFormatPALBDGHI, | 141 | .format = VideoFormatPALBDGHI, |
200 | |||
201 | }, { | 142 | }, { |
202 | .name = "NTSC", | 143 | .name = "NTSC", |
203 | .id = V4L2_STD_NTSC, | 144 | .id = V4L2_STD_NTSC, |
@@ -210,46 +151,6 @@ static struct tw68_tvnorm tvnorms[] = { | |||
210 | .chroma_ctrl2 = 0x0e, | 151 | .chroma_ctrl2 = 0x0e, |
211 | .vgate_misc = 0x18, | 152 | .vgate_misc = 0x18, |
212 | .format = VideoFormatNTSC, | 153 | .format = VideoFormatNTSC, |
213 | |||
214 | }, { | ||
215 | .name = "SECAM-DK", | ||
216 | .id = V4L2_STD_SECAM_DK, | ||
217 | NORM_625_50, | ||
218 | |||
219 | .sync_control = 0x18, | ||
220 | .luma_control = 0x1b, | ||
221 | .chroma_ctrl1 = 0xd1, | ||
222 | .chroma_gain = 0x80, | ||
223 | .chroma_ctrl2 = 0x00, | ||
224 | .vgate_misc = 0x1c, | ||
225 | .format = VideoFormatSECAM, | ||
226 | |||
227 | }, { | ||
228 | .name = "SECAM-L", | ||
229 | .id = V4L2_STD_SECAM_L, | ||
230 | NORM_625_50, | ||
231 | |||
232 | .sync_control = 0x18, | ||
233 | .luma_control = 0x1b, | ||
234 | .chroma_ctrl1 = 0xd1, | ||
235 | .chroma_gain = 0x80, | ||
236 | .chroma_ctrl2 = 0x00, | ||
237 | .vgate_misc = 0x1c, | ||
238 | .format = VideoFormatSECAM, | ||
239 | |||
240 | }, { | ||
241 | .name = "SECAM-LC", | ||
242 | .id = V4L2_STD_SECAM_LC, | ||
243 | NORM_625_50, | ||
244 | |||
245 | .sync_control = 0x18, | ||
246 | .luma_control = 0x1b, | ||
247 | .chroma_ctrl1 = 0xd1, | ||
248 | .chroma_gain = 0x80, | ||
249 | .chroma_ctrl2 = 0x00, | ||
250 | .vgate_misc = 0x1c, | ||
251 | .format = VideoFormatSECAM, | ||
252 | |||
253 | }, { | 154 | }, { |
254 | .name = "SECAM", | 155 | .name = "SECAM", |
255 | .id = V4L2_STD_SECAM, | 156 | .id = V4L2_STD_SECAM, |
@@ -262,7 +163,6 @@ static struct tw68_tvnorm tvnorms[] = { | |||
262 | .chroma_ctrl2 = 0x00, | 163 | .chroma_ctrl2 = 0x00, |
263 | .vgate_misc = 0x1c, | 164 | .vgate_misc = 0x1c, |
264 | .format = VideoFormatSECAM, | 165 | .format = VideoFormatSECAM, |
265 | |||
266 | }, { | 166 | }, { |
267 | .name = "PAL-M", | 167 | .name = "PAL-M", |
268 | .id = V4L2_STD_PAL_M, | 168 | .id = V4L2_STD_PAL_M, |
@@ -275,7 +175,6 @@ static struct tw68_tvnorm tvnorms[] = { | |||
275 | .chroma_ctrl2 = 0x0e, | 175 | .chroma_ctrl2 = 0x0e, |
276 | .vgate_misc = 0x18, | 176 | .vgate_misc = 0x18, |
277 | .format = VideoFormatPALM, | 177 | .format = VideoFormatPALM, |
278 | |||
279 | }, { | 178 | }, { |
280 | .name = "PAL-Nc", | 179 | .name = "PAL-Nc", |
281 | .id = V4L2_STD_PAL_Nc, | 180 | .id = V4L2_STD_PAL_Nc, |
@@ -288,7 +187,6 @@ static struct tw68_tvnorm tvnorms[] = { | |||
288 | .chroma_ctrl2 = 0x06, | 187 | .chroma_ctrl2 = 0x06, |
289 | .vgate_misc = 0x1c, | 188 | .vgate_misc = 0x1c, |
290 | .format = VideoFormatPALNC, | 189 | .format = VideoFormatPALNC, |
291 | |||
292 | }, { | 190 | }, { |
293 | .name = "PAL-60", | 191 | .name = "PAL-60", |
294 | .id = V4L2_STD_PAL_60, | 192 | .id = V4L2_STD_PAL_60, |
@@ -309,127 +207,11 @@ static struct tw68_tvnorm tvnorms[] = { | |||
309 | .chroma_ctrl2 = 0x06, | 207 | .chroma_ctrl2 = 0x06, |
310 | .vgate_misc = 0x1c, | 208 | .vgate_misc = 0x1c, |
311 | .format = VideoFormatPAL60, | 209 | .format = VideoFormatPAL60, |
312 | |||
313 | }, { | ||
314 | /* | ||
315 | * FIXME: The following are meant to be "catch-all", and need | ||
316 | * to be further thought out! | ||
317 | */ | ||
318 | .name = "STD-525-60", | ||
319 | .id = V4L2_STD_525_60, | ||
320 | NORM_525_60, | ||
321 | |||
322 | .sync_control = 0x59, | ||
323 | .luma_control = 0x40, | ||
324 | .chroma_ctrl1 = 0x89, | ||
325 | .chroma_gain = 0x2a, | ||
326 | .chroma_ctrl2 = 0x0e, | ||
327 | .vgate_misc = 0x18, | ||
328 | .format = VideoFormatNTSC, | ||
329 | |||
330 | }, { | ||
331 | .name = "STD-625-50", | ||
332 | .id = V4L2_STD_625_50, | ||
333 | NORM_625_50, | ||
334 | |||
335 | .sync_control = 0x18, | ||
336 | .luma_control = 0x40, | ||
337 | .chroma_ctrl1 = 0x81, | ||
338 | .chroma_gain = 0x2a, | ||
339 | .chroma_ctrl2 = 0x06, | ||
340 | .vgate_misc = 0x1c, | ||
341 | .format = VideoFormatPALBDGHI, | ||
342 | } | 210 | } |
343 | }; | 211 | }; |
344 | #define TVNORMS ARRAY_SIZE(tvnorms) | 212 | #define TVNORMS ARRAY_SIZE(tvnorms) |
345 | 213 | ||
346 | static const struct v4l2_queryctrl no_ctrl = { | 214 | static const struct tw68_format *format_by_fourcc(unsigned int fourcc) |
347 | .name = "42", | ||
348 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
349 | }; | ||
350 | static const struct v4l2_queryctrl video_ctrls[] = { | ||
351 | /* --- video --- */ | ||
352 | { | ||
353 | .id = V4L2_CID_BRIGHTNESS, | ||
354 | .name = "Brightness", | ||
355 | .minimum = -128, | ||
356 | .maximum = 127, | ||
357 | .step = 1, | ||
358 | .default_value = 20, | ||
359 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
360 | }, { | ||
361 | .id = V4L2_CID_CONTRAST, | ||
362 | .name = "Contrast", | ||
363 | .minimum = 0, | ||
364 | .maximum = 255, | ||
365 | .step = 1, | ||
366 | .default_value = 100, | ||
367 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
368 | }, { | ||
369 | .id = V4L2_CID_SATURATION, | ||
370 | .name = "Saturation", | ||
371 | .minimum = 0, | ||
372 | .maximum = 255, | ||
373 | .step = 1, | ||
374 | .default_value = 128, | ||
375 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
376 | }, { | ||
377 | .id = V4L2_CID_HUE, | ||
378 | .name = "Hue", | ||
379 | .minimum = -128, | ||
380 | .maximum = 127, | ||
381 | .step = 1, | ||
382 | .default_value = 0, | ||
383 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
384 | }, { | ||
385 | .id = V4L2_CID_COLOR_KILLER, | ||
386 | .name = "Color Killer", | ||
387 | .minimum = 0, | ||
388 | .maximum = 1, | ||
389 | .default_value = 1, | ||
390 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
391 | }, { | ||
392 | .id = V4L2_CID_CHROMA_AGC, | ||
393 | .name = "Chroma AGC", | ||
394 | .minimum = 0, | ||
395 | .maximum = 1, | ||
396 | .default_value = 1, | ||
397 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
398 | }, | ||
399 | /* --- audio --- */ | ||
400 | { | ||
401 | .id = V4L2_CID_AUDIO_MUTE, | ||
402 | .name = "Mute", | ||
403 | .minimum = 0, | ||
404 | .maximum = 1, | ||
405 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
406 | }, { | ||
407 | .id = V4L2_CID_AUDIO_VOLUME, | ||
408 | .name = "Volume", | ||
409 | .minimum = -15, | ||
410 | .maximum = 15, | ||
411 | .step = 1, | ||
412 | .default_value = 0, | ||
413 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
414 | } | ||
415 | }; | ||
416 | static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); | ||
417 | |||
418 | /* | ||
419 | * Routine to lookup a control by its ID, and return a pointer | ||
420 | * to the entry in the video_ctrls array for that control. | ||
421 | */ | ||
422 | static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) | ||
423 | { | ||
424 | unsigned int i; | ||
425 | |||
426 | for (i = 0; i < CTRLS; i++) | ||
427 | if (video_ctrls[i].id == id) | ||
428 | return video_ctrls+i; | ||
429 | return NULL; | ||
430 | } | ||
431 | |||
432 | static struct tw68_format *format_by_fourcc(unsigned int fourcc) | ||
433 | { | 215 | { |
434 | unsigned int i; | 216 | unsigned int i; |
435 | 217 | ||
@@ -439,99 +221,22 @@ static struct tw68_format *format_by_fourcc(unsigned int fourcc) | |||
439 | return NULL; | 221 | return NULL; |
440 | } | 222 | } |
441 | 223 | ||
442 | /* ----------------------------------------------------------------------- */ | ||
443 | /* resource management */ | ||
444 | |||
445 | static int res_get(struct tw68_fh *fh, unsigned int bit) | ||
446 | { | ||
447 | struct tw68_dev *dev = fh->dev; | ||
448 | |||
449 | if (fh->resources & bit) | ||
450 | /* have it already allocated */ | ||
451 | return 1; | ||
452 | |||
453 | /* is it free? */ | ||
454 | mutex_lock(&dev->lock); | ||
455 | if (dev->resources & bit) { | ||
456 | /* no, someone else uses it */ | ||
457 | mutex_unlock(&fh->dev->lock); | ||
458 | return 0; | ||
459 | } | ||
460 | /* it's free, grab it */ | ||
461 | fh->resources |= bit; | ||
462 | dev->resources |= bit; | ||
463 | dprintk(DBG_FLOW, "%s: %d\n", __func__, bit); | ||
464 | mutex_unlock(&dev->lock); | ||
465 | return 1; | ||
466 | } | ||
467 | |||
468 | static int res_check(struct tw68_fh *fh, unsigned int bit) | ||
469 | { | ||
470 | return fh->resources & bit; | ||
471 | } | ||
472 | |||
473 | static int res_locked(struct tw68_dev *dev, unsigned int bit) | ||
474 | { | ||
475 | return dev->resources & bit; | ||
476 | } | ||
477 | |||
478 | static void res_free(struct tw68_fh *fh, | ||
479 | unsigned int bits) | ||
480 | { | ||
481 | struct tw68_dev *dev = fh->dev; | ||
482 | |||
483 | BUG_ON((fh->resources & bits) != bits); | ||
484 | |||
485 | mutex_lock(&fh->dev->lock); | ||
486 | fh->resources &= ~bits; | ||
487 | fh->dev->resources &= ~bits; | ||
488 | dprintk(DBG_FLOW, "%s: %d\n", __func__, bits); | ||
489 | mutex_unlock(&fh->dev->lock); | ||
490 | } | ||
491 | 224 | ||
492 | /* ------------------------------------------------------------------ */ | 225 | /* ------------------------------------------------------------------ */ |
493 | /* | 226 | /* |
494 | * Note that the cropping rectangles are described in terms of a single | 227 | * Note that the cropping rectangles are described in terms of a single |
495 | * frame, i.e. line positions are only 1/2 the interlaced equivalent | 228 | * frame, i.e. line positions are only 1/2 the interlaced equivalent |
496 | */ | 229 | */ |
497 | static void set_tvnorm(struct tw68_dev *dev, struct tw68_tvnorm *norm) | 230 | static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm) |
498 | { | 231 | { |
499 | dprintk(DBG_FLOW, "%s: %s\n", __func__, norm->name); | ||
500 | dev->tvnorm = norm; | ||
501 | |||
502 | /* setup cropping */ | ||
503 | dev->crop_bounds.left = norm->h_start; | ||
504 | dev->crop_defrect.left = norm->h_start; | ||
505 | dev->crop_bounds.width = norm->h_stop - norm->h_start + 1; | ||
506 | dev->crop_defrect.width = norm->h_stop - norm->h_start + 1; | ||
507 | |||
508 | dev->crop_bounds.top = norm->video_v_start; | ||
509 | dev->crop_defrect.top = norm->video_v_start; | ||
510 | dev->crop_bounds.height = (((norm->id & V4L2_STD_525_60) ? | ||
511 | 524 : 624)) / 2 - dev->crop_bounds.top; | ||
512 | dev->crop_defrect.height = (norm->video_v_stop - | ||
513 | norm->video_v_start + 1); | ||
514 | |||
515 | dev->crop_current = dev->crop_defrect; | ||
516 | |||
517 | if (norm != dev->tvnorm) { | 232 | if (norm != dev->tvnorm) { |
233 | dev->width = 720; | ||
234 | dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576; | ||
518 | dev->tvnorm = norm; | 235 | dev->tvnorm = norm; |
519 | tw68_set_tvnorm_hw(dev); | 236 | tw68_set_tvnorm_hw(dev); |
520 | } | 237 | } |
521 | } | 238 | } |
522 | 239 | ||
523 | static void video_mux(struct tw68_dev *dev, int input) | ||
524 | { | ||
525 | dprintk(DBG_FLOW, "%s: input = %d [%s]\n", __func__, input, | ||
526 | card_in(dev, input).name); | ||
527 | /* | ||
528 | * dev->input shows current application request, | ||
529 | * dev->hw_input shows current hardware setting | ||
530 | */ | ||
531 | dev->input = &card_in(dev, input); | ||
532 | tw68_tvaudio_setinput(dev, &card_in(dev, input)); | ||
533 | } | ||
534 | |||
535 | /* | 240 | /* |
536 | * tw68_set_scale | 241 | * tw68_set_scale |
537 | * | 242 | * |
@@ -544,7 +249,7 @@ static void video_mux(struct tw68_dev *dev, int input) | |||
544 | * before scaling. HDELAY represents the number of pixels skipped | 249 | * before scaling. HDELAY represents the number of pixels skipped |
545 | * between the start of the horizontal sync and the start of the image. | 250 | * between the start of the horizontal sync and the start of the image. |
546 | * HSCALE is calculated using the formula | 251 | * HSCALE is calculated using the formula |
547 | * HSCALE = (HACTIVE / (#pixels desired)) * 256 | 252 | * HSCALE = (HACTIVE / (#pixels desired)) * 256 |
548 | * | 253 | * |
549 | * The vertical registers are similar, except based upon the total number | 254 | * The vertical registers are similar, except based upon the total number |
550 | * of lines in the image, and the first line of the image (i.e. ignoring | 255 | * of lines in the image, and the first line of the image (i.e. ignoring |
@@ -555,16 +260,16 @@ static void video_mux(struct tw68_dev *dev, int input) | |||
555 | * these values, especially HSCALE. | 260 | * these values, especially HSCALE. |
556 | * | 261 | * |
557 | * Parameters: | 262 | * Parameters: |
558 | * @dev pointer to the device structure, needed for | 263 | * @dev pointer to the device structure, needed for |
559 | * getting current norm (as well as debug print) | 264 | * getting current norm (as well as debug print) |
560 | * @width actual image width (from user buffer) | 265 | * @width actual image width (from user buffer) |
561 | * @height actual image height | 266 | * @height actual image height |
562 | * @field indicates Top, Bottom or Interlaced | 267 | * @field indicates Top, Bottom or Interlaced |
563 | */ | 268 | */ |
564 | static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, | 269 | static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, |
565 | unsigned int height, enum v4l2_field field) | 270 | unsigned int height, enum v4l2_field field) |
566 | { | 271 | { |
567 | 272 | const struct tw68_tvnorm *norm = dev->tvnorm; | |
568 | /* set individually for debugging clarity */ | 273 | /* set individually for debugging clarity */ |
569 | int hactive, hdelay, hscale; | 274 | int hactive, hdelay, hscale; |
570 | int vactive, vdelay, vscale; | 275 | int vactive, vdelay, vscale; |
@@ -573,41 +278,38 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, | |||
573 | if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */ | 278 | if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */ |
574 | height /= 2; /* we must set for 1-frame */ | 279 | height /= 2; /* we must set for 1-frame */ |
575 | 280 | ||
576 | dprintk(DBG_FLOW, "%s: width=%d, height=%d, both=%d\n Crop rect: " | 281 | pr_debug("%s: width=%d, height=%d, both=%d\n" |
577 | "top=%d, left=%d, width=%d height=%d\n" | 282 | " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " |
578 | " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " | 283 | "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, |
579 | "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, | ||
580 | width, height, V4L2_FIELD_HAS_BOTH(field), | 284 | width, height, V4L2_FIELD_HAS_BOTH(field), |
581 | dev->crop_bounds.top, dev->crop_bounds.left, | 285 | norm->h_delay, norm->h_start, norm->h_stop, |
582 | dev->crop_bounds.width, dev->crop_bounds.height, | 286 | norm->v_delay, norm->video_v_start, |
583 | dev->tvnorm->h_delay, dev->tvnorm->h_start, dev->tvnorm->h_stop, | 287 | norm->video_v_stop); |
584 | dev->tvnorm->v_delay, dev->tvnorm->video_v_start, | ||
585 | dev->tvnorm->video_v_stop); | ||
586 | 288 | ||
587 | switch (dev->vdecoder) { | 289 | switch (dev->vdecoder) { |
588 | case TW6800: | 290 | case TW6800: |
589 | hdelay = dev->tvnorm->h_delay0; | 291 | hdelay = norm->h_delay0; |
590 | break; | 292 | break; |
591 | default: | 293 | default: |
592 | hdelay = dev->tvnorm->h_delay; | 294 | hdelay = norm->h_delay; |
593 | break; | 295 | break; |
594 | } | 296 | } |
595 | hdelay += dev->crop_bounds.left; | 297 | |
596 | hactive = dev->crop_bounds.width; | 298 | hdelay += norm->h_start; |
299 | hactive = norm->h_stop - norm->h_start + 1; | ||
597 | 300 | ||
598 | hscale = (hactive * 256) / (width); | 301 | hscale = (hactive * 256) / (width); |
599 | 302 | ||
600 | vdelay = dev->tvnorm->v_delay + dev->crop_bounds.top - | 303 | vdelay = norm->v_delay; |
601 | dev->crop_defrect.top; | 304 | vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start; |
602 | vactive = dev->crop_bounds.height; | ||
603 | vscale = (vactive * 256) / height; | 305 | vscale = (vactive * 256) / height; |
604 | 306 | ||
605 | dprintk(DBG_FLOW, "%s: %dx%d [%s%s,%s]\n", __func__, | 307 | pr_debug("%s: %dx%d [%s%s,%s]\n", __func__, |
606 | width, height, | 308 | width, height, |
607 | V4L2_FIELD_HAS_TOP(field) ? "T" : "", | 309 | V4L2_FIELD_HAS_TOP(field) ? "T" : "", |
608 | V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", | 310 | V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", |
609 | v4l2_norm_to_name(dev->tvnorm->id)); | 311 | v4l2_norm_to_name(dev->tvnorm->id)); |
610 | dprintk(DBG_FLOW, "%s: hactive=%d, hdelay=%d, hscale=%d; " | 312 | pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; " |
611 | "vactive=%d, vdelay=%d, vscale=%d\n", __func__, | 313 | "vactive=%d, vdelay=%d, vscale=%d\n", __func__, |
612 | hactive, hdelay, hscale, vactive, vdelay, vscale); | 314 | hactive, hdelay, hscale, vactive, vdelay, vscale); |
613 | 315 | ||
@@ -615,7 +317,7 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, | |||
615 | ((vactive & 0x300) >> 4) | | 317 | ((vactive & 0x300) >> 4) | |
616 | ((hdelay & 0x300) >> 6) | | 318 | ((hdelay & 0x300) >> 6) | |
617 | ((hactive & 0x300) >> 8); | 319 | ((hactive & 0x300) >> 8); |
618 | dprintk(DBG_FLOW, "%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " | 320 | pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " |
619 | "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", | 321 | "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", |
620 | __func__, comb, vdelay, vactive, hdelay, hactive); | 322 | __func__, comb, vdelay, vactive, hdelay, hactive); |
621 | tw_writeb(TW68_CROP_HI, comb); | 323 | tw_writeb(TW68_CROP_HI, comb); |
@@ -625,7 +327,7 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, | |||
625 | tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); | 327 | tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); |
626 | 328 | ||
627 | comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); | 329 | comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); |
628 | dprintk(DBG_FLOW, "%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " | 330 | pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " |
629 | "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); | 331 | "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); |
630 | tw_writeb(TW68_SCALE_HI, comb); | 332 | tw_writeb(TW68_SCALE_HI, comb); |
631 | tw_writeb(TW68_VSCALE_LO, vscale); | 333 | tw_writeb(TW68_VSCALE_LO, vscale); |
@@ -636,28 +338,21 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, | |||
636 | 338 | ||
637 | /* ------------------------------------------------------------------ */ | 339 | /* ------------------------------------------------------------------ */ |
638 | 340 | ||
639 | static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, | 341 | int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) |
640 | struct tw68_buf *buf) { | 342 | { |
641 | |||
642 | dprintk(DBG_FLOW, "%s: Starting risc program\n", __func__); | ||
643 | /* Assure correct input */ | ||
644 | if (dev->hw_input != dev->input) { | ||
645 | dev->hw_input = dev->input; | ||
646 | tw_andorb(TW68_INFORM, 0x03 << 2, dev->input->vmux << 2); | ||
647 | } | ||
648 | /* Set cropping and scaling */ | 343 | /* Set cropping and scaling */ |
649 | tw68_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); | 344 | tw68_set_scale(dev, dev->width, dev->height, dev->field); |
650 | /* | 345 | /* |
651 | * Set start address for RISC program. Note that if the DMAP | 346 | * Set start address for RISC program. Note that if the DMAP |
652 | * processor is currently running, it must be stopped before | 347 | * processor is currently running, it must be stopped before |
653 | * a new address can be set. | 348 | * a new address can be set. |
654 | */ | 349 | */ |
655 | tw_clearl(TW68_DMAC, TW68_DMAP_EN); | 350 | tw_clearl(TW68_DMAC, TW68_DMAP_EN); |
656 | tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->risc.dma)); | 351 | tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->dma)); |
657 | /* Clear any pending interrupts */ | 352 | /* Clear any pending interrupts */ |
658 | tw_writel(TW68_INTSTAT, dev->board_virqmask); | 353 | tw_writel(TW68_INTSTAT, dev->board_virqmask); |
659 | /* Enable the risc engine and the fifo */ | 354 | /* Enable the risc engine and the fifo */ |
660 | tw_andorl(TW68_DMAC, 0xff, buf->fmt->twformat | | 355 | tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat | |
661 | ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN); | 356 | ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN); |
662 | dev->pci_irqmask |= dev->board_virqmask; | 357 | dev->pci_irqmask |= dev->board_virqmask; |
663 | tw_setl(TW68_INTMASK, dev->pci_irqmask); | 358 | tw_setl(TW68_INTMASK, dev->pci_irqmask); |
@@ -665,638 +360,244 @@ static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, | |||
665 | } | 360 | } |
666 | 361 | ||
667 | /* ------------------------------------------------------------------ */ | 362 | /* ------------------------------------------------------------------ */ |
668 | /* videobuf queue operations */ | ||
669 | 363 | ||
670 | /* | 364 | /* nr of (tw68-)pages for the given buffer size */ |
671 | * check_buf_fmt | 365 | static int tw68_buffer_pages(int size) |
672 | * | ||
673 | * callback from tw68-core buffer_queue to determine whether the | ||
674 | * current buffer and the previous one are "compatible" (i.e. the | ||
675 | * risc programs can be chained without requiring a format change) | ||
676 | */ | ||
677 | static int tw68_check_video_fmt(struct tw68_buf *prev, struct tw68_buf *buf) | ||
678 | { | 366 | { |
679 | return (prev->vb.width == buf->vb.width && | 367 | size = PAGE_ALIGN(size); |
680 | prev->vb.height == buf->vb.height && | 368 | size += PAGE_SIZE; /* for non-page-aligned buffers */ |
681 | prev->fmt == buf->fmt); | 369 | size /= 4096; |
370 | return size; | ||
682 | } | 371 | } |
683 | 372 | ||
684 | /* | 373 | /* calc max # of buffers from size (must not exceed the 4MB virtual |
685 | * buffer_setup | 374 | * address space per DMA channel) */ |
686 | * | 375 | static int tw68_buffer_count(unsigned int size, unsigned int count) |
687 | * Calculate required size of buffer and maximum number allowed | ||
688 | */ | ||
689 | static int | ||
690 | buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
691 | unsigned int *size) | ||
692 | { | 376 | { |
693 | struct tw68_fh *fh = q->priv_data; | 377 | unsigned int maxcount; |
694 | 378 | ||
695 | *size = fh->fmt->depth * fh->width * fh->height >> 3; | 379 | maxcount = 1024 / tw68_buffer_pages(size); |
696 | if (0 == *count) | 380 | if (count > maxcount) |
697 | *count = gbuffers; | 381 | count = maxcount; |
698 | *count = tw68_buffer_count(*size, *count); | 382 | return count; |
699 | return 0; | ||
700 | } | 383 | } |
701 | 384 | ||
702 | static int buffer_activate(struct tw68_dev *dev, struct tw68_buf *buf, | 385 | /* ------------------------------------------------------------- */ |
703 | struct tw68_buf *next) | 386 | /* vb2 queue operations */ |
704 | { | ||
705 | dprintk(DBG_BUFF, "%s: dev=%p, buf=%p, next=%p\n", | ||
706 | __func__, dev, buf, next); | ||
707 | if (dev->hw_input != dev->input) { | ||
708 | dev->hw_input = dev->input; | ||
709 | tw_andorb(TW68_INFORM, 0x03 << 2, | ||
710 | dev->hw_input->vmux << 2); | ||
711 | } | ||
712 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
713 | /* TODO - need to assure scaling/cropping are set correctly */ | ||
714 | mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); | ||
715 | return 0; | ||
716 | } | ||
717 | 387 | ||
718 | /* | 388 | static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, |
719 | * buffer_prepare | 389 | unsigned int *num_buffers, unsigned int *num_planes, |
720 | * | 390 | unsigned int sizes[], void *alloc_ctxs[]) |
721 | * Set the ancilliary information into the buffer structure. This | ||
722 | * includes generating the necessary risc program if it hasn't already | ||
723 | * been done for the current buffer format. | ||
724 | * The structure fh contains the details of the format requested by the | ||
725 | * user - type, width, height and #fields. This is compared with the | ||
726 | * last format set for the current buffer. If they differ, the risc | ||
727 | * code (which controls the filling of the buffer) is (re-)generated. | ||
728 | */ | ||
729 | static int | ||
730 | buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
731 | enum v4l2_field field) | ||
732 | { | 391 | { |
733 | struct tw68_fh *fh = q->priv_data; | 392 | struct tw68_dev *dev = vb2_get_drv_priv(q); |
734 | struct tw68_dev *dev = fh->dev; | 393 | unsigned tot_bufs = q->num_buffers + *num_buffers; |
735 | struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); | ||
736 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
737 | int rc, init_buffer = 0; | ||
738 | unsigned int maxw, maxh; | ||
739 | |||
740 | BUG_ON(NULL == fh->fmt); | ||
741 | maxw = dev->tvnorm->h_stop - dev->tvnorm->h_start + 1; | ||
742 | maxh = 2*(dev->tvnorm->video_v_stop - dev->tvnorm->video_v_start + 1); | ||
743 | if (fh->width < 48 || fh->width > maxw || fh->height > maxh | ||
744 | || fh->height < 16) { | ||
745 | dprintk(DBG_UNEXPECTED, "%s: invalid dimensions - " | ||
746 | "fh->width=%d, fh->height=%d, maxw=%d, maxh=%d\n", | ||
747 | __func__, fh->width, fh->height, maxw, maxh); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | buf->vb.size = (fh->width * fh->height * (fh->fmt->depth)) >> 3; | ||
751 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
752 | return -EINVAL; | ||
753 | |||
754 | if (buf->fmt != fh->fmt || | ||
755 | buf->vb.width != fh->width || | ||
756 | buf->vb.height != fh->height || | ||
757 | buf->vb.field != field) { | ||
758 | dprintk(DBG_BUFF, "%s: buf - fmt=%p, width=%3d, height=%3d, " | ||
759 | "field=%d\n%s: fh - fmt=%p, width=%3d, height=%3d, " | ||
760 | "field=%d\n", __func__, buf->fmt, buf->vb.width, | ||
761 | buf->vb.height, buf->vb.field, __func__, fh->fmt, | ||
762 | fh->width, fh->height, field); | ||
763 | buf->fmt = fh->fmt; | ||
764 | buf->vb.width = fh->width; | ||
765 | buf->vb.height = fh->height; | ||
766 | buf->vb.field = field; | ||
767 | init_buffer = 1; /* force risc code re-generation */ | ||
768 | } | ||
769 | buf->input = dev->input; | ||
770 | 394 | ||
771 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 395 | sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; |
772 | rc = videobuf_iolock(q, &buf->vb, NULL); | 396 | /* |
773 | if (0 != rc) | 397 | * We allow create_bufs, but only if the sizeimage is the same as the |
774 | goto fail; | 398 | * current sizeimage. The tw68_buffer_count calculation becomes quite |
775 | init_buffer = 1; /* force risc code re-generation */ | 399 | * difficult otherwise. |
776 | } | 400 | */ |
777 | dprintk(DBG_BUFF, "%s: q=%p, vb=%p, init_buffer=%d\n", | 401 | if (fmt && fmt->fmt.pix.sizeimage < sizes[0]) |
778 | __func__, q, vb, init_buffer); | 402 | return -EINVAL; |
779 | 403 | *num_planes = 1; | |
780 | if (init_buffer) { | 404 | if (tot_bufs < 2) |
781 | buf->bpl = buf->vb.width * (buf->fmt->depth) >> 3; | 405 | tot_bufs = 2; |
782 | dprintk(DBG_TESTING, "%s: Generating new risc code " | 406 | tot_bufs = tw68_buffer_count(sizes[0], tot_bufs); |
783 | "[%dx%dx%d](%d)\n", __func__, buf->vb.width, | 407 | *num_buffers = tot_bufs - q->num_buffers; |
784 | buf->vb.height, buf->fmt->depth, buf->bpl); | ||
785 | switch (buf->vb.field) { | ||
786 | case V4L2_FIELD_TOP: | ||
787 | tw68_risc_buffer(dev->pci, &buf->risc, | ||
788 | dma->sglist, | ||
789 | 0, UNSET, | ||
790 | buf->bpl, 0, | ||
791 | buf->vb.height); | ||
792 | break; | ||
793 | case V4L2_FIELD_BOTTOM: | ||
794 | tw68_risc_buffer(dev->pci, &buf->risc, | ||
795 | dma->sglist, | ||
796 | UNSET, 0, | ||
797 | buf->bpl, 0, | ||
798 | buf->vb.height); | ||
799 | break; | ||
800 | case V4L2_FIELD_INTERLACED: | ||
801 | tw68_risc_buffer(dev->pci, &buf->risc, | ||
802 | dma->sglist, | ||
803 | 0, buf->bpl, | ||
804 | buf->bpl, buf->bpl, | ||
805 | buf->vb.height >> 1); | ||
806 | break; | ||
807 | case V4L2_FIELD_SEQ_TB: | ||
808 | tw68_risc_buffer(dev->pci, &buf->risc, | ||
809 | dma->sglist, | ||
810 | 0, buf->bpl * (buf->vb.height >> 1), | ||
811 | buf->bpl, 0, | ||
812 | buf->vb.height >> 1); | ||
813 | break; | ||
814 | case V4L2_FIELD_SEQ_BT: | ||
815 | tw68_risc_buffer(dev->pci, &buf->risc, | ||
816 | dma->sglist, | ||
817 | buf->bpl * (buf->vb.height >> 1), 0, | ||
818 | buf->bpl, 0, | ||
819 | buf->vb.height >> 1); | ||
820 | break; | ||
821 | default: | ||
822 | BUG(); | ||
823 | } | ||
824 | } | ||
825 | dprintk(DBG_BUFF, "%s: [%p/%d] - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | ||
826 | __func__, buf, buf->vb.i, fh->width, fh->height, | ||
827 | fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); | ||
828 | 408 | ||
829 | buf->vb.state = VIDEOBUF_PREPARED; | ||
830 | buf->activate = buffer_activate; | ||
831 | return 0; | 409 | return 0; |
832 | |||
833 | fail: | ||
834 | tw68_dma_free(q, buf); | ||
835 | return rc; | ||
836 | } | 410 | } |
837 | 411 | ||
838 | /* | 412 | /* |
839 | * buffer_queue | 413 | * The risc program for each buffers works as follows: it starts with a simple |
414 | * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the | ||
415 | * buffer follows and at the end we have a JUMP back to the start + 8 (skipping | ||
416 | * the initial JUMP). | ||
417 | * | ||
418 | * This is the program of the first buffer to be queued if the active list is | ||
419 | * empty and it just keeps DMAing this buffer without generating any interrupts. | ||
840 | * | 420 | * |
841 | * Callback whenever a buffer has been requested (by read() or QBUF) | 421 | * If a new buffer is added then the initial JUMP in the program generates an |
422 | * interrupt as well which signals that the previous buffer has been DMAed | ||
423 | * successfully and that it can be returned to userspace. | ||
424 | * | ||
425 | * It also sets the final jump of the previous buffer to the start of the new | ||
426 | * buffer, thus chaining the new buffer into the DMA chain. This is a single | ||
427 | * atomic u32 write, so there is no race condition. | ||
428 | * | ||
429 | * The end-result of all this that you only get an interrupt when a buffer | ||
430 | * is ready, so the control flow is very easy. | ||
842 | */ | 431 | */ |
843 | static void | 432 | static void tw68_buf_queue(struct vb2_buffer *vb) |
844 | buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
845 | { | 433 | { |
846 | struct tw68_fh *fh = q->priv_data; | 434 | struct vb2_queue *vq = vb->vb2_queue; |
847 | struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); | 435 | struct tw68_dev *dev = vb2_get_drv_priv(vq); |
436 | struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); | ||
437 | struct tw68_buf *prev; | ||
438 | unsigned long flags; | ||
439 | |||
440 | spin_lock_irqsave(&dev->slock, flags); | ||
848 | 441 | ||
849 | tw68_buffer_queue(fh->dev, &fh->dev->video_q, buf); | 442 | /* append a 'JUMP to start of buffer' to the buffer risc program */ |
443 | buf->jmp[0] = cpu_to_le32(RISC_JUMP); | ||
444 | buf->jmp[1] = cpu_to_le32(buf->dma + 8); | ||
445 | |||
446 | if (!list_empty(&dev->active)) { | ||
447 | prev = list_entry(dev->active.prev, struct tw68_buf, list); | ||
448 | buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT); | ||
449 | prev->jmp[1] = cpu_to_le32(buf->dma); | ||
450 | } | ||
451 | list_add_tail(&buf->list, &dev->active); | ||
452 | spin_unlock_irqrestore(&dev->slock, flags); | ||
850 | } | 453 | } |
851 | 454 | ||
852 | /* | 455 | /* |
853 | * buffer_release | 456 | * buffer_prepare |
854 | * | 457 | * |
855 | * Free a buffer previously allocated. | 458 | * Set the ancilliary information into the buffer structure. This |
459 | * includes generating the necessary risc program if it hasn't already | ||
460 | * been done for the current buffer format. | ||
461 | * The structure fh contains the details of the format requested by the | ||
462 | * user - type, width, height and #fields. This is compared with the | ||
463 | * last format set for the current buffer. If they differ, the risc | ||
464 | * code (which controls the filling of the buffer) is (re-)generated. | ||
856 | */ | 465 | */ |
857 | static void buffer_release(struct videobuf_queue *q, | 466 | static int tw68_buf_prepare(struct vb2_buffer *vb) |
858 | struct videobuf_buffer *vb) | ||
859 | { | 467 | { |
468 | struct vb2_queue *vq = vb->vb2_queue; | ||
469 | struct tw68_dev *dev = vb2_get_drv_priv(vq); | ||
860 | struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); | 470 | struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); |
471 | struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0); | ||
472 | unsigned size, bpl; | ||
473 | int rc; | ||
861 | 474 | ||
862 | tw68_dma_free(q, buf); | 475 | size = (dev->width * dev->height * dev->fmt->depth) >> 3; |
863 | } | 476 | if (vb2_plane_size(vb, 0) < size) |
864 | 477 | return -EINVAL; | |
865 | static struct videobuf_queue_ops video_qops = { | 478 | vb2_set_plane_payload(vb, 0, size); |
866 | .buf_setup = buffer_setup, | ||
867 | .buf_prepare = buffer_prepare, | ||
868 | .buf_queue = buffer_queue, | ||
869 | .buf_release = buffer_release, | ||
870 | }; | ||
871 | |||
872 | /* ------------------------------------------------------------------ */ | ||
873 | 479 | ||
874 | static int tw68_g_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, | 480 | rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE); |
875 | struct v4l2_control *c) | 481 | if (!rc) |
876 | { | 482 | return -EIO; |
877 | const struct v4l2_queryctrl *ctrl; | ||
878 | 483 | ||
879 | dprintk(DBG_FLOW, "%s\n", __func__); | 484 | bpl = (dev->width * dev->fmt->depth) >> 3; |
880 | ctrl = ctrl_by_id(c->id); | 485 | switch (dev->field) { |
881 | if (NULL == ctrl) | 486 | case V4L2_FIELD_TOP: |
882 | return -EINVAL; | 487 | tw68_risc_buffer(dev->pci, buf, dma->sgl, |
883 | switch (c->id) { | 488 | 0, UNSET, bpl, 0, dev->height); |
884 | case V4L2_CID_BRIGHTNESS: | ||
885 | c->value = (char)tw_readb(TW68_BRIGHT); | ||
886 | break; | ||
887 | case V4L2_CID_HUE: | ||
888 | c->value = (char)tw_readb(TW68_HUE); | ||
889 | break; | ||
890 | case V4L2_CID_CONTRAST: | ||
891 | c->value = tw_readb(TW68_CONTRAST); | ||
892 | break; | ||
893 | case V4L2_CID_SATURATION: | ||
894 | c->value = tw_readb(TW68_SAT_U); | ||
895 | break; | ||
896 | case V4L2_CID_COLOR_KILLER: | ||
897 | c->value = 0 != (tw_readb(TW68_MISC2) & 0xe0); | ||
898 | break; | 489 | break; |
899 | case V4L2_CID_CHROMA_AGC: | 490 | case V4L2_FIELD_BOTTOM: |
900 | c->value = 0 != (tw_readb(TW68_LOOP) & 0x30); | 491 | tw68_risc_buffer(dev->pci, buf, dma->sgl, |
492 | UNSET, 0, bpl, 0, dev->height); | ||
901 | break; | 493 | break; |
902 | case V4L2_CID_AUDIO_MUTE: | 494 | case V4L2_FIELD_SEQ_TB: |
903 | /*hack to suppresss tvtime complaint */ | 495 | tw68_risc_buffer(dev->pci, buf, dma->sgl, |
904 | c->value = 0; | 496 | 0, bpl * (dev->height >> 1), |
497 | bpl, 0, dev->height >> 1); | ||
905 | break; | 498 | break; |
906 | #if 0 | 499 | case V4L2_FIELD_SEQ_BT: |
907 | case V4L2_CID_AUDIO_VOLUME: | 500 | tw68_risc_buffer(dev->pci, buf, dma->sgl, |
908 | c->value = dev->ctl_volume; | 501 | bpl * (dev->height >> 1), 0, |
502 | bpl, 0, dev->height >> 1); | ||
909 | break; | 503 | break; |
910 | #endif | 504 | case V4L2_FIELD_INTERLACED: |
911 | default: | 505 | default: |
912 | return -EINVAL; | 506 | tw68_risc_buffer(dev->pci, buf, dma->sgl, |
507 | 0, bpl, bpl, bpl, dev->height >> 1); | ||
508 | break; | ||
913 | } | 509 | } |
914 | return 0; | 510 | return 0; |
915 | } | 511 | } |
916 | 512 | ||
917 | static int tw68_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) | 513 | static void tw68_buf_finish(struct vb2_buffer *vb) |
514 | { | ||
515 | struct vb2_queue *vq = vb->vb2_queue; | ||
516 | struct tw68_dev *dev = vb2_get_drv_priv(vq); | ||
517 | struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0); | ||
518 | struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); | ||
519 | |||
520 | dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE); | ||
521 | |||
522 | pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma); | ||
523 | } | ||
524 | |||
525 | static int tw68_start_streaming(struct vb2_queue *q, unsigned int count) | ||
526 | { | ||
527 | struct tw68_dev *dev = vb2_get_drv_priv(q); | ||
528 | struct tw68_buf *buf = | ||
529 | container_of(dev->active.next, struct tw68_buf, list); | ||
530 | |||
531 | dev->seqnr = 0; | ||
532 | tw68_video_start_dma(dev, buf); | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static void tw68_stop_streaming(struct vb2_queue *q) | ||
918 | { | 537 | { |
919 | struct tw68_fh *fh = priv; | 538 | struct tw68_dev *dev = vb2_get_drv_priv(q); |
920 | 539 | ||
921 | return tw68_g_ctrl_internal(fh->dev, fh, c); | 540 | /* Stop risc & fifo */ |
541 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | ||
542 | while (!list_empty(&dev->active)) { | ||
543 | struct tw68_buf *buf = | ||
544 | container_of(dev->active.next, struct tw68_buf, list); | ||
545 | |||
546 | list_del(&buf->list); | ||
547 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
548 | } | ||
922 | } | 549 | } |
923 | 550 | ||
924 | static int tw68_s_ctrl_value(struct tw68_dev *dev, __u32 id, int val) | 551 | static struct vb2_ops tw68_video_qops = { |
552 | .queue_setup = tw68_queue_setup, | ||
553 | .buf_queue = tw68_buf_queue, | ||
554 | .buf_prepare = tw68_buf_prepare, | ||
555 | .buf_finish = tw68_buf_finish, | ||
556 | .start_streaming = tw68_start_streaming, | ||
557 | .stop_streaming = tw68_stop_streaming, | ||
558 | .wait_prepare = vb2_ops_wait_prepare, | ||
559 | .wait_finish = vb2_ops_wait_finish, | ||
560 | }; | ||
561 | |||
562 | /* ------------------------------------------------------------------ */ | ||
563 | |||
564 | static int tw68_s_ctrl(struct v4l2_ctrl *ctrl) | ||
925 | { | 565 | { |
926 | int err = 0; | 566 | struct tw68_dev *dev = |
567 | container_of(ctrl->handler, struct tw68_dev, hdl); | ||
927 | 568 | ||
928 | dprintk(DBG_FLOW, "%s\n", __func__); | 569 | switch (ctrl->id) { |
929 | switch (id) { | ||
930 | case V4L2_CID_BRIGHTNESS: | 570 | case V4L2_CID_BRIGHTNESS: |
931 | tw_writeb(TW68_BRIGHT, val); | 571 | tw_writeb(TW68_BRIGHT, ctrl->val); |
932 | break; | 572 | break; |
933 | case V4L2_CID_HUE: | 573 | case V4L2_CID_HUE: |
934 | tw_writeb(TW68_HUE, val); | 574 | tw_writeb(TW68_HUE, ctrl->val); |
935 | break; | 575 | break; |
936 | case V4L2_CID_CONTRAST: | 576 | case V4L2_CID_CONTRAST: |
937 | tw_writeb(TW68_CONTRAST, val); | 577 | tw_writeb(TW68_CONTRAST, ctrl->val); |
938 | break; | 578 | break; |
939 | case V4L2_CID_SATURATION: | 579 | case V4L2_CID_SATURATION: |
940 | tw_writeb(TW68_SAT_U, val); | 580 | tw_writeb(TW68_SAT_U, ctrl->val); |
941 | tw_writeb(TW68_SAT_V, val); | 581 | tw_writeb(TW68_SAT_V, ctrl->val); |
942 | break; | 582 | break; |
943 | case V4L2_CID_COLOR_KILLER: | 583 | case V4L2_CID_COLOR_KILLER: |
944 | if (val) | 584 | if (ctrl->val) |
945 | tw_andorb(TW68_MISC2, 0xe0, 0xe0); | 585 | tw_andorb(TW68_MISC2, 0xe0, 0xe0); |
946 | else | 586 | else |
947 | tw_andorb(TW68_MISC2, 0xe0, 0x00); | 587 | tw_andorb(TW68_MISC2, 0xe0, 0x00); |
948 | break; | 588 | break; |
949 | case V4L2_CID_CHROMA_AGC: | 589 | case V4L2_CID_CHROMA_AGC: |
950 | if (val) | 590 | if (ctrl->val) |
951 | tw_andorb(TW68_LOOP, 0x30, 0x20); | 591 | tw_andorb(TW68_LOOP, 0x30, 0x20); |
952 | else | 592 | else |
953 | tw_andorb(TW68_LOOP, 0x30, 0x00); | 593 | tw_andorb(TW68_LOOP, 0x30, 0x00); |
954 | break; | 594 | break; |
955 | case V4L2_CID_AUDIO_MUTE: | ||
956 | /* hack to suppress tvtime complaint */ | ||
957 | break; | ||
958 | #if 0 | ||
959 | case V4L2_CID_AUDIO_VOLUME: | ||
960 | dev->ctl_volume = val; | ||
961 | tw68_tvaudio_setvolume(dev, dev->ctl_volume); | ||
962 | break; | ||
963 | case V4L2_CID_HFLIP: | ||
964 | dev->ctl_mirror = val; | ||
965 | break; | ||
966 | case V4L2_CID_PRIVATE_AUTOMUTE: | ||
967 | { | ||
968 | struct v4l2_priv_tun_config tda9887_cfg; | ||
969 | |||
970 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
971 | tda9887_cfg.priv = &dev->tda9887_conf; | ||
972 | |||
973 | dev->ctl_automute = val; | ||
974 | if (dev->tda9887_conf) { | ||
975 | if (dev->ctl_automute) | ||
976 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | ||
977 | else | ||
978 | dev->tda9887_conf &= ~TDA9887_AUTOMUTE; | ||
979 | |||
980 | tw_call_all(dev, tuner, s_config, &tda9887_cfg); | ||
981 | } | ||
982 | break; | ||
983 | } | 595 | } |
984 | #endif | ||
985 | default: | ||
986 | err = -EINVAL; | ||
987 | } | ||
988 | return err; | ||
989 | } | ||
990 | |||
991 | static int tw68_s_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, | ||
992 | struct v4l2_control *c) | ||
993 | { | ||
994 | const struct v4l2_queryctrl *ctrl; | ||
995 | int err; | ||
996 | |||
997 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
998 | if (fh) { | ||
999 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) | ||
1000 | err = v4l2_prio_check(&dev->prio, &fh->prio); | ||
1001 | #else | ||
1002 | err = v4l2_prio_check(&dev->prio, fh->prio); | ||
1003 | #endif | ||
1004 | if (0 != err) | ||
1005 | return err; | ||
1006 | } | ||
1007 | |||
1008 | mutex_lock(&dev->lock); | ||
1009 | |||
1010 | ctrl = ctrl_by_id(c->id); | ||
1011 | if (NULL == ctrl) { | ||
1012 | err = -EINVAL; | ||
1013 | goto error; | ||
1014 | } | ||
1015 | |||
1016 | dprintk(DBG_BUFF, "%s: name=%s val=%d\n", __func__, | ||
1017 | ctrl->name, c->value); | ||
1018 | switch (ctrl->type) { | ||
1019 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
1020 | case V4L2_CTRL_TYPE_MENU: | ||
1021 | case V4L2_CTRL_TYPE_INTEGER: | ||
1022 | if (c->value < ctrl->minimum) | ||
1023 | c->value = ctrl->minimum; | ||
1024 | if (c->value > ctrl->maximum) | ||
1025 | c->value = ctrl->maximum; | ||
1026 | break; | ||
1027 | default: | ||
1028 | /* nothing */; | ||
1029 | }; | ||
1030 | err = tw68_s_ctrl_value(dev, c->id, c->value); | ||
1031 | |||
1032 | error: | ||
1033 | mutex_unlock(&dev->lock); | ||
1034 | return err; | ||
1035 | } | ||
1036 | |||
1037 | static int tw68_s_ctrl(struct file *file, void *f, struct v4l2_control *c) | ||
1038 | { | ||
1039 | struct tw68_fh *fh = f; | ||
1040 | |||
1041 | return tw68_s_ctrl_internal(fh->dev, fh, c); | ||
1042 | } | ||
1043 | |||
1044 | /* ------------------------------------------------------------------ */ | ||
1045 | |||
1046 | /* | ||
1047 | * Returns a pointer to the currently used queue (e.g. video, vbi, etc.) | ||
1048 | */ | ||
1049 | static struct videobuf_queue *tw68_queue(struct tw68_fh *fh) | ||
1050 | { | ||
1051 | struct videobuf_queue *q = NULL; | ||
1052 | |||
1053 | switch (fh->type) { | ||
1054 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1055 | q = &fh->cap; | ||
1056 | break; | ||
1057 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1058 | q = &fh->vbi; | ||
1059 | break; | ||
1060 | default: | ||
1061 | BUG(); | ||
1062 | } | ||
1063 | return q; | ||
1064 | } | ||
1065 | |||
1066 | static int tw68_resource(struct tw68_fh *fh) | ||
1067 | { | ||
1068 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1069 | return RESOURCE_VIDEO; | ||
1070 | |||
1071 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1072 | return RESOURCE_VBI; | ||
1073 | |||
1074 | BUG(); | ||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | static int video_open(struct file *file) | ||
1079 | { | ||
1080 | int minor = video_devdata(file)->minor; | ||
1081 | struct tw68_dev *dev; | ||
1082 | struct tw68_fh *fh; | ||
1083 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1084 | int radio = 0; | ||
1085 | |||
1086 | mutex_lock(&tw68_devlist_lock); | ||
1087 | list_for_each_entry(dev, &tw68_devlist, devlist) { | ||
1088 | if (dev->video_dev && (dev->video_dev->minor == minor)) | ||
1089 | goto found; | ||
1090 | if (dev->radio_dev && (dev->radio_dev->minor == minor)) { | ||
1091 | radio = 1; | ||
1092 | goto found; | ||
1093 | } | ||
1094 | if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { | ||
1095 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
1096 | goto found; | ||
1097 | } | ||
1098 | } | ||
1099 | mutex_unlock(&tw68_devlist_lock); | ||
1100 | return -ENODEV; | ||
1101 | |||
1102 | found: | ||
1103 | mutex_unlock(&tw68_devlist_lock); | ||
1104 | |||
1105 | dprintk(DBG_FLOW, "%s: minor=%d radio=%d type=%s\n", __func__, minor, | ||
1106 | radio, v4l2_type_names[type]); | ||
1107 | |||
1108 | /* allocate + initialize per filehandle data */ | ||
1109 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
1110 | if (NULL == fh) | ||
1111 | return -ENOMEM; | ||
1112 | |||
1113 | file->private_data = fh; | ||
1114 | fh->dev = dev; | ||
1115 | fh->radio = radio; | ||
1116 | fh->type = type; | ||
1117 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | ||
1118 | fh->width = 720; | ||
1119 | fh->height = 576; | ||
1120 | v4l2_prio_open(&dev->prio, &fh->prio); | ||
1121 | |||
1122 | videobuf_queue_sg_init(&fh->cap, &video_qops, | ||
1123 | &dev->pci->dev, &dev->slock, | ||
1124 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1125 | V4L2_FIELD_INTERLACED, | ||
1126 | sizeof(struct tw68_buf), | ||
1127 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) | ||
1128 | fh | ||
1129 | #else | ||
1130 | fh, &dev->lock | ||
1131 | #endif | ||
1132 | ); | ||
1133 | videobuf_queue_sg_init(&fh->vbi, &tw68_vbi_qops, | ||
1134 | &dev->pci->dev, &dev->slock, | ||
1135 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
1136 | V4L2_FIELD_SEQ_TB, | ||
1137 | sizeof(struct tw68_buf), | ||
1138 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) | ||
1139 | fh | ||
1140 | #else | ||
1141 | fh, &dev->lock | ||
1142 | #endif | ||
1143 | ); | ||
1144 | if (fh->radio) { | ||
1145 | /* switch to radio mode */ | ||
1146 | tw68_tvaudio_setinput(dev, &card(dev).radio); | ||
1147 | tw_call_all(dev, tuner, s_radio); | ||
1148 | } else { | ||
1149 | /* switch to video/vbi mode */ | ||
1150 | tw68_tvaudio_setinput(dev, dev->input); | ||
1151 | } | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | static ssize_t | ||
1156 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
1157 | { | ||
1158 | struct tw68_fh *fh = file->private_data; | ||
1159 | |||
1160 | switch (fh->type) { | ||
1161 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1162 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | ||
1163 | return -EBUSY; | ||
1164 | return videobuf_read_one(tw68_queue(fh), | ||
1165 | data, count, ppos, | ||
1166 | file->f_flags & O_NONBLOCK); | ||
1167 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1168 | if (!res_get(fh, RESOURCE_VBI)) | ||
1169 | return -EBUSY; | ||
1170 | return videobuf_read_stream(tw68_queue(fh), | ||
1171 | data, count, ppos, 1, | ||
1172 | file->f_flags & O_NONBLOCK); | ||
1173 | break; | ||
1174 | default: | ||
1175 | BUG(); | ||
1176 | return 0; | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | static unsigned int | ||
1181 | video_poll(struct file *file, struct poll_table_struct *wait) | ||
1182 | { | ||
1183 | struct tw68_fh *fh = file->private_data; | ||
1184 | struct videobuf_buffer *buf = NULL; | ||
1185 | |||
1186 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) | ||
1187 | return videobuf_poll_stream(file, &fh->vbi, wait); | ||
1188 | |||
1189 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
1190 | if (!list_empty(&fh->cap.stream)) | ||
1191 | buf = list_entry(fh->cap.stream.next, | ||
1192 | struct videobuf_buffer, stream); | ||
1193 | } else { | ||
1194 | mutex_lock(&fh->cap.vb_lock); | ||
1195 | if (UNSET == fh->cap.read_off) { | ||
1196 | /* need to capture a new frame */ | ||
1197 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | ||
1198 | goto err; | ||
1199 | if (0 != fh->cap.ops->buf_prepare(&fh->cap, | ||
1200 | fh->cap.read_buf, fh->cap.field)) | ||
1201 | goto err; | ||
1202 | fh->cap.ops->buf_queue(&fh->cap, fh->cap.read_buf); | ||
1203 | fh->cap.read_off = 0; | ||
1204 | } | ||
1205 | mutex_unlock(&fh->cap.vb_lock); | ||
1206 | buf = fh->cap.read_buf; | ||
1207 | } | ||
1208 | |||
1209 | if (!buf) | ||
1210 | return POLLERR; | ||
1211 | |||
1212 | poll_wait(file, &buf->done, wait); | ||
1213 | if (buf->state == VIDEOBUF_DONE || | ||
1214 | buf->state == VIDEOBUF_ERROR) | ||
1215 | return POLLIN | POLLRDNORM; | ||
1216 | return 0; | ||
1217 | |||
1218 | err: | ||
1219 | mutex_unlock(&fh->cap.vb_lock); | ||
1220 | return POLLERR; | ||
1221 | } | ||
1222 | |||
1223 | static int video_release(struct file *file) | ||
1224 | { | ||
1225 | struct tw68_fh *fh = file->private_data; | ||
1226 | struct tw68_dev *dev = fh->dev; | ||
1227 | |||
1228 | /* stop video capture */ | ||
1229 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
1230 | videobuf_streamoff(&fh->cap); | ||
1231 | res_free(fh , RESOURCE_VIDEO); | ||
1232 | } | ||
1233 | if (fh->cap.read_buf) { | ||
1234 | buffer_release(&fh->cap, fh->cap.read_buf); | ||
1235 | kfree(fh->cap.read_buf); | ||
1236 | } | ||
1237 | |||
1238 | /* stop vbi capture */ | ||
1239 | if (res_check(fh, RESOURCE_VBI)) { | ||
1240 | videobuf_stop(&fh->vbi); | ||
1241 | res_free(fh, RESOURCE_VBI); | ||
1242 | } | ||
1243 | |||
1244 | #if 0 | ||
1245 | tw_call_all(dev, core, s_standby, 0); | ||
1246 | #endif | ||
1247 | |||
1248 | /* free stuff */ | ||
1249 | videobuf_mmap_free(&fh->cap); | ||
1250 | videobuf_mmap_free(&fh->vbi); | ||
1251 | |||
1252 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) | ||
1253 | v4l2_prio_close(&dev->prio, &fh->prio); | ||
1254 | #else | ||
1255 | v4l2_prio_close(&dev->prio, fh->prio); | ||
1256 | #endif | ||
1257 | file->private_data = NULL; | ||
1258 | kfree(fh); | ||
1259 | return 0; | 596 | return 0; |
1260 | } | 597 | } |
1261 | 598 | ||
1262 | static int video_mmap(struct file *file, struct vm_area_struct * vma) | ||
1263 | { | ||
1264 | struct tw68_fh *fh = file->private_data; | ||
1265 | |||
1266 | return videobuf_mmap_mapper(tw68_queue(fh), vma); | ||
1267 | } | ||
1268 | |||
1269 | /* ------------------------------------------------------------------ */ | 599 | /* ------------------------------------------------------------------ */ |
1270 | 600 | ||
1271 | #if 0 | ||
1272 | static int tw68_try_get_set_fmt_vbi_cap(struct file *file, void *priv, | ||
1273 | struct v4l2_format *f) | ||
1274 | { | ||
1275 | struct tw68_fh *fh = priv; | ||
1276 | struct tw68_dev *dev = fh->dev; | ||
1277 | struct tw68_tvnorm *norm = dev->tvnorm; | ||
1278 | |||
1279 | f->fmt.vbi.sampling_rate = 6750000 * 4; | ||
1280 | f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; | ||
1281 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
1282 | f->fmt.vbi.offset = 64 * 4; | ||
1283 | f->fmt.vbi.start[0] = norm->vbi_v_start_0; | ||
1284 | f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1; | ||
1285 | f->fmt.vbi.start[1] = norm->vbi_v_start_1; | ||
1286 | f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; | ||
1287 | f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ | ||
1288 | |||
1289 | #if 0 | ||
1290 | if (V4L2_STD_PAL == norm->id) { | ||
1291 | /* FIXME */ | ||
1292 | f->fmt.vbi.start[0] += 3; | ||
1293 | f->fmt.vbi.start[1] += 3*2; | ||
1294 | } | ||
1295 | #endif | ||
1296 | return 0; | ||
1297 | } | ||
1298 | #endif | ||
1299 | |||
1300 | /* | 601 | /* |
1301 | * Note that this routine returns what is stored in the fh structure, and | 602 | * Note that this routine returns what is stored in the fh structure, and |
1302 | * does not interrogate any of the device registers. | 603 | * does not interrogate any of the device registers. |
@@ -1304,54 +605,50 @@ static int tw68_try_get_set_fmt_vbi_cap(struct file *file, void *priv, | |||
1304 | static int tw68_g_fmt_vid_cap(struct file *file, void *priv, | 605 | static int tw68_g_fmt_vid_cap(struct file *file, void *priv, |
1305 | struct v4l2_format *f) | 606 | struct v4l2_format *f) |
1306 | { | 607 | { |
1307 | struct tw68_fh *fh = priv; | 608 | struct tw68_dev *dev = video_drvdata(file); |
1308 | struct tw68_dev *dev = fh->dev; | 609 | |
1309 | 610 | f->fmt.pix.width = dev->width; | |
1310 | dprintk(DBG_FLOW, "%s\n", __func__); | 611 | f->fmt.pix.height = dev->height; |
1311 | f->fmt.pix.width = fh->width; | 612 | f->fmt.pix.field = dev->field; |
1312 | f->fmt.pix.height = fh->height; | 613 | f->fmt.pix.pixelformat = dev->fmt->fourcc; |
1313 | f->fmt.pix.field = fh->cap.field; | ||
1314 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
1315 | f->fmt.pix.bytesperline = | 614 | f->fmt.pix.bytesperline = |
1316 | (f->fmt.pix.width * (fh->fmt->depth)) >> 3; | 615 | (f->fmt.pix.width * (dev->fmt->depth)) >> 3; |
1317 | f->fmt.pix.sizeimage = | 616 | f->fmt.pix.sizeimage = |
1318 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 617 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
1319 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | 618 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
619 | f->fmt.pix.priv = 0; | ||
1320 | return 0; | 620 | return 0; |
1321 | } | 621 | } |
1322 | 622 | ||
1323 | static int tw68_try_fmt_vid_cap(struct file *file, void *priv, | 623 | static int tw68_try_fmt_vid_cap(struct file *file, void *priv, |
1324 | struct v4l2_format *f) | 624 | struct v4l2_format *f) |
1325 | { | 625 | { |
1326 | struct tw68_fh *fh = priv; | 626 | struct tw68_dev *dev = video_drvdata(file); |
1327 | struct tw68_dev *dev = fh->dev; | 627 | const struct tw68_format *fmt; |
1328 | struct tw68_format *fmt; | ||
1329 | enum v4l2_field field; | 628 | enum v4l2_field field; |
1330 | unsigned int maxw, maxh; | 629 | unsigned int maxh; |
1331 | 630 | ||
1332 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1333 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 631 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1334 | if (NULL == fmt) | 632 | if (NULL == fmt) |
1335 | return -EINVAL; | 633 | return -EINVAL; |
1336 | 634 | ||
1337 | field = f->fmt.pix.field; | 635 | field = f->fmt.pix.field; |
1338 | maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); | 636 | maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576; |
1339 | maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); | ||
1340 | 637 | ||
1341 | if (V4L2_FIELD_ANY == field) { | ||
1342 | field = (f->fmt.pix.height > maxh/2) | ||
1343 | ? V4L2_FIELD_INTERLACED | ||
1344 | : V4L2_FIELD_BOTTOM; | ||
1345 | } | ||
1346 | switch (field) { | 638 | switch (field) { |
1347 | case V4L2_FIELD_TOP: | 639 | case V4L2_FIELD_TOP: |
1348 | case V4L2_FIELD_BOTTOM: | 640 | case V4L2_FIELD_BOTTOM: |
1349 | break; | 641 | break; |
1350 | case V4L2_FIELD_INTERLACED: | 642 | case V4L2_FIELD_INTERLACED: |
643 | case V4L2_FIELD_SEQ_BT: | ||
644 | case V4L2_FIELD_SEQ_TB: | ||
1351 | maxh = maxh * 2; | 645 | maxh = maxh * 2; |
1352 | break; | 646 | break; |
1353 | default: | 647 | default: |
1354 | return -EINVAL; | 648 | field = (f->fmt.pix.height > maxh / 2) |
649 | ? V4L2_FIELD_INTERLACED | ||
650 | : V4L2_FIELD_BOTTOM; | ||
651 | break; | ||
1355 | } | 652 | } |
1356 | 653 | ||
1357 | f->fmt.pix.field = field; | 654 | f->fmt.pix.field = field; |
@@ -1359,8 +656,8 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, | |||
1359 | f->fmt.pix.width = 48; | 656 | f->fmt.pix.width = 48; |
1360 | if (f->fmt.pix.height < 32) | 657 | if (f->fmt.pix.height < 32) |
1361 | f->fmt.pix.height = 32; | 658 | f->fmt.pix.height = 32; |
1362 | if (f->fmt.pix.width > maxw) | 659 | if (f->fmt.pix.width > 720) |
1363 | f->fmt.pix.width = maxw; | 660 | f->fmt.pix.width = 720; |
1364 | if (f->fmt.pix.height > maxh) | 661 | if (f->fmt.pix.height > maxh) |
1365 | f->fmt.pix.height = maxh; | 662 | f->fmt.pix.height = maxh; |
1366 | f->fmt.pix.width &= ~0x03; | 663 | f->fmt.pix.width &= ~0x03; |
@@ -1368,7 +665,7 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, | |||
1368 | (f->fmt.pix.width * (fmt->depth)) >> 3; | 665 | (f->fmt.pix.width * (fmt->depth)) >> 3; |
1369 | f->fmt.pix.sizeimage = | 666 | f->fmt.pix.sizeimage = |
1370 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 667 | f->fmt.pix.height * f->fmt.pix.bytesperline; |
1371 | 668 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | |
1372 | return 0; | 669 | return 0; |
1373 | } | 670 | } |
1374 | 671 | ||
@@ -1381,76 +678,35 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, | |||
1381 | static int tw68_s_fmt_vid_cap(struct file *file, void *priv, | 678 | static int tw68_s_fmt_vid_cap(struct file *file, void *priv, |
1382 | struct v4l2_format *f) | 679 | struct v4l2_format *f) |
1383 | { | 680 | { |
1384 | struct tw68_fh *fh = priv; | 681 | struct tw68_dev *dev = video_drvdata(file); |
1385 | struct tw68_dev *dev = fh->dev; | ||
1386 | int err; | 682 | int err; |
1387 | 683 | ||
1388 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1389 | err = tw68_try_fmt_vid_cap(file, priv, f); | 684 | err = tw68_try_fmt_vid_cap(file, priv, f); |
1390 | if (0 != err) | 685 | if (0 != err) |
1391 | return err; | 686 | return err; |
1392 | 687 | ||
1393 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 688 | dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1394 | fh->width = f->fmt.pix.width; | 689 | dev->width = f->fmt.pix.width; |
1395 | fh->height = f->fmt.pix.height; | 690 | dev->height = f->fmt.pix.height; |
1396 | fh->cap.field = f->fmt.pix.field; | 691 | dev->field = f->fmt.pix.field; |
1397 | /* | ||
1398 | * The following lines are to make v4l2-test program happy. | ||
1399 | * The docs should be checked to assure they make sense. | ||
1400 | */ | ||
1401 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1402 | f->fmt.pix.priv = 0; | ||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | static int tw68_queryctrl(struct file *file, void *priv, | ||
1407 | struct v4l2_queryctrl *c) | ||
1408 | { | ||
1409 | const struct v4l2_queryctrl *ctrl; | ||
1410 | struct tw68_fh *fh = priv; | ||
1411 | struct tw68_dev *dev = fh->dev; | ||
1412 | |||
1413 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1414 | if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) | ||
1415 | #if 0 | ||
1416 | && (c->id < V4L2_CID_PRIVATE_BASE || | ||
1417 | c->id >= V4L2_CID_PRIVATE_LASTP1) | ||
1418 | #endif | ||
1419 | ) | ||
1420 | return -EINVAL; | ||
1421 | ctrl = ctrl_by_id(c->id); | ||
1422 | if (NULL == ctrl) | ||
1423 | return -EINVAL; | ||
1424 | *c = *ctrl; | ||
1425 | return 0; | 692 | return 0; |
1426 | } | 693 | } |
1427 | 694 | ||
1428 | static int tw68_enum_input(struct file *file, void *priv, | 695 | static int tw68_enum_input(struct file *file, void *priv, |
1429 | struct v4l2_input *i) | 696 | struct v4l2_input *i) |
1430 | { | 697 | { |
1431 | struct tw68_fh *fh = priv; | 698 | struct tw68_dev *dev = video_drvdata(file); |
1432 | struct tw68_dev *dev = fh->dev; | ||
1433 | unsigned int n; | 699 | unsigned int n; |
1434 | 700 | ||
1435 | n = i->index; | 701 | n = i->index; |
1436 | dprintk(DBG_FLOW, "%s: index is %d\n", __func__, n); | 702 | if (n >= TW68_INPUT_MAX) |
1437 | if (n >= TW68_INPUT_MAX) { | ||
1438 | dprintk(DBG_FLOW, "%s: INPUT_MAX reached\n", __func__); | ||
1439 | return -EINVAL; | ||
1440 | } | ||
1441 | if (NULL == card_in(dev, n).name) { | ||
1442 | dprintk(DBG_FLOW, "%s: End of list\n", __func__); | ||
1443 | return -EINVAL; | 703 | return -EINVAL; |
1444 | } | ||
1445 | memset(i, 0, sizeof(*i)); | ||
1446 | i->index = n; | 704 | i->index = n; |
1447 | i->type = V4L2_INPUT_TYPE_CAMERA; | 705 | i->type = V4L2_INPUT_TYPE_CAMERA; |
1448 | strcpy(i->name, card_in(dev, n).name); | 706 | snprintf(i->name, sizeof(i->name), "Composite %d", n); |
1449 | if (card_in(dev, n).tv) | 707 | |
1450 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1451 | i->audioset = 1; | ||
1452 | /* If the query is for the current input, get live data */ | 708 | /* If the query is for the current input, get live data */ |
1453 | if (n == dev->hw_input->vmux) { | 709 | if (n == dev->input) { |
1454 | int v1 = tw_readb(TW68_STATUS1); | 710 | int v1 = tw_readb(TW68_STATUS1); |
1455 | int v2 = tw_readb(TW68_MVSN); | 711 | int v2 = tw_readb(TW68_MVSN); |
1456 | 712 | ||
@@ -1465,305 +721,86 @@ static int tw68_enum_input(struct file *file, void *priv, | |||
1465 | if (0 != (v2 & (1 << 2))) | 721 | if (0 != (v2 & (1 << 2))) |
1466 | i->status |= V4L2_IN_ST_MACROVISION; | 722 | i->status |= V4L2_IN_ST_MACROVISION; |
1467 | } | 723 | } |
1468 | i->std = TW68_NORMS; | 724 | i->std = video_devdata(file)->tvnorms; |
1469 | return 0; | 725 | return 0; |
1470 | } | 726 | } |
1471 | 727 | ||
1472 | static int tw68_g_input(struct file *file, void *priv, unsigned int *i) | 728 | static int tw68_g_input(struct file *file, void *priv, unsigned int *i) |
1473 | { | 729 | { |
1474 | struct tw68_fh *fh = priv; | 730 | struct tw68_dev *dev = video_drvdata(file); |
1475 | struct tw68_dev *dev = fh->dev; | ||
1476 | 731 | ||
1477 | dprintk(DBG_FLOW, "%s\n", __func__); | 732 | *i = dev->input; |
1478 | *i = dev->input->vmux; | ||
1479 | return 0; | 733 | return 0; |
1480 | } | 734 | } |
1481 | 735 | ||
1482 | static int tw68_s_input(struct file *file, void *priv, unsigned int i) | 736 | static int tw68_s_input(struct file *file, void *priv, unsigned int i) |
1483 | { | 737 | { |
1484 | struct tw68_fh *fh = priv; | 738 | struct tw68_dev *dev = video_drvdata(file); |
1485 | struct tw68_dev *dev = fh->dev; | ||
1486 | int err; | ||
1487 | |||
1488 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1489 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) | ||
1490 | err = v4l2_prio_check(&dev->prio, &fh->prio); | ||
1491 | #else | ||
1492 | err = v4l2_prio_check(&dev->prio, fh->prio); | ||
1493 | #endif | ||
1494 | if (0 != err) | ||
1495 | if (0 != err) | ||
1496 | return err; | ||
1497 | 739 | ||
1498 | if (i < 0 || i >= TW68_INPUT_MAX) | 740 | if (i >= TW68_INPUT_MAX) |
1499 | return -EINVAL; | ||
1500 | if (NULL == card_in(dev, i).name) | ||
1501 | return -EINVAL; | 741 | return -EINVAL; |
1502 | mutex_lock(&dev->lock); | 742 | dev->input = i; |
1503 | video_mux(dev, i); | 743 | tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2); |
1504 | mutex_unlock(&dev->lock); | ||
1505 | return 0; | 744 | return 0; |
1506 | } | 745 | } |
1507 | 746 | ||
1508 | static int tw68_querycap(struct file *file, void *priv, | 747 | static int tw68_querycap(struct file *file, void *priv, |
1509 | struct v4l2_capability *cap) | 748 | struct v4l2_capability *cap) |
1510 | { | 749 | { |
1511 | struct tw68_fh *fh = priv; | 750 | struct tw68_dev *dev = video_drvdata(file); |
1512 | struct tw68_dev *dev = fh->dev; | ||
1513 | 751 | ||
1514 | unsigned int tuner_type = dev->tuner_type; | ||
1515 | |||
1516 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1517 | strcpy(cap->driver, "tw68"); | 752 | strcpy(cap->driver, "tw68"); |
1518 | strlcpy(cap->card, tw68_boards[dev->board].name, | 753 | strlcpy(cap->card, "Techwell Capture Card", |
1519 | sizeof(cap->card)); | 754 | sizeof(cap->card)); |
1520 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); | 755 | sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); |
1521 | cap->version = TW68_VERSION_CODE; | 756 | cap->device_caps = |
1522 | cap->capabilities = | ||
1523 | V4L2_CAP_VIDEO_CAPTURE | | 757 | V4L2_CAP_VIDEO_CAPTURE | |
1524 | V4L2_CAP_VBI_CAPTURE | | ||
1525 | V4L2_CAP_READWRITE | | 758 | V4L2_CAP_READWRITE | |
1526 | V4L2_CAP_STREAMING | | 759 | V4L2_CAP_STREAMING; |
1527 | V4L2_CAP_TUNER; | ||
1528 | 760 | ||
1529 | if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) | 761 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
1530 | cap->capabilities &= ~V4L2_CAP_TUNER; | ||
1531 | return 0; | 762 | return 0; |
1532 | } | 763 | } |
1533 | 764 | ||
1534 | static int tw68_s_std_internal(struct tw68_dev *dev, struct tw68_fh *fh, | 765 | static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id) |
1535 | v4l2_std_id *id) | ||
1536 | { | 766 | { |
1537 | /* unsigned long flags; */ | 767 | struct tw68_dev *dev = video_drvdata(file); |
1538 | unsigned int i; | 768 | unsigned int i; |
1539 | v4l2_std_id fixup; | ||
1540 | int err; | ||
1541 | 769 | ||
1542 | dprintk(DBG_FLOW, "%s\n", __func__); | 770 | if (vb2_is_busy(&dev->vidq)) |
1543 | if (fh) { | 771 | return -EBUSY; |
1544 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) | ||
1545 | err = v4l2_prio_check(&dev->prio, &fh->prio); | ||
1546 | #else | ||
1547 | err = v4l2_prio_check(&dev->prio, fh->prio); | ||
1548 | #endif | ||
1549 | if (0 != err) | ||
1550 | if (0 != err) | ||
1551 | return err; | ||
1552 | } | ||
1553 | 772 | ||
1554 | /* Look for match on complete norm id (may have mult bits) */ | 773 | /* Look for match on complete norm id (may have mult bits) */ |
1555 | for (i = 0; i < TVNORMS; i++) { | 774 | for (i = 0; i < TVNORMS; i++) { |
1556 | if (*id == tvnorms[i].id) | 775 | if (id == tvnorms[i].id) |
1557 | break; | 776 | break; |
1558 | } | 777 | } |
1559 | 778 | ||
1560 | /* If no exact match, look for norm which contains this one */ | 779 | /* If no exact match, look for norm which contains this one */ |
1561 | if (i == TVNORMS) | 780 | if (i == TVNORMS) { |
1562 | for (i = 0; i < TVNORMS; i++) { | 781 | for (i = 0; i < TVNORMS; i++) |
1563 | if (*id & tvnorms[i].id) | 782 | if (id & tvnorms[i].id) |
1564 | break; | 783 | break; |
1565 | } | 784 | } |
1566 | /* If still not matched, give up */ | 785 | /* If still not matched, give up */ |
1567 | if (i == TVNORMS) | 786 | if (i == TVNORMS) |
1568 | return -EINVAL; | 787 | return -EINVAL; |
1569 | 788 | ||
1570 | /* TODO - verify this additional work with SECAM applies to TW */ | ||
1571 | if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { | ||
1572 | if (secam[0] == 'L' || secam[0] == 'l') { | ||
1573 | if (secam[1] == 'C' || secam[1] == 'c') | ||
1574 | fixup = V4L2_STD_SECAM_LC; | ||
1575 | else | ||
1576 | fixup = V4L2_STD_SECAM_L; | ||
1577 | } else { | ||
1578 | if (secam[0] == 'D' || secam[0] == 'd') | ||
1579 | fixup = V4L2_STD_SECAM_DK; | ||
1580 | else | ||
1581 | fixup = V4L2_STD_SECAM; | ||
1582 | } | ||
1583 | for (i = 0; i < TVNORMS; i++) | ||
1584 | if (fixup == tvnorms[i].id) | ||
1585 | break; | ||
1586 | } | ||
1587 | |||
1588 | *id = tvnorms[i].id; | ||
1589 | mutex_lock(&dev->lock); | ||
1590 | set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */ | 789 | set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */ |
1591 | tw68_tvaudio_do_scan(dev); | ||
1592 | mutex_unlock(&dev->lock); | ||
1593 | return 0; | 790 | return 0; |
1594 | } | 791 | } |
1595 | 792 | ||
1596 | static int tw68_s_std(struct file *file, void *priv, v4l2_std_id *id) | ||
1597 | { | ||
1598 | struct tw68_fh *fh = priv; | ||
1599 | struct tw68_dev *dev = fh->dev; | ||
1600 | |||
1601 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1602 | return tw68_s_std_internal(fh->dev, fh, id); | ||
1603 | } | ||
1604 | |||
1605 | static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id) | 793 | static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id) |
1606 | { | 794 | { |
1607 | struct tw68_fh *fh = priv; | 795 | struct tw68_dev *dev = video_drvdata(file); |
1608 | struct tw68_dev *dev = fh->dev; | ||
1609 | 796 | ||
1610 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1611 | *id = dev->tvnorm->id; | 797 | *id = dev->tvnorm->id; |
1612 | return 0; | 798 | return 0; |
1613 | } | 799 | } |
1614 | 800 | ||
1615 | static int tw68_g_tuner(struct file *file, void *priv, | ||
1616 | struct v4l2_tuner *t) | ||
1617 | { | ||
1618 | struct tw68_fh *fh = priv; | ||
1619 | struct tw68_dev *dev = fh->dev; | ||
1620 | int n; | ||
1621 | |||
1622 | if (unlikely(UNSET == dev->tuner_type)) | ||
1623 | return -EINVAL; | ||
1624 | if (0 != t->index) | ||
1625 | return -EINVAL; | ||
1626 | memset(t, 0, sizeof(*t)); | ||
1627 | for (n = 0; n < TW68_INPUT_MAX; n++) | ||
1628 | if (card_in(dev, n).tv) | ||
1629 | break; | ||
1630 | if (n == TW68_INPUT_MAX) | ||
1631 | return -EINVAL; | ||
1632 | #if 0 | ||
1633 | if (NULL != card_in(dev, n).name) { | ||
1634 | strcpy(t->name, "Television"); | ||
1635 | t->type = V4L2_TUNER_ANALOG_TV; | ||
1636 | t->capability = V4L2_TUNER_CAP_NORM | | ||
1637 | V4L2_TUNER_CAP_STEREO | | ||
1638 | V4L2_TUNER_CAP_LANG1 | | ||
1639 | V4L2_TUNER_CAP_LANG2; | ||
1640 | t->rangehigh = 0xffffffffUL; | ||
1641 | t->rxsubchans = tw68_tvaudio_getstereo(dev); | ||
1642 | t->audmode = tw68_tvaudio_rx2mode(t->rxsubchans); | ||
1643 | } | ||
1644 | if (0 != (saa_readb(TW68_STATUS_VIDEO1) & 0x03)) | ||
1645 | t->signal = 0xffff; | ||
1646 | #endif | ||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static int tw68_s_tuner(struct file *file, void *priv, | ||
1651 | struct v4l2_tuner *t) | ||
1652 | { | ||
1653 | struct tw68_fh *fh = priv; | ||
1654 | struct tw68_dev *dev = fh->dev; | ||
1655 | int err; | ||
1656 | #if 0 | ||
1657 | int rx, mode | ||
1658 | #endif | ||
1659 | |||
1660 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) | ||
1661 | err = v4l2_prio_check(&dev->prio, &fh->prio); | ||
1662 | #else | ||
1663 | err = v4l2_prio_check(&dev->prio, fh->prio); | ||
1664 | #endif | ||
1665 | if (0 != err) | ||
1666 | if (0 != err) | ||
1667 | return err; | ||
1668 | |||
1669 | #if 0 | ||
1670 | mode = dev->thread.mode; | ||
1671 | if (UNSET == mode) { | ||
1672 | rx = tw68_tvaudio_getstereo(dev); | ||
1673 | mode = tw68_tvaudio_rx2mode(t->rxsubchans); | ||
1674 | } | ||
1675 | if (mode != t->audmode) | ||
1676 | dev->thread.mode = t->audmode; | ||
1677 | #endif | ||
1678 | return 0; | ||
1679 | } | ||
1680 | |||
1681 | static int tw68_g_frequency(struct file *file, void *priv, | ||
1682 | struct v4l2_frequency *f) | ||
1683 | { | ||
1684 | struct tw68_fh *fh = priv; | ||
1685 | struct tw68_dev *dev = fh->dev; | ||
1686 | |||
1687 | if (unlikely(dev->tuner_type)) | ||
1688 | return -EINVAL; | ||
1689 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1690 | /* f->frequency = dev->ctl_freq; */ | ||
1691 | |||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | static int tw68_s_frequency(struct file *file, void *priv, | ||
1696 | struct v4l2_frequency *f) | ||
1697 | { | ||
1698 | struct tw68_fh *fh = priv; | ||
1699 | struct tw68_dev *dev = fh->dev; | ||
1700 | int err; | ||
1701 | |||
1702 | if (unlikely(UNSET == dev->tuner_type)) | ||
1703 | return -EINVAL; | ||
1704 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) | ||
1705 | err = v4l2_prio_check(&dev->prio, &fh->prio); | ||
1706 | #else | ||
1707 | err = v4l2_prio_check(&dev->prio, fh->prio); | ||
1708 | #endif | ||
1709 | if (0 != err) | ||
1710 | if (0 != err) | ||
1711 | return err; | ||
1712 | |||
1713 | if (0 != f->tuner) | ||
1714 | return -EINVAL; | ||
1715 | if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) | ||
1716 | return -EINVAL; | ||
1717 | if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) | ||
1718 | return -EINVAL; | ||
1719 | mutex_lock(&dev->lock); | ||
1720 | /* dev->ctl_freq = f->frequency; */ | ||
1721 | |||
1722 | tw_call_all(dev, tuner, s_frequency, f); | ||
1723 | |||
1724 | tw68_tvaudio_do_scan(dev); | ||
1725 | mutex_unlock(&dev->lock); | ||
1726 | return 0; | ||
1727 | } | ||
1728 | |||
1729 | static int tw68_g_audio(struct file *file, void *priv, struct v4l2_audio *a) | ||
1730 | { | ||
1731 | strcpy(a->name, "audio"); | ||
1732 | return 0; | ||
1733 | } | ||
1734 | |||
1735 | static int tw68_s_audio(struct file *file, void *priv, struct v4l2_audio *a) | ||
1736 | { | ||
1737 | return 0; | ||
1738 | } | ||
1739 | |||
1740 | static int tw68_g_priority(struct file *file, void *f, enum v4l2_priority *p) | ||
1741 | { | ||
1742 | struct tw68_fh *fh = f; | ||
1743 | struct tw68_dev *dev = fh->dev; | ||
1744 | |||
1745 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1746 | *p = v4l2_prio_max(&dev->prio); | ||
1747 | return 0; | ||
1748 | } | ||
1749 | |||
1750 | static int tw68_s_priority(struct file *file, void *f, | ||
1751 | enum v4l2_priority prio) | ||
1752 | { | ||
1753 | struct tw68_fh *fh = f; | ||
1754 | struct tw68_dev *dev = fh->dev; | ||
1755 | |||
1756 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1757 | return v4l2_prio_change(&dev->prio, &fh->prio, prio); | ||
1758 | } | ||
1759 | |||
1760 | static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, | 801 | static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, |
1761 | struct v4l2_fmtdesc *f) | 802 | struct v4l2_fmtdesc *f) |
1762 | { | 803 | { |
1763 | struct tw68_fh *fh = priv; | ||
1764 | struct tw68_dev *dev = fh->dev; | ||
1765 | |||
1766 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1767 | if (f->index >= FORMATS) | 804 | if (f->index >= FORMATS) |
1768 | return -EINVAL; | 805 | return -EINVAL; |
1769 | 806 | ||
@@ -1775,149 +812,6 @@ static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, | |||
1775 | return 0; | 812 | return 0; |
1776 | } | 813 | } |
1777 | 814 | ||
1778 | static int tw68_cropcap(struct file *file, void *priv, | ||
1779 | struct v4l2_cropcap *cap) | ||
1780 | { | ||
1781 | struct tw68_fh *fh = priv; | ||
1782 | struct tw68_dev *dev = fh->dev; | ||
1783 | |||
1784 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1785 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1786 | return -EINVAL; | ||
1787 | cap->bounds = dev->crop_bounds; | ||
1788 | cap->defrect = dev->crop_defrect; | ||
1789 | cap->pixelaspect.numerator = 1; | ||
1790 | cap->pixelaspect.denominator = 1; | ||
1791 | if (dev->tvnorm->id & V4L2_STD_525_60) { | ||
1792 | cap->pixelaspect.numerator = 11; | ||
1793 | cap->pixelaspect.denominator = 10; | ||
1794 | } | ||
1795 | if (dev->tvnorm->id & V4L2_STD_625_50) { | ||
1796 | cap->pixelaspect.numerator = 54; | ||
1797 | cap->pixelaspect.denominator = 59; | ||
1798 | } | ||
1799 | return 0; | ||
1800 | } | ||
1801 | |||
1802 | static int tw68_g_crop(struct file *file, void *f, struct v4l2_crop *crop) | ||
1803 | { | ||
1804 | struct tw68_fh *fh = f; | ||
1805 | struct tw68_dev *dev = fh->dev; | ||
1806 | |||
1807 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1808 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1809 | return -EINVAL; | ||
1810 | crop->c = dev->crop_current; | ||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1814 | static int tw68_s_crop(struct file *file, void *f, struct v4l2_crop *crop) | ||
1815 | { | ||
1816 | struct tw68_fh *fh = f; | ||
1817 | struct tw68_dev *dev = fh->dev; | ||
1818 | struct v4l2_rect *b = &dev->crop_bounds; | ||
1819 | |||
1820 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1821 | if (res_locked(fh->dev, RESOURCE_VIDEO)) | ||
1822 | return -EBUSY; | ||
1823 | |||
1824 | if ((crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || | ||
1825 | (crop->c.height < 0) || (crop->c.width < 0)) { | ||
1826 | dprintk(DBG_UNEXPECTED, "%s: invalid request\n", __func__); | ||
1827 | return -EINVAL; | ||
1828 | } | ||
1829 | |||
1830 | if (crop->c.top < b->top) | ||
1831 | crop->c.top = b->top; | ||
1832 | if (crop->c.top > b->top + b->height) | ||
1833 | crop->c.top = b->top + b->height; | ||
1834 | if (crop->c.height > b->top - crop->c.top + b->height) | ||
1835 | crop->c.height = b->top - crop->c.top + b->height; | ||
1836 | |||
1837 | if (crop->c.left < b->left) | ||
1838 | crop->c.left = b->left; | ||
1839 | if (crop->c.left > b->left + b->width) | ||
1840 | crop->c.left = b->left + b->width; | ||
1841 | if (crop->c.width > b->left - crop->c.left + b->width) | ||
1842 | crop->c.width = b->left - crop->c.left + b->width; | ||
1843 | |||
1844 | dprintk(DBG_FLOW, "%s: setting cropping rectangle: top=%d, left=%d, " | ||
1845 | "width=%d, height=%d\n", __func__, crop->c.top, | ||
1846 | crop->c.left, crop->c.width, crop->c.height); | ||
1847 | dev->crop_current = crop->c; | ||
1848 | return 0; | ||
1849 | } | ||
1850 | |||
1851 | /* | ||
1852 | * Wrappers for the v4l2_ioctl_ops functions | ||
1853 | */ | ||
1854 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1855 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) | ||
1856 | { | ||
1857 | struct tw68_fh *fh = file->private_data; | ||
1858 | return videobuf_cgmbuf(tw68_queue(fh), mbuf, 8); | ||
1859 | } | ||
1860 | #endif | ||
1861 | |||
1862 | static int tw68_reqbufs(struct file *file, void *priv, | ||
1863 | struct v4l2_requestbuffers *p) | ||
1864 | { | ||
1865 | struct tw68_fh *fh = priv; | ||
1866 | return videobuf_reqbufs(tw68_queue(fh), p); | ||
1867 | } | ||
1868 | |||
1869 | static int tw68_querybuf(struct file *file, void *priv, | ||
1870 | struct v4l2_buffer *b) | ||
1871 | { | ||
1872 | struct tw68_fh *fh = priv; | ||
1873 | return videobuf_querybuf(tw68_queue(fh), b); | ||
1874 | } | ||
1875 | |||
1876 | static int tw68_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
1877 | { | ||
1878 | struct tw68_fh *fh = priv; | ||
1879 | return videobuf_qbuf(tw68_queue(fh), b); | ||
1880 | } | ||
1881 | |||
1882 | static int tw68_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
1883 | { | ||
1884 | struct tw68_fh *fh = priv; | ||
1885 | return videobuf_dqbuf(tw68_queue(fh), b, | ||
1886 | file->f_flags & O_NONBLOCK); | ||
1887 | } | ||
1888 | |||
1889 | static int tw68_streamon(struct file *file, void *priv, | ||
1890 | enum v4l2_buf_type type) | ||
1891 | { | ||
1892 | struct tw68_fh *fh = priv; | ||
1893 | struct tw68_dev *dev = fh->dev; | ||
1894 | int res = tw68_resource(fh); | ||
1895 | |||
1896 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1897 | if (!res_get(fh, res)) | ||
1898 | return -EBUSY; | ||
1899 | |||
1900 | tw68_buffer_requeue(dev, &dev->video_q); | ||
1901 | return videobuf_streamon(tw68_queue(fh)); | ||
1902 | } | ||
1903 | |||
1904 | static int tw68_streamoff(struct file *file, void *priv, | ||
1905 | enum v4l2_buf_type type) | ||
1906 | { | ||
1907 | int err; | ||
1908 | struct tw68_fh *fh = priv; | ||
1909 | struct tw68_dev *dev = fh->dev; | ||
1910 | int res = tw68_resource(fh); | ||
1911 | |||
1912 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1913 | err = videobuf_streamoff(tw68_queue(fh)); | ||
1914 | if (err < 0) | ||
1915 | return err; | ||
1916 | res_free(fh, res); | ||
1917 | return 0; | ||
1918 | } | ||
1919 | |||
1920 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1921 | /* | 815 | /* |
1922 | * Used strictly for internal development and debugging, this routine | 816 | * Used strictly for internal development and debugging, this routine |
1923 | * prints out the current register contents for the tw68xx device. | 817 | * prints out the current register contents for the tw68xx device. |
@@ -1928,7 +822,7 @@ static void tw68_dump_regs(struct tw68_dev *dev) | |||
1928 | int i, j, k; | 822 | int i, j, k; |
1929 | unsigned char *cptr; | 823 | unsigned char *cptr; |
1930 | 824 | ||
1931 | printk(KERN_DEBUG "Full dump of TW68 registers:\n"); | 825 | pr_info("Full dump of TW68 registers:\n"); |
1932 | /* First we do the PCI regs, 8 4-byte regs per line */ | 826 | /* First we do the PCI regs, 8 4-byte regs per line */ |
1933 | for (i = 0; i < 0x100; i += 32) { | 827 | for (i = 0; i < 0x100; i += 32) { |
1934 | cptr = line; | 828 | cptr = line; |
@@ -1941,7 +835,7 @@ static void tw68_dump_regs(struct tw68_dev *dev) | |||
1941 | cptr += sprintf(cptr, "%08x ", tw_readl(j)); | 835 | cptr += sprintf(cptr, "%08x ", tw_readl(j)); |
1942 | *cptr++ = '\n'; | 836 | *cptr++ = '\n'; |
1943 | *cptr = 0; | 837 | *cptr = 0; |
1944 | printk(KERN_DEBUG "%s", line); | 838 | pr_info("%s", line); |
1945 | } | 839 | } |
1946 | /* Next the control regs, which are single-byte, address mod 4 */ | 840 | /* Next the control regs, which are single-byte, address mod 4 */ |
1947 | while (i < 0x400) { | 841 | while (i < 0x400) { |
@@ -1958,29 +852,24 @@ static void tw68_dump_regs(struct tw68_dev *dev) | |||
1958 | } | 852 | } |
1959 | *cptr++ = '\n'; | 853 | *cptr++ = '\n'; |
1960 | *cptr = 0; | 854 | *cptr = 0; |
1961 | printk(KERN_DEBUG "%s", line); | 855 | pr_info("%s", line); |
1962 | } | 856 | } |
1963 | } | 857 | } |
1964 | 858 | ||
1965 | static int vidioc_log_status(struct file *file, void *priv) | 859 | static int vidioc_log_status(struct file *file, void *priv) |
1966 | { | 860 | { |
1967 | struct tw68_fh *fh = priv; | 861 | struct tw68_dev *dev = video_drvdata(file); |
1968 | struct tw68_dev *dev = fh->dev; | ||
1969 | 862 | ||
1970 | tw68_dump_regs(dev); | 863 | tw68_dump_regs(dev); |
1971 | return 0; | 864 | return v4l2_ctrl_log_status(file, priv); |
1972 | } | 865 | } |
1973 | 866 | ||
867 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1974 | static int vidioc_g_register(struct file *file, void *priv, | 868 | static int vidioc_g_register(struct file *file, void *priv, |
1975 | struct v4l2_dbg_register *reg) | 869 | struct v4l2_dbg_register *reg) |
1976 | { | 870 | { |
1977 | struct tw68_fh *fh = priv; | 871 | struct tw68_dev *dev = video_drvdata(file); |
1978 | struct tw68_dev *dev = fh->dev; /* needed for tw_readb */ | ||
1979 | 872 | ||
1980 | dprintk(DBG_FLOW, "%s\n", __func__); | ||
1981 | if (!v4l2_chip_match_host(®->match)) | ||
1982 | dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); | ||
1983 | return -EINVAL; | ||
1984 | if (reg->size == 1) | 873 | if (reg->size == 1) |
1985 | reg->val = tw_readb(reg->reg); | 874 | reg->val = tw_readb(reg->reg); |
1986 | else | 875 | else |
@@ -1989,17 +878,10 @@ static int vidioc_g_register(struct file *file, void *priv, | |||
1989 | } | 878 | } |
1990 | 879 | ||
1991 | static int vidioc_s_register(struct file *file, void *priv, | 880 | static int vidioc_s_register(struct file *file, void *priv, |
1992 | struct v4l2_dbg_register *reg) | 881 | const struct v4l2_dbg_register *reg) |
1993 | { | 882 | { |
1994 | struct tw68_fh *fh = priv; | 883 | struct tw68_dev *dev = video_drvdata(file); |
1995 | struct tw68_dev *dev = fh->dev; /* needed for tw_writeb */ | ||
1996 | 884 | ||
1997 | dprintk(DBG_FLOW, "%s: request to set reg 0x%04x to 0x%02x\n", | ||
1998 | __func__, (unsigned int)reg->reg, (unsigned int)reg->val); | ||
1999 | if (!v4l2_chip_match_host(®->match)) { | ||
2000 | dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); | ||
2001 | return -EINVAL; | ||
2002 | } | ||
2003 | if (reg->size == 1) | 885 | if (reg->size == 1) |
2004 | tw_writeb(reg->reg, reg->val); | 886 | tw_writeb(reg->reg, reg->val); |
2005 | else | 887 | else |
@@ -2008,151 +890,120 @@ static int vidioc_s_register(struct file *file, void *priv, | |||
2008 | } | 890 | } |
2009 | #endif | 891 | #endif |
2010 | 892 | ||
893 | static const struct v4l2_ctrl_ops tw68_ctrl_ops = { | ||
894 | .s_ctrl = tw68_s_ctrl, | ||
895 | }; | ||
896 | |||
2011 | static const struct v4l2_file_operations video_fops = { | 897 | static const struct v4l2_file_operations video_fops = { |
2012 | .owner = THIS_MODULE, | 898 | .owner = THIS_MODULE, |
2013 | .open = video_open, | 899 | .open = v4l2_fh_open, |
2014 | .release = video_release, | 900 | .release = vb2_fop_release, |
2015 | .read = video_read, | 901 | .read = vb2_fop_read, |
2016 | .poll = video_poll, | 902 | .poll = vb2_fop_poll, |
2017 | .mmap = video_mmap, | 903 | .mmap = vb2_fop_mmap, |
2018 | .ioctl = video_ioctl2, | 904 | .unlocked_ioctl = video_ioctl2, |
2019 | }; | 905 | }; |
2020 | 906 | ||
2021 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | 907 | static const struct v4l2_ioctl_ops video_ioctl_ops = { |
2022 | .vidioc_querycap = tw68_querycap, | 908 | .vidioc_querycap = tw68_querycap, |
2023 | .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap, | 909 | .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap, |
2024 | .vidioc_reqbufs = tw68_reqbufs, | 910 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
2025 | .vidioc_querybuf = tw68_querybuf, | 911 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
2026 | .vidioc_qbuf = tw68_qbuf, | 912 | .vidioc_querybuf = vb2_ioctl_querybuf, |
2027 | .vidioc_dqbuf = tw68_dqbuf, | 913 | .vidioc_qbuf = vb2_ioctl_qbuf, |
914 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
2028 | .vidioc_s_std = tw68_s_std, | 915 | .vidioc_s_std = tw68_s_std, |
2029 | .vidioc_g_std = tw68_g_std, | 916 | .vidioc_g_std = tw68_g_std, |
2030 | .vidioc_enum_input = tw68_enum_input, | 917 | .vidioc_enum_input = tw68_enum_input, |
2031 | .vidioc_g_input = tw68_g_input, | 918 | .vidioc_g_input = tw68_g_input, |
2032 | .vidioc_s_input = tw68_s_input, | 919 | .vidioc_s_input = tw68_s_input, |
2033 | .vidioc_queryctrl = tw68_queryctrl, | 920 | .vidioc_streamon = vb2_ioctl_streamon, |
2034 | .vidioc_g_ctrl = tw68_g_ctrl, | 921 | .vidioc_streamoff = vb2_ioctl_streamoff, |
2035 | .vidioc_s_ctrl = tw68_s_ctrl, | ||
2036 | .vidioc_streamon = tw68_streamon, | ||
2037 | .vidioc_streamoff = tw68_streamoff, | ||
2038 | .vidioc_g_priority = tw68_g_priority, | ||
2039 | .vidioc_s_priority = tw68_s_priority, | ||
2040 | .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap, | 922 | .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap, |
2041 | .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap, | 923 | .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap, |
2042 | .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap, | 924 | .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap, |
2043 | .vidioc_cropcap = tw68_cropcap, | ||
2044 | .vidioc_g_crop = tw68_g_crop, | ||
2045 | .vidioc_s_crop = tw68_s_crop, | ||
2046 | /* | ||
2047 | * Functions not yet implemented / not yet passing tests. | ||
2048 | */ | ||
2049 | |||
2050 | #if 0 | ||
2051 | .vidioc_g_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, | ||
2052 | .vidioc_try_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, | ||
2053 | .vidioc_s_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, | ||
2054 | #endif | ||
2055 | .vidioc_g_audio = tw68_g_audio, | ||
2056 | .vidioc_s_audio = tw68_s_audio, | ||
2057 | .vidioc_g_tuner = tw68_g_tuner, | ||
2058 | .vidioc_s_tuner = tw68_s_tuner, | ||
2059 | .vidioc_g_frequency = tw68_g_frequency, | ||
2060 | .vidioc_s_frequency = tw68_s_frequency, | ||
2061 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
2062 | .vidiocgmbuf = vidiocgmbuf, | ||
2063 | #endif | ||
2064 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2065 | .vidioc_log_status = vidioc_log_status, | 925 | .vidioc_log_status = vidioc_log_status, |
926 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
927 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
928 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2066 | .vidioc_g_register = vidioc_g_register, | 929 | .vidioc_g_register = vidioc_g_register, |
2067 | .vidioc_s_register = vidioc_s_register, | 930 | .vidioc_s_register = vidioc_s_register, |
2068 | #endif | 931 | #endif |
2069 | }; | 932 | }; |
2070 | 933 | ||
2071 | /* ------------------------------------------------------------------ */ | 934 | static struct video_device tw68_video_template = { |
2072 | /* exported stuff */ | ||
2073 | struct video_device tw68_video_template = { | ||
2074 | .name = "tw68_video", | 935 | .name = "tw68_video", |
2075 | .fops = &video_fops, | 936 | .fops = &video_fops, |
2076 | .ioctl_ops = &video_ioctl_ops, | 937 | .ioctl_ops = &video_ioctl_ops, |
2077 | .minor = -1, | 938 | .release = video_device_release_empty, |
2078 | .tvnorms = TW68_NORMS, | 939 | .tvnorms = TW68_NORMS, |
2079 | .current_norm = V4L2_STD_PAL, | ||
2080 | }; | ||
2081 | |||
2082 | struct video_device tw68_radio_template = { | ||
2083 | .name = "tw68_radio", | ||
2084 | }; | 940 | }; |
2085 | 941 | ||
2086 | int tw68_videoport_init(struct tw68_dev *dev) | 942 | /* ------------------------------------------------------------------ */ |
2087 | { | 943 | /* exported stuff */ |
2088 | return 0; | ||
2089 | } | ||
2090 | |||
2091 | void tw68_set_tvnorm_hw(struct tw68_dev *dev) | 944 | void tw68_set_tvnorm_hw(struct tw68_dev *dev) |
2092 | { | 945 | { |
2093 | tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format); | 946 | tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format); |
2094 | return; | ||
2095 | } | 947 | } |
2096 | 948 | ||
2097 | int tw68_video_init1(struct tw68_dev *dev) | 949 | int tw68_video_init1(struct tw68_dev *dev) |
2098 | { | 950 | { |
2099 | int i; | 951 | struct v4l2_ctrl_handler *hdl = &dev->hdl; |
2100 | 952 | ||
2101 | dprintk(DBG_FLOW, "%s\n", __func__); | 953 | v4l2_ctrl_handler_init(hdl, 6); |
2102 | /* sanitycheck insmod options */ | 954 | v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, |
2103 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) | 955 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 20); |
2104 | gbuffers = 2; | 956 | v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, |
2105 | if (gbufsz < 0 || gbufsz > gbufsz_max) | 957 | V4L2_CID_CONTRAST, 0, 255, 1, 100); |
2106 | gbufsz = gbufsz_max; | 958 | v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, |
2107 | gbufsz = (gbufsz + PAGE_SIZE - 1) & PAGE_MASK; | 959 | V4L2_CID_SATURATION, 0, 255, 1, 128); |
2108 | 960 | /* NTSC only */ | |
2109 | /* put some sensible defaults into the data structures ... */ | 961 | v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, |
2110 | for (i = 0; i < CTRLS; i++) | 962 | V4L2_CID_HUE, -128, 127, 1, 0); |
2111 | tw68_s_ctrl_value(dev, video_ctrls[i].id, | 963 | v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, |
2112 | video_ctrls[i].default_value); | 964 | V4L2_CID_COLOR_KILLER, 0, 1, 1, 0); |
2113 | #if 0 | 965 | v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, |
2114 | if (dev->tda9887_conf && dev->ctl_automute) | 966 | V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); |
2115 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | 967 | if (hdl->error) { |
2116 | dev->automute = 0; | 968 | v4l2_ctrl_handler_free(hdl); |
2117 | #endif | 969 | return hdl->error; |
2118 | INIT_LIST_HEAD(&dev->video_q.queued); | 970 | } |
2119 | INIT_LIST_HEAD(&dev->video_q.active); | 971 | dev->v4l2_dev.ctrl_handler = hdl; |
2120 | init_timer(&dev->video_q.timeout); | 972 | v4l2_ctrl_handler_setup(hdl); |
2121 | dev->video_q.timeout.function = tw68_buffer_timeout; | ||
2122 | dev->video_q.timeout.data = (unsigned long)(&dev->video_q); | ||
2123 | dev->video_q.dev = dev; | ||
2124 | dev->video_q.buf_compat = tw68_check_video_fmt; | ||
2125 | dev->video_q.start_dma = tw68_video_start_dma; | ||
2126 | tw68_risc_stopper(dev->pci, &dev->video_q.stopper); | ||
2127 | |||
2128 | if (tw68_boards[dev->board].video_out) | ||
2129 | tw68_videoport_init(dev); | ||
2130 | |||
2131 | return 0; | 973 | return 0; |
2132 | } | 974 | } |
2133 | 975 | ||
2134 | int tw68_video_init2(struct tw68_dev *dev) | 976 | int tw68_video_init2(struct tw68_dev *dev, int video_nr) |
2135 | { | 977 | { |
2136 | dprintk(DBG_FLOW, "%s\n", __func__); | 978 | int ret; |
979 | |||
2137 | set_tvnorm(dev, &tvnorms[0]); | 980 | set_tvnorm(dev, &tvnorms[0]); |
2138 | video_mux(dev, 0); | ||
2139 | /* | ||
2140 | tw68_tvaudio_setmut(dev); | ||
2141 | tw68_tvaudio_setvolume(dev, dev->ctl_volume); | ||
2142 | */ | ||
2143 | return 0; | ||
2144 | } | ||
2145 | 981 | ||
2146 | /* | 982 | dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); |
2147 | * tw68_irq_video_signalchange | 983 | dev->width = 720; |
2148 | * | 984 | dev->height = 576; |
2149 | * TODO: | 985 | dev->field = V4L2_FIELD_INTERLACED; |
2150 | * Check for presence of video signal. If not present, mute audio. | 986 | |
2151 | * If present, log type of signal present. | 987 | INIT_LIST_HEAD(&dev->active); |
2152 | */ | 988 | dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
2153 | void tw68_irq_video_signalchange(struct tw68_dev *dev) | 989 | dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
2154 | { | 990 | dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF; |
2155 | return; | 991 | dev->vidq.ops = &tw68_video_qops; |
992 | dev->vidq.mem_ops = &vb2_dma_sg_memops; | ||
993 | dev->vidq.drv_priv = dev; | ||
994 | dev->vidq.gfp_flags = __GFP_DMA32; | ||
995 | dev->vidq.buf_struct_size = sizeof(struct tw68_buf); | ||
996 | dev->vidq.lock = &dev->lock; | ||
997 | dev->vidq.min_buffers_needed = 2; | ||
998 | ret = vb2_queue_init(&dev->vidq); | ||
999 | if (ret) | ||
1000 | return ret; | ||
1001 | dev->vdev = tw68_video_template; | ||
1002 | dev->vdev.v4l2_dev = &dev->v4l2_dev; | ||
1003 | dev->vdev.lock = &dev->lock; | ||
1004 | dev->vdev.queue = &dev->vidq; | ||
1005 | video_set_drvdata(&dev->vdev, dev); | ||
1006 | return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr); | ||
2156 | } | 1007 | } |
2157 | 1008 | ||
2158 | /* | 1009 | /* |
@@ -2171,60 +1022,39 @@ void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status) | |||
2171 | * for the current buffer. | 1022 | * for the current buffer. |
2172 | */ | 1023 | */ |
2173 | if (status & TW68_DMAPI) { | 1024 | if (status & TW68_DMAPI) { |
2174 | struct tw68_dmaqueue *q = &dev->video_q; | 1025 | struct tw68_buf *buf; |
2175 | dprintk(DBG_FLOW | DBG_TESTING, "DMAPI interrupt\n"); | 1026 | |
2176 | spin_lock(&dev->slock); | 1027 | spin_lock(&dev->slock); |
2177 | /* | 1028 | buf = list_entry(dev->active.next, struct tw68_buf, list); |
2178 | * tw68_wakeup will take care of the buffer handling, | 1029 | list_del(&buf->list); |
2179 | * plus any non-video requirements. | ||
2180 | */ | ||
2181 | tw68_wakeup(q, &dev->video_fieldcount); | ||
2182 | spin_unlock(&dev->slock); | 1030 | spin_unlock(&dev->slock); |
2183 | /* Check whether we have gotten into 'stopper' code */ | 1031 | v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); |
2184 | reg = tw_readl(TW68_DMAP_PP); | 1032 | buf->vb.v4l2_buf.field = dev->field; |
2185 | if ((reg >= q->stopper.dma) && | 1033 | buf->vb.v4l2_buf.sequence = dev->seqnr++; |
2186 | (reg < q->stopper.dma + q->stopper.size)) { | 1034 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); |
2187 | /* Yes - log the information */ | ||
2188 | dprintk(DBG_FLOW | DBG_TESTING, | ||
2189 | "%s: stopper risc code entered\n", __func__); | ||
2190 | } | ||
2191 | status &= ~(TW68_DMAPI); | 1035 | status &= ~(TW68_DMAPI); |
2192 | if (0 == status) | 1036 | if (0 == status) |
2193 | return; | 1037 | return; |
2194 | } | 1038 | } |
2195 | if (status & (TW68_VLOCK | TW68_HLOCK)) { /* lost sync */ | 1039 | if (status & (TW68_VLOCK | TW68_HLOCK)) |
2196 | dprintk(DBG_UNUSUAL, "Lost sync\n"); | 1040 | dev_dbg(&dev->pci->dev, "Lost sync\n"); |
2197 | } | 1041 | if (status & TW68_PABORT) |
2198 | if (status & TW68_PABORT) { /* TODO - what should we do? */ | 1042 | dev_err(&dev->pci->dev, "PABORT interrupt\n"); |
2199 | dprintk(DBG_UNEXPECTED, "PABORT interrupt\n"); | 1043 | if (status & TW68_DMAPERR) |
2200 | } | 1044 | dev_err(&dev->pci->dev, "DMAPERR interrupt\n"); |
2201 | if (status & TW68_DMAPERR) { | ||
2202 | dprintk(DBG_UNEXPECTED, "DMAPERR interrupt\n"); | ||
2203 | #if 0 | ||
2204 | /* Stop risc & fifo */ | ||
2205 | tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | ||
2206 | tw_clearl(TW68_INTMASK, dev->board_virqmask); | ||
2207 | dev->pci_irqmask &= ~dev->board_virqmask; | ||
2208 | #endif | ||
2209 | } | ||
2210 | /* | 1045 | /* |
2211 | * On TW6800, FDMIS is apparently generated if video input is switched | 1046 | * On TW6800, FDMIS is apparently generated if video input is switched |
2212 | * during operation. Therefore, it is not enabled for that chip. | 1047 | * during operation. Therefore, it is not enabled for that chip. |
2213 | */ | 1048 | */ |
2214 | if (status & TW68_FDMIS) { /* logic error somewhere */ | 1049 | if (status & TW68_FDMIS) |
2215 | dprintk(DBG_UNEXPECTED, "FDMIS interrupt\n"); | 1050 | dev_dbg(&dev->pci->dev, "FDMIS interrupt\n"); |
2216 | /* Stop risc & fifo */ | 1051 | if (status & TW68_FFOF) { |
2217 | // tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); | 1052 | /* probably a logic error */ |
2218 | // tw_clearl(TW68_INTMASK, dev->board_virqmask); | ||
2219 | // dev->pci_irqmask &= ~dev->board_virqmask; | ||
2220 | } | ||
2221 | if (status & TW68_FFOF) { /* probably a logic error */ | ||
2222 | reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN; | 1053 | reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN; |
2223 | tw_clearl(TW68_DMAC, TW68_FIFO_EN); | 1054 | tw_clearl(TW68_DMAC, TW68_FIFO_EN); |
2224 | dprintk(DBG_UNUSUAL, "FFOF interrupt\n"); | 1055 | dev_dbg(&dev->pci->dev, "FFOF interrupt\n"); |
2225 | tw_setl(TW68_DMAC, reg); | 1056 | tw_setl(TW68_DMAC, reg); |
2226 | } | 1057 | } |
2227 | if (status & TW68_FFERR) | 1058 | if (status & TW68_FFERR) |
2228 | dprintk(DBG_UNEXPECTED, "FFERR interrupt\n"); | 1059 | dev_dbg(&dev->pci->dev, "FFERR interrupt\n"); |
2229 | return; | ||
2230 | } | 1060 | } |
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index e723efb5e623..2c8abe26b13b 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h | |||
@@ -8,7 +8,11 @@ | |||
8 | * acknowledged. Full credit goes to them - any problems within this code | 8 | * acknowledged. Full credit goes to them - any problems within this code |
9 | * are mine. | 9 | * are mine. |
10 | * | 10 | * |
11 | * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> | 11 | * Copyright (C) 2009 William M. Brack |
12 | * | ||
13 | * Refactored and updated to the latest v4l core frameworks: | ||
14 | * | ||
15 | * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> | ||
12 | * | 16 | * |
13 | * This program is free software; you can redistribute it and/or modify | 17 | * 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 | 18 | * it under the terms of the GNU General Public License as published by |
@@ -19,54 +23,26 @@ | |||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 25 | * GNU General Public License for more details. |
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
26 | * 02111-1307 USA | ||
27 | */ | 26 | */ |
28 | 27 | ||
29 | #include <linux/version.h> | 28 | #include <linux/version.h> |
30 | #define TW68_VERSION_CODE KERNEL_VERSION(0, 0, 8) | ||
31 | |||
32 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
33 | #include <linux/i2c.h> | ||
34 | #include <linux/i2c-algo-bit.h> | ||
35 | #include <linux/videodev2.h> | 30 | #include <linux/videodev2.h> |
36 | #include <linux/kdev_t.h> | ||
37 | #include <linux/input.h> | ||
38 | #include <linux/notifier.h> | 31 | #include <linux/notifier.h> |
39 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
40 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
41 | 34 | #include <linux/io.h> | |
42 | #include <asm/io.h> | ||
43 | 35 | ||
44 | #include <media/v4l2-common.h> | 36 | #include <media/v4l2-common.h> |
45 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include <media/v4l2-ctrls.h> | ||
46 | #include <media/v4l2-device.h> | 39 | #include <media/v4l2-device.h> |
40 | #include <media/videobuf2-dma-sg.h> | ||
47 | 41 | ||
48 | #include <media/tuner.h> | ||
49 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) | ||
50 | # include <media/ir-common.h> | ||
51 | #endif | ||
52 | #include <media/ir-kbd-i2c.h> | ||
53 | #include <media/videobuf-dma-sg.h> | ||
54 | |||
55 | #include "btcx-risc.h" | ||
56 | #include "tw68-reg.h" | 42 | #include "tw68-reg.h" |
57 | 43 | ||
58 | #define UNSET (-1U) | 44 | #define UNSET (-1U) |
59 | 45 | ||
60 | /* | ||
61 | * dprintk statement within the code use a 'level' argument. For | ||
62 | * our purposes, we use the following levels: | ||
63 | */ | ||
64 | #define DBG_UNEXPECTED (1 << 0) | ||
65 | #define DBG_UNUSUAL (1 << 1) | ||
66 | #define DBG_TESTING (1 << 2) | ||
67 | #define DBG_BUFF (1 << 3) | ||
68 | #define DBG_FLOW (1 << 15) | ||
69 | |||
70 | /* system vendor and device ID's */ | 46 | /* system vendor and device ID's */ |
71 | #define PCI_VENDOR_ID_TECHWELL 0x1797 | 47 | #define PCI_VENDOR_ID_TECHWELL 0x1797 |
72 | #define PCI_DEVICE_ID_6800 0x6800 | 48 | #define PCI_DEVICE_ID_6800 0x6800 |
@@ -83,15 +59,9 @@ | |||
83 | #define PCI_DEVICE_ID_6816_3 0x6812 | 59 | #define PCI_DEVICE_ID_6816_3 0x6812 |
84 | #define PCI_DEVICE_ID_6816_4 0x6813 | 60 | #define PCI_DEVICE_ID_6816_4 0x6813 |
85 | 61 | ||
86 | /* subsystem vendor ID's */ | 62 | #define TW68_NORMS ( \ |
87 | #define TW68_PCI_ID_TECHWELL 0x1797 | 63 | V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ |
88 | 64 | V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60) | |
89 | #define TW68_NORMS (\ | ||
90 | V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ | ||
91 | V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ | ||
92 | V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60 | \ | ||
93 | V4L2_STD_525_60 | V4L2_STD_625_50 | \ | ||
94 | V4L2_STD_SECAM_L| V4L2_STD_SECAM_LC | V4L2_STD_SECAM_DK) | ||
95 | 65 | ||
96 | #define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \ | 66 | #define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \ |
97 | TW68_FFOF | TW68_DMAPI) | 67 | TW68_FFOF | TW68_DMAPI) |
@@ -101,12 +71,13 @@ | |||
101 | #define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \ | 71 | #define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \ |
102 | TW68_SBDONE2) | 72 | TW68_SBDONE2) |
103 | 73 | ||
104 | typedef enum { | 74 | enum tw68_decoder_type { |
105 | TW6800, | 75 | TW6800, |
106 | TW6801, | 76 | TW6801, |
107 | TW6804, | 77 | TW6804, |
108 | TWXXXX, | 78 | TWXXXX, |
109 | } TW68_DECODER_TYPE; | 79 | }; |
80 | |||
110 | /* ----------------------------------------------------------- */ | 81 | /* ----------------------------------------------------------- */ |
111 | /* static data */ | 82 | /* static data */ |
112 | 83 | ||
@@ -153,164 +124,24 @@ struct tw68_format { | |||
153 | #define TW68_BOARD_GENERIC_6802 1 | 124 | #define TW68_BOARD_GENERIC_6802 1 |
154 | 125 | ||
155 | #define TW68_MAXBOARDS 16 | 126 | #define TW68_MAXBOARDS 16 |
156 | #define TW68_INPUT_MAX 8 | 127 | #define TW68_INPUT_MAX 4 |
157 | |||
158 | /* ----------------------------------------------------------- */ | ||
159 | /* enums */ | ||
160 | |||
161 | enum tw68_mpeg_type { | ||
162 | TW68_MPEG_UNUSED, | ||
163 | TW68_MPEG_EMPRESS, | ||
164 | TW68_MPEG_DVB, | ||
165 | }; | ||
166 | |||
167 | enum tw68_audio_in { | ||
168 | TV = 1, | ||
169 | LINE1 = 2, | ||
170 | LINE2 = 3, | ||
171 | LINE2_LEFT, | ||
172 | }; | ||
173 | |||
174 | enum tw68_video_out { | ||
175 | CCIR656 = 1, | ||
176 | }; | ||
177 | |||
178 | /* Structs for card definition */ | ||
179 | struct tw68_input { | ||
180 | char *name; /* text description */ | ||
181 | unsigned int vmux; /* mux value */ | ||
182 | enum tw68_audio_in mux; | ||
183 | unsigned int gpio; | ||
184 | unsigned int tv:1; | ||
185 | }; | ||
186 | |||
187 | struct tw68_board { | ||
188 | char *name; | ||
189 | unsigned int audio_clock; | ||
190 | |||
191 | /* input switching */ | ||
192 | unsigned int gpiomask; | ||
193 | struct tw68_input inputs[TW68_INPUT_MAX]; | ||
194 | struct tw68_input radio; | ||
195 | struct tw68_input mute; | ||
196 | |||
197 | /* i2c chip info */ | ||
198 | unsigned int tuner_type; | ||
199 | unsigned int radio_type; | ||
200 | unsigned char tuner_addr; | ||
201 | unsigned char radio_addr; | ||
202 | |||
203 | unsigned int tda9887_conf; | ||
204 | unsigned int tuner_config; | ||
205 | |||
206 | enum tw68_video_out video_out; | ||
207 | enum tw68_mpeg_type mpeg; | ||
208 | unsigned int vid_port_opts; | ||
209 | }; | ||
210 | |||
211 | #define card_has_radio(dev) (NULL != tw68_boards[dev->board].radio.name) | ||
212 | #define card_has_mpeg(dev) (TW68_MPEG_UNUSED != \ | ||
213 | tw68_boards[dev->board].mpeg) | ||
214 | #define card_in(dev, n) (tw68_boards[dev->board].inputs[n]) | ||
215 | #define card(dev) (tw68_boards[dev->board]) | ||
216 | 128 | ||
217 | /* ----------------------------------------------------------- */ | 129 | /* ----------------------------------------------------------- */ |
218 | /* device / file handle status */ | 130 | /* device / file handle status */ |
219 | 131 | ||
220 | #define RESOURCE_VIDEO 1 | ||
221 | #define RESOURCE_VBI 2 | ||
222 | |||
223 | #define INTERLACE_AUTO 0 | ||
224 | #define INTERLACE_ON 1 | ||
225 | #define INTERLACE_OFF 2 | ||
226 | |||
227 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ | 132 | #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ |
228 | 133 | ||
229 | struct tw68_dev; /* forward delclaration */ | 134 | struct tw68_dev; /* forward delclaration */ |
230 | 135 | ||
231 | /* tvaudio thread status */ | ||
232 | struct tw68_thread { | ||
233 | struct task_struct *thread; | ||
234 | unsigned int scan1; | ||
235 | unsigned int scan2; | ||
236 | unsigned int mode; | ||
237 | unsigned int stopped; | ||
238 | }; | ||
239 | |||
240 | /* buffer for one video/vbi/ts frame */ | 136 | /* buffer for one video/vbi/ts frame */ |
241 | struct tw68_buf { | 137 | struct tw68_buf { |
242 | /* common v4l buffer stuff -- must be first */ | 138 | struct vb2_buffer vb; |
243 | struct videobuf_buffer vb; | 139 | struct list_head list; |
244 | |||
245 | /* tw68 specific */ | ||
246 | struct tw68_format *fmt; | ||
247 | struct tw68_input *input; | ||
248 | unsigned int top_seen; | ||
249 | int (*activate)(struct tw68_dev *dev, | ||
250 | struct tw68_buf *buf, | ||
251 | struct tw68_buf *next); | ||
252 | struct btcx_riscmem risc; | ||
253 | unsigned int bpl; | ||
254 | }; | ||
255 | 140 | ||
256 | struct tw68_dmaqueue { | 141 | unsigned int size; |
257 | struct tw68_dev *dev; | 142 | __le32 *cpu; |
258 | struct list_head active; | 143 | __le32 *jmp; |
259 | struct list_head queued; | 144 | dma_addr_t dma; |
260 | struct timer_list timeout; | ||
261 | struct btcx_riscmem stopper; | ||
262 | int (*buf_compat)(struct tw68_buf *prev, | ||
263 | struct tw68_buf *buf); | ||
264 | int (*start_dma)(struct tw68_dev *dev, | ||
265 | struct tw68_dmaqueue *q, | ||
266 | struct tw68_buf *buf); | ||
267 | }; | ||
268 | |||
269 | /* video filehandle status */ | ||
270 | struct tw68_fh { | ||
271 | struct tw68_dev *dev; | ||
272 | unsigned int radio; | ||
273 | enum v4l2_buf_type type; | ||
274 | unsigned int resources; | ||
275 | enum v4l2_priority prio; | ||
276 | |||
277 | /* video capture */ | ||
278 | struct tw68_format *fmt; | ||
279 | unsigned int width, height; | ||
280 | struct videobuf_queue cap; /* also used for overlay */ | ||
281 | |||
282 | /* vbi capture */ | ||
283 | struct videobuf_queue vbi; | ||
284 | }; | ||
285 | |||
286 | /* dmasound dsp status */ | ||
287 | struct tw68_dmasound { | ||
288 | struct mutex lock; | ||
289 | int minor_mixer; | ||
290 | int minor_dsp; | ||
291 | unsigned int users_dsp; | ||
292 | |||
293 | /* mixer */ | ||
294 | enum tw68_audio_in input; | ||
295 | unsigned int count; | ||
296 | unsigned int line1; | ||
297 | unsigned int line2; | ||
298 | |||
299 | /* dsp */ | ||
300 | unsigned int afmt; | ||
301 | unsigned int rate; | ||
302 | unsigned int channels; | ||
303 | unsigned int recording_on; | ||
304 | unsigned int dma_running; | ||
305 | unsigned int blocks; | ||
306 | unsigned int blksize; | ||
307 | unsigned int bufsize; | ||
308 | struct videobuf_dmabuf dma; | ||
309 | unsigned int dma_blk; | ||
310 | unsigned int read_offset; | ||
311 | unsigned int read_count; | ||
312 | void *priv_data; | ||
313 | struct snd_pcm_substream *substream; | ||
314 | }; | 145 | }; |
315 | 146 | ||
316 | struct tw68_fmt { | 147 | struct tw68_fmt { |
@@ -321,58 +152,20 @@ struct tw68_fmt { | |||
321 | u32 twformat; | 152 | u32 twformat; |
322 | }; | 153 | }; |
323 | 154 | ||
324 | /* ts/mpeg status */ | ||
325 | struct tw68_ts { | ||
326 | /* TS capture */ | ||
327 | int nr_packets; | ||
328 | int nr_bufs; | ||
329 | }; | ||
330 | |||
331 | /* ts/mpeg ops */ | ||
332 | struct tw68_mpeg_ops { | ||
333 | enum tw68_mpeg_type type; | ||
334 | struct list_head next; | ||
335 | int (*init)(struct tw68_dev *dev); | ||
336 | int (*fini)(struct tw68_dev *dev); | ||
337 | void (*signal_change)(struct tw68_dev *dev); | ||
338 | }; | ||
339 | |||
340 | enum tw68_ts_status { | ||
341 | TW68_TS_STOPPED, | ||
342 | TW68_TS_BUFF_DONE, | ||
343 | TW68_TS_STARTED, | ||
344 | }; | ||
345 | |||
346 | /* global device status */ | 155 | /* global device status */ |
347 | struct tw68_dev { | 156 | struct tw68_dev { |
348 | struct list_head devlist; | ||
349 | struct mutex lock; | 157 | struct mutex lock; |
350 | spinlock_t slock; | 158 | spinlock_t slock; |
351 | struct v4l2_prio_state prio; | 159 | u16 instance; |
352 | struct v4l2_device v4l2_dev; | 160 | struct v4l2_device v4l2_dev; |
353 | /* workstruct for loading modules */ | ||
354 | struct work_struct request_module_wk; | ||
355 | |||
356 | /* insmod option/autodetected */ | ||
357 | int autodetected; | ||
358 | 161 | ||
359 | /* various device info */ | 162 | /* various device info */ |
360 | TW68_DECODER_TYPE vdecoder; | 163 | enum tw68_decoder_type vdecoder; |
361 | unsigned int resources; | 164 | struct video_device vdev; |
362 | struct video_device *video_dev; | 165 | struct v4l2_ctrl_handler hdl; |
363 | struct video_device *radio_dev; | ||
364 | struct video_device *vbi_dev; | ||
365 | struct tw68_dmasound dmasound; | ||
366 | |||
367 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) | ||
368 | /* infrared remote */ | ||
369 | int has_remote; | ||
370 | struct card_ir *remote; | ||
371 | #endif | ||
372 | 166 | ||
373 | /* pci i/o */ | 167 | /* pci i/o */ |
374 | char name[32]; | 168 | char *name; |
375 | int nr; | ||
376 | struct pci_dev *pci; | 169 | struct pci_dev *pci; |
377 | unsigned char pci_rev, pci_lat; | 170 | unsigned char pci_rev, pci_lat; |
378 | u32 __iomem *lmmio; | 171 | u32 __iomem *lmmio; |
@@ -381,75 +174,18 @@ struct tw68_dev { | |||
381 | /* The irq mask to be used will depend upon the chip type */ | 174 | /* The irq mask to be used will depend upon the chip type */ |
382 | u32 board_virqmask; | 175 | u32 board_virqmask; |
383 | 176 | ||
384 | /* config info */ | 177 | /* video capture */ |
385 | unsigned int board; | 178 | const struct tw68_format *fmt; |
386 | unsigned int tuner_type; | 179 | unsigned width, height; |
387 | unsigned int radio_type; | 180 | unsigned seqnr; |
388 | unsigned char tuner_addr; | 181 | unsigned field; |
389 | unsigned char radio_addr; | 182 | struct vb2_queue vidq; |
390 | 183 | struct list_head active; | |
391 | unsigned int tda9887_conf; | ||
392 | unsigned int gpio_value; | ||
393 | |||
394 | /* i2c i/o */ | ||
395 | struct i2c_algo_bit_data i2c_algo; | ||
396 | struct i2c_adapter i2c_adap; | ||
397 | struct i2c_client i2c_client; | ||
398 | u32 i2c_state; | ||
399 | u32 i2c_done; | ||
400 | wait_queue_head_t i2c_queue; | ||
401 | int i2c_rc; | ||
402 | unsigned char eedata[256]; | ||
403 | |||
404 | /* video+ts+vbi capture */ | ||
405 | struct tw68_dmaqueue video_q; | ||
406 | struct tw68_dmaqueue vbi_q; | ||
407 | unsigned int video_fieldcount; | ||
408 | unsigned int vbi_fieldcount; | ||
409 | 184 | ||
410 | /* various v4l controls */ | 185 | /* various v4l controls */ |
411 | struct tw68_tvnorm *tvnorm; /* video */ | 186 | const struct tw68_tvnorm *tvnorm; /* video */ |
412 | struct tw68_tvaudio *tvaudio; | 187 | |
413 | #if 0 | 188 | int input; |
414 | unsigned int ctl_input; | ||
415 | int ctl_bright; | ||
416 | int ctl_contrast; | ||
417 | int ctl_hue; | ||
418 | int ctl_saturation; | ||
419 | int ctl_freq; | ||
420 | int ctl_mute; /* audio */ | ||
421 | int ctl_volume; | ||
422 | int ctl_invert; /* private */ | ||
423 | int ctl_mirror; | ||
424 | int ctl_y_odd; | ||
425 | int ctl_y_even; | ||
426 | int ctl_automute; | ||
427 | #endif | ||
428 | |||
429 | /* crop */ | ||
430 | struct v4l2_rect crop_bounds; | ||
431 | struct v4l2_rect crop_defrect; | ||
432 | struct v4l2_rect crop_current; | ||
433 | |||
434 | /* other global state info */ | ||
435 | unsigned int automute; | ||
436 | struct tw68_thread thread; | ||
437 | /* input is latest requested by app, hw_input is current hw setting */ | ||
438 | struct tw68_input *input; | ||
439 | struct tw68_input *hw_input; | ||
440 | unsigned int hw_mute; | ||
441 | int last_carrier; | ||
442 | int nosignal; | ||
443 | unsigned int insuspend; | ||
444 | |||
445 | /* TW68_MPEG_* */ | ||
446 | struct tw68_ts ts; | ||
447 | struct tw68_dmaqueue ts_q; | ||
448 | enum tw68_ts_status ts_state; | ||
449 | unsigned int buff_cnt; | ||
450 | struct tw68_mpeg_ops *mops; | ||
451 | |||
452 | void (*gate_ctrl)(struct tw68_dev *dev, int open); | ||
453 | }; | 189 | }; |
454 | 190 | ||
455 | /* ----------------------------------------------------------- */ | 191 | /* ----------------------------------------------------------- */ |
@@ -473,116 +209,23 @@ struct tw68_dev { | |||
473 | #define tw_clearb(reg, bit) \ | 209 | #define tw_clearb(reg, bit) \ |
474 | writeb((readb(dev->bmmio+(reg)) & ~(bit)), \ | 210 | writeb((readb(dev->bmmio+(reg)) & ~(bit)), \ |
475 | dev->bmmio + (reg)) | 211 | dev->bmmio + (reg)) |
476 | #define tw_call_all(dev, o, f, args...) do { \ | ||
477 | if (dev->gate_ctrl) \ | ||
478 | dev->gate_ctrl(dev, 1); \ | ||
479 | v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ | ||
480 | if (dev->gate_ctrl) \ | ||
481 | dev->gate_ctrl(dev, 0); \ | ||
482 | } while (0) | ||
483 | 212 | ||
484 | #define tw_wait(us) { udelay(us); } | 213 | #define tw_wait(us) { udelay(us); } |
485 | 214 | ||
486 | static inline struct tw68_dev *to_tw68_dev(struct v4l2_device *v4l2_dev) | ||
487 | { | ||
488 | return container_of(v4l2_dev, struct tw68_dev, v4l2_dev); | ||
489 | } | ||
490 | |||
491 | /* ----------------------------------------------------------- */ | ||
492 | /* tw68-core.c */ | ||
493 | |||
494 | extern struct list_head tw68_devlist; | ||
495 | extern struct mutex tw68_devlist_lock; | ||
496 | extern unsigned int irq_debug; | ||
497 | |||
498 | int tw68_buffer_count(unsigned int size, unsigned int count); | ||
499 | void tw68_buffer_queue(struct tw68_dev *dev, struct tw68_dmaqueue *q, | ||
500 | struct tw68_buf *buf); | ||
501 | void tw68_buffer_timeout(unsigned long data); | ||
502 | int tw68_set_dmabits(struct tw68_dev *dev); | ||
503 | void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf); | ||
504 | void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *field_count); | ||
505 | int tw68_buffer_requeue(struct tw68_dev *dev, struct tw68_dmaqueue *q); | ||
506 | |||
507 | /* ----------------------------------------------------------- */ | ||
508 | /* tw68-cards.c */ | ||
509 | |||
510 | extern struct tw68_board tw68_boards[]; | ||
511 | extern const unsigned int tw68_bcount; | ||
512 | extern struct pci_device_id __devinitdata tw68_pci_tbl[]; | ||
513 | |||
514 | int tw68_board_init1(struct tw68_dev *dev); | ||
515 | int tw68_board_init2(struct tw68_dev *dev); | ||
516 | int tw68_tuner_callback(void *priv, int component, int command, int arg); | ||
517 | |||
518 | /* ----------------------------------------------------------- */ | ||
519 | /* tw68-i2c.c */ | ||
520 | |||
521 | int tw68_i2c_register(struct tw68_dev *dev); | ||
522 | int tw68_i2c_unregister(struct tw68_dev *dev); | ||
523 | void tw68_irq_i2c(struct tw68_dev *dev, int status); | ||
524 | |||
525 | /* ----------------------------------------------------------- */ | 215 | /* ----------------------------------------------------------- */ |
526 | /* tw68-video.c */ | 216 | /* tw68-video.c */ |
527 | 217 | ||
528 | extern unsigned int video_debug; | ||
529 | extern struct video_device tw68_video_template; | ||
530 | extern struct video_device tw68_radio_template; | ||
531 | |||
532 | int tw68_videoport_init(struct tw68_dev *dev); | ||
533 | void tw68_set_tvnorm_hw(struct tw68_dev *dev); | 218 | void tw68_set_tvnorm_hw(struct tw68_dev *dev); |
534 | 219 | ||
535 | int tw68_video_init1(struct tw68_dev *dev); | 220 | int tw68_video_init1(struct tw68_dev *dev); |
536 | int tw68_video_init2(struct tw68_dev *dev); | 221 | int tw68_video_init2(struct tw68_dev *dev, int video_nr); |
537 | void tw68_irq_video_signalchange(struct tw68_dev *dev); | ||
538 | void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status); | 222 | void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status); |
539 | 223 | int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf); | |
540 | /* ----------------------------------------------------------- */ | ||
541 | /* tw68-ts.c */ | ||
542 | |||
543 | int tw68_ts_init1(struct tw68_dev *dev); | ||
544 | int tw68_ts_fini(struct tw68_dev *dev); | ||
545 | void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status); | ||
546 | |||
547 | int tw68_ts_register(struct tw68_mpeg_ops *ops); | ||
548 | void tw68_ts_unregister(struct tw68_mpeg_ops *ops); | ||
549 | |||
550 | int tw68_ts_init_hw(struct tw68_dev *dev); | ||
551 | |||
552 | /* ----------------------------------------------------------- */ | ||
553 | /* tw68-vbi.c */ | ||
554 | |||
555 | extern struct videobuf_queue_ops tw68_vbi_qops; | ||
556 | extern struct video_device tw68_vbi_template; | ||
557 | |||
558 | int tw68_vbi_init1(struct tw68_dev *dev); | ||
559 | int tw68_vbi_fini(struct tw68_dev *dev); | ||
560 | void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status); | ||
561 | |||
562 | /* ----------------------------------------------------------- */ | ||
563 | /* tw68-tvaudio.c */ | ||
564 | |||
565 | int tw68_tvaudio_rx2mode(u32 rx); | ||
566 | |||
567 | void tw68_tvaudio_setmute(struct tw68_dev *dev); | ||
568 | void tw68_tvaudio_setinput(struct tw68_dev *dev, | ||
569 | struct tw68_input *in); | ||
570 | void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level); | ||
571 | int tw68_tvaudio_getstereo(struct tw68_dev *dev); | ||
572 | void tw68_tvaudio_init(struct tw68_dev *dev); | ||
573 | int tw68_tvaudio_init2(struct tw68_dev *dev); | ||
574 | int tw68_tvaudio_fini(struct tw68_dev *dev); | ||
575 | int tw68_tvaudio_do_scan(struct tw68_dev *dev); | ||
576 | int tw_dsp_writel(struct tw68_dev *dev, int reg, u32 value); | ||
577 | void tw68_enable_i2s(struct tw68_dev *dev); | ||
578 | 224 | ||
579 | /* ----------------------------------------------------------- */ | 225 | /* ----------------------------------------------------------- */ |
580 | /* tw68-risc.c */ | 226 | /* tw68-risc.c */ |
581 | 227 | ||
582 | int tw68_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | 228 | int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf, |
583 | struct scatterlist *sglist, unsigned int top_offset, | 229 | struct scatterlist *sglist, unsigned int top_offset, |
584 | unsigned int bottom_offset, unsigned int bpl, | 230 | unsigned int bottom_offset, unsigned int bpl, |
585 | unsigned int padding, unsigned int lines); | 231 | unsigned int padding, unsigned int lines); |
586 | int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc); | ||
587 | int tw68_risc_overlay(struct tw68_fh *fh, struct btcx_riscmem *risc, | ||
588 | int field_type); | ||