diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-03-25 04:35:17 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-25 07:25:07 -0400 |
commit | dcae5dacbce518513abf7776cb450b7bd95d722b (patch) | |
tree | 2e0d8d5376ca5655b38eae279b6112efdca7cc1d | |
parent | c535cc6c714bd21b3afad35baa926b3b9eb51361 (diff) |
[media] solo6x10: sync to latest code from Bluecherry's git repo
Synced to commit e9815ac5503ae60cfbf6ff8037035de8f62e2846 from
branch next in git repository https://github.com/bluecherrydvr/solo6x10.git
Only removed some code under #if LINUX_VERSION_CODE < some-kernel-version,
renamed the driver back to solo6x10 from solo6x10-edge, removed the
unnecessary compat.h header and kept the slab.h includes.
Otherwise the code is identical.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Ismael Luceno <ismael.luceno@corp.bluecherry.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/staging/media/solo6x10/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/TODO | 33 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/core.c | 576 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/disp.c | 127 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/eeprom.c | 154 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/enc.c | 239 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/g723.c | 92 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/gpio.c | 13 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/i2c.c | 26 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/offsets.h | 79 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/osd-font.h | 154 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/p2m.c | 393 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/registers.h | 86 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/solo6x10-jpeg.h | 94 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/solo6x10.h | 198 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/tw28.c | 171 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/tw28.h | 11 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/v4l2-enc.c | 1370 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/v4l2.c | 290 |
19 files changed, 2376 insertions, 1732 deletions
diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile index 337e38c3a0f0..9bbde291d6a3 100644 --- a/drivers/staging/media/solo6x10/Makefile +++ b/drivers/staging/media/solo6x10/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o | 1 | solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o eeprom.o |
2 | 2 | ||
3 | obj-$(CONFIG_SOLO6X10) += solo6x10.o | 3 | obj-$(CONFIG_SOLO6X10) += solo6x10.o |
diff --git a/drivers/staging/media/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO index d09dd03fafba..7b8db75b1acb 100644 --- a/drivers/staging/media/solo6x10/TODO +++ b/drivers/staging/media/solo6x10/TODO | |||
@@ -1,24 +1,15 @@ | |||
1 | TODO (staging => main): | 1 | - batch up desc requests for more efficient use of p2m? |
2 | 2 | - encoder on/off controls | |
3 | * Motion detection flags need to be moved to v4l2 | 3 | - mpeg cid bitrate mode (vbr/cbr) |
4 | * Some private CIDs need to be moved to v4l2 | 4 | - mpeg cid bitrate/bitrate-peak |
5 | 5 | - mpeg encode of user data | |
6 | TODO (general): | 6 | - mpeg decode of user data |
7 | 7 | - implement CID controls for mozaic areas | |
8 | * encoder on/off controls | 8 | |
9 | * mpeg cid bitrate mode (vbr/cbr) | 9 | - sound |
10 | * mpeg cid bitrate/bitrate-peak | 10 | - implement playback via external sound jack |
11 | * mpeg encode of user data | 11 | - implement loopback of external sound jack with incoming audio? |
12 | * mpeg decode of user data | 12 | - implement pause/resume (make use of in bc-server) |
13 | * switch between 4 frames/irq to 1 when using mjpeg (and then back | ||
14 | when not) | ||
15 | * implement a CID control for motion areas/thresholds | ||
16 | * implement CID controls for mozaic areas | ||
17 | * allow for higher level of interval (for < 1 fps) | ||
18 | * sound: | ||
19 | - implement playback via external sound jack | ||
20 | - implement loopback of external sound jack with incoming audio? | ||
21 | - implement pause/resume | ||
22 | 13 | ||
23 | Please send patches to the linux media list <linux-media@vger.kernel.org> and | 14 | Please send patches to the linux media list <linux-media@vger.kernel.org> and |
24 | Cc Ismael Luceno <ismael.luceno@corp.bluecherry.net>. | 15 | Cc Ismael Luceno <ismael.luceno@corp.bluecherry.net>. |
diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index fd83d6d028bf..75d98cc61c40 100644 --- a/drivers/staging/media/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -21,29 +26,79 @@ | |||
21 | #include <linux/module.h> | 26 | #include <linux/module.h> |
22 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
23 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/videodev2.h> | 29 | #include <linux/videodev2.h> |
30 | #include <linux/delay.h> | ||
31 | #include <linux/sysfs.h> | ||
32 | #include <linux/ktime.h> | ||
33 | #include <linux/slab.h> | ||
34 | |||
26 | #include "solo6x10.h" | 35 | #include "solo6x10.h" |
27 | #include "tw28.h" | 36 | #include "tw28.h" |
28 | 37 | ||
29 | MODULE_DESCRIPTION("Softlogic 6x10 MP4/H.264 Encoder/Decoder V4L2/ALSA Driver"); | 38 | MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver"); |
30 | MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>"); | 39 | MODULE_AUTHOR("Bluecherry <maintainers@bluecherrydvr.com>"); |
31 | MODULE_VERSION(SOLO6X10_VERSION); | 40 | MODULE_VERSION(SOLO6X10_VERSION); |
32 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
33 | 42 | ||
34 | void solo_irq_on(struct solo_dev *solo_dev, u32 mask) | 43 | unsigned video_nr = -1; |
44 | module_param(video_nr, uint, 0644); | ||
45 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); | ||
46 | |||
47 | static int full_eeprom; /* default is only top 64B */ | ||
48 | module_param(full_eeprom, uint, 0644); | ||
49 | MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)"); | ||
50 | |||
51 | |||
52 | static void solo_set_time(struct solo_dev *solo_dev) | ||
35 | { | 53 | { |
36 | solo_dev->irq_mask |= mask; | 54 | struct timespec ts; |
37 | solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); | 55 | |
56 | ktime_get_ts(&ts); | ||
57 | |||
58 | solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec); | ||
59 | solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC); | ||
38 | } | 60 | } |
39 | 61 | ||
40 | void solo_irq_off(struct solo_dev *solo_dev, u32 mask) | 62 | static void solo_timer_sync(struct solo_dev *solo_dev) |
41 | { | 63 | { |
42 | solo_dev->irq_mask &= ~mask; | 64 | u32 sec, usec; |
43 | solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); | 65 | struct timespec ts; |
66 | long diff; | ||
67 | |||
68 | if (solo_dev->type != SOLO_DEV_6110) | ||
69 | return; | ||
70 | |||
71 | if (++solo_dev->time_sync < 60) | ||
72 | return; | ||
73 | |||
74 | solo_dev->time_sync = 0; | ||
75 | |||
76 | sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); | ||
77 | usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); | ||
78 | |||
79 | ktime_get_ts(&ts); | ||
80 | |||
81 | diff = (long)ts.tv_sec - (long)sec; | ||
82 | diff = (diff * 1000000) | ||
83 | + ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec); | ||
84 | |||
85 | if (diff > 1000 || diff < -1000) { | ||
86 | solo_set_time(solo_dev); | ||
87 | } else if (diff) { | ||
88 | long usec_lsb = solo_dev->usec_lsb; | ||
89 | |||
90 | usec_lsb -= diff / 4; | ||
91 | if (usec_lsb < 0) | ||
92 | usec_lsb = 0; | ||
93 | else if (usec_lsb > 255) | ||
94 | usec_lsb = 255; | ||
95 | |||
96 | solo_dev->usec_lsb = usec_lsb; | ||
97 | solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, | ||
98 | solo_dev->usec_lsb); | ||
99 | } | ||
44 | } | 100 | } |
45 | 101 | ||
46 | /* XXX We should check the return value of the sub-device ISR's */ | ||
47 | static irqreturn_t solo_isr(int irq, void *data) | 102 | static irqreturn_t solo_isr(int irq, void *data) |
48 | { | 103 | { |
49 | struct solo_dev *solo_dev = data; | 104 | struct solo_dev *solo_dev = data; |
@@ -60,11 +115,8 @@ static irqreturn_t solo_isr(int irq, void *data) | |||
60 | status &= solo_dev->irq_mask; | 115 | status &= solo_dev->irq_mask; |
61 | } | 116 | } |
62 | 117 | ||
63 | if (status & SOLO_IRQ_PCI_ERR) { | 118 | if (status & SOLO_IRQ_PCI_ERR) |
64 | u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR); | 119 | solo_p2m_error_isr(solo_dev); |
65 | solo_p2m_error_isr(solo_dev, err); | ||
66 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR); | ||
67 | } | ||
68 | 120 | ||
69 | for (i = 0; i < SOLO_NR_P2M; i++) | 121 | for (i = 0; i < SOLO_NR_P2M; i++) |
70 | if (status & SOLO_IRQ_P2M(i)) | 122 | if (status & SOLO_IRQ_P2M(i)) |
@@ -73,12 +125,10 @@ static irqreturn_t solo_isr(int irq, void *data) | |||
73 | if (status & SOLO_IRQ_IIC) | 125 | if (status & SOLO_IRQ_IIC) |
74 | solo_i2c_isr(solo_dev); | 126 | solo_i2c_isr(solo_dev); |
75 | 127 | ||
76 | if (status & SOLO_IRQ_VIDEO_IN) | 128 | if (status & SOLO_IRQ_VIDEO_IN) { |
77 | solo_video_in_isr(solo_dev); | 129 | solo_video_in_isr(solo_dev); |
78 | 130 | solo_timer_sync(solo_dev); | |
79 | /* Call this first so enc gets detected flag set */ | 131 | } |
80 | if (status & SOLO_IRQ_MOTION) | ||
81 | solo_motion_isr(solo_dev); | ||
82 | 132 | ||
83 | if (status & SOLO_IRQ_ENCODER) | 133 | if (status & SOLO_IRQ_ENCODER) |
84 | solo_enc_v4l2_isr(solo_dev); | 134 | solo_enc_v4l2_isr(solo_dev); |
@@ -86,6 +136,9 @@ static irqreturn_t solo_isr(int irq, void *data) | |||
86 | if (status & SOLO_IRQ_G723) | 136 | if (status & SOLO_IRQ_G723) |
87 | solo_g723_isr(solo_dev); | 137 | solo_g723_isr(solo_dev); |
88 | 138 | ||
139 | /* Clear all interrupts handled */ | ||
140 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); | ||
141 | |||
89 | return IRQ_HANDLED; | 142 | return IRQ_HANDLED; |
90 | } | 143 | } |
91 | 144 | ||
@@ -96,6 +149,9 @@ static void free_solo_dev(struct solo_dev *solo_dev) | |||
96 | if (!solo_dev) | 149 | if (!solo_dev) |
97 | return; | 150 | return; |
98 | 151 | ||
152 | if (solo_dev->dev.parent) | ||
153 | device_unregister(&solo_dev->dev); | ||
154 | |||
99 | pdev = solo_dev->pdev; | 155 | pdev = solo_dev->pdev; |
100 | 156 | ||
101 | /* If we never initialized the PCI device, then nothing else | 157 | /* If we never initialized the PCI device, then nothing else |
@@ -105,21 +161,22 @@ static void free_solo_dev(struct solo_dev *solo_dev) | |||
105 | return; | 161 | return; |
106 | } | 162 | } |
107 | 163 | ||
108 | /* Bring down the sub-devices first */ | ||
109 | solo_g723_exit(solo_dev); | ||
110 | solo_enc_v4l2_exit(solo_dev); | ||
111 | solo_enc_exit(solo_dev); | ||
112 | solo_v4l2_exit(solo_dev); | ||
113 | solo_disp_exit(solo_dev); | ||
114 | solo_gpio_exit(solo_dev); | ||
115 | solo_p2m_exit(solo_dev); | ||
116 | solo_i2c_exit(solo_dev); | ||
117 | |||
118 | /* Now cleanup the PCI device */ | ||
119 | if (solo_dev->reg_base) { | 164 | if (solo_dev->reg_base) { |
165 | /* Bring down the sub-devices first */ | ||
166 | solo_g723_exit(solo_dev); | ||
167 | solo_enc_v4l2_exit(solo_dev); | ||
168 | solo_enc_exit(solo_dev); | ||
169 | solo_v4l2_exit(solo_dev); | ||
170 | solo_disp_exit(solo_dev); | ||
171 | solo_gpio_exit(solo_dev); | ||
172 | solo_p2m_exit(solo_dev); | ||
173 | solo_i2c_exit(solo_dev); | ||
174 | |||
175 | /* Now cleanup the PCI device */ | ||
120 | solo_irq_off(solo_dev, ~0); | 176 | solo_irq_off(solo_dev, ~0); |
121 | pci_iounmap(pdev, solo_dev->reg_base); | 177 | pci_iounmap(pdev, solo_dev->reg_base); |
122 | free_irq(pdev->irq, solo_dev); | 178 | if (pdev->irq) |
179 | free_irq(pdev->irq, solo_dev); | ||
123 | } | 180 | } |
124 | 181 | ||
125 | pci_release_regions(pdev); | 182 | pci_release_regions(pdev); |
@@ -129,29 +186,346 @@ static void free_solo_dev(struct solo_dev *solo_dev) | |||
129 | kfree(solo_dev); | 186 | kfree(solo_dev); |
130 | } | 187 | } |
131 | 188 | ||
132 | static int solo_pci_probe(struct pci_dev *pdev, | 189 | static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr, |
133 | const struct pci_device_id *id) | 190 | const char *buf, size_t count) |
191 | { | ||
192 | struct solo_dev *solo_dev = | ||
193 | container_of(dev, struct solo_dev, dev); | ||
194 | unsigned short *p = (unsigned short *)buf; | ||
195 | int i; | ||
196 | |||
197 | if (count & 0x1) | ||
198 | dev_warn(dev, "EEPROM Write not aligned (truncating)\n"); | ||
199 | |||
200 | if (!full_eeprom && count > 64) { | ||
201 | dev_warn(dev, "EEPROM Write truncated to 64 bytes\n"); | ||
202 | count = 64; | ||
203 | } else if (full_eeprom && count > 128) { | ||
204 | dev_warn(dev, "EEPROM Write truncated to 128 bytes\n"); | ||
205 | count = 128; | ||
206 | } | ||
207 | |||
208 | solo_eeprom_ewen(solo_dev, 1); | ||
209 | |||
210 | for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32), | ||
211 | (int)(count / 2)); i++) | ||
212 | solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i])); | ||
213 | |||
214 | solo_eeprom_ewen(solo_dev, 0); | ||
215 | |||
216 | return count; | ||
217 | } | ||
218 | |||
219 | static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, | ||
220 | char *buf) | ||
221 | { | ||
222 | struct solo_dev *solo_dev = | ||
223 | container_of(dev, struct solo_dev, dev); | ||
224 | unsigned short *p = (unsigned short *)buf; | ||
225 | int count = (full_eeprom ? 128 : 64); | ||
226 | int i; | ||
227 | |||
228 | for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++) | ||
229 | p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i)); | ||
230 | |||
231 | return count; | ||
232 | } | ||
233 | |||
234 | static ssize_t video_type_store(struct device *dev, | ||
235 | struct device_attribute *attr, | ||
236 | const char *buf, size_t count) | ||
237 | { | ||
238 | return -EPERM; | ||
239 | } | ||
240 | |||
241 | static ssize_t video_type_show(struct device *dev, | ||
242 | struct device_attribute *attr, | ||
243 | char *buf) | ||
244 | { | ||
245 | struct solo_dev *solo_dev = | ||
246 | container_of(dev, struct solo_dev, dev); | ||
247 | |||
248 | return sprintf(buf, "%s", solo_dev->video_type == | ||
249 | SOLO_VO_FMT_TYPE_NTSC ? "NTSC" : "PAL"); | ||
250 | } | ||
251 | |||
252 | static ssize_t p2m_timeouts_show(struct device *dev, | ||
253 | struct device_attribute *attr, | ||
254 | char *buf) | ||
255 | { | ||
256 | struct solo_dev *solo_dev = | ||
257 | container_of(dev, struct solo_dev, dev); | ||
258 | |||
259 | return sprintf(buf, "%d\n", solo_dev->p2m_timeouts); | ||
260 | } | ||
261 | |||
262 | static ssize_t sdram_size_show(struct device *dev, | ||
263 | struct device_attribute *attr, | ||
264 | char *buf) | ||
265 | { | ||
266 | struct solo_dev *solo_dev = | ||
267 | container_of(dev, struct solo_dev, dev); | ||
268 | |||
269 | return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20); | ||
270 | } | ||
271 | |||
272 | static ssize_t tw28xx_show(struct device *dev, | ||
273 | struct device_attribute *attr, | ||
274 | char *buf) | ||
275 | { | ||
276 | struct solo_dev *solo_dev = | ||
277 | container_of(dev, struct solo_dev, dev); | ||
278 | |||
279 | return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n", | ||
280 | hweight32(solo_dev->tw2815), | ||
281 | hweight32(solo_dev->tw2864), | ||
282 | hweight32(solo_dev->tw2865)); | ||
283 | } | ||
284 | |||
285 | static ssize_t input_map_show(struct device *dev, | ||
286 | struct device_attribute *attr, | ||
287 | char *buf) | ||
288 | { | ||
289 | struct solo_dev *solo_dev = | ||
290 | container_of(dev, struct solo_dev, dev); | ||
291 | unsigned int val; | ||
292 | char *out = buf; | ||
293 | |||
294 | val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0); | ||
295 | out += sprintf(out, "Channel 0 => Input %d\n", val & 0x1f); | ||
296 | out += sprintf(out, "Channel 1 => Input %d\n", (val >> 5) & 0x1f); | ||
297 | out += sprintf(out, "Channel 2 => Input %d\n", (val >> 10) & 0x1f); | ||
298 | out += sprintf(out, "Channel 3 => Input %d\n", (val >> 15) & 0x1f); | ||
299 | out += sprintf(out, "Channel 4 => Input %d\n", (val >> 20) & 0x1f); | ||
300 | out += sprintf(out, "Channel 5 => Input %d\n", (val >> 25) & 0x1f); | ||
301 | |||
302 | val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1); | ||
303 | out += sprintf(out, "Channel 6 => Input %d\n", val & 0x1f); | ||
304 | out += sprintf(out, "Channel 7 => Input %d\n", (val >> 5) & 0x1f); | ||
305 | out += sprintf(out, "Channel 8 => Input %d\n", (val >> 10) & 0x1f); | ||
306 | out += sprintf(out, "Channel 9 => Input %d\n", (val >> 15) & 0x1f); | ||
307 | out += sprintf(out, "Channel 10 => Input %d\n", (val >> 20) & 0x1f); | ||
308 | out += sprintf(out, "Channel 11 => Input %d\n", (val >> 25) & 0x1f); | ||
309 | |||
310 | val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2); | ||
311 | out += sprintf(out, "Channel 12 => Input %d\n", val & 0x1f); | ||
312 | out += sprintf(out, "Channel 13 => Input %d\n", (val >> 5) & 0x1f); | ||
313 | out += sprintf(out, "Channel 14 => Input %d\n", (val >> 10) & 0x1f); | ||
314 | out += sprintf(out, "Channel 15 => Input %d\n", (val >> 15) & 0x1f); | ||
315 | out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f); | ||
316 | |||
317 | return out - buf; | ||
318 | } | ||
319 | |||
320 | static ssize_t p2m_timeout_store(struct device *dev, | ||
321 | struct device_attribute *attr, | ||
322 | const char *buf, size_t count) | ||
323 | { | ||
324 | struct solo_dev *solo_dev = | ||
325 | container_of(dev, struct solo_dev, dev); | ||
326 | unsigned long ms; | ||
327 | |||
328 | int ret = kstrtoul(buf, 10, &ms); | ||
329 | if (ret < 0 || ms > 200) | ||
330 | return -EINVAL; | ||
331 | solo_dev->p2m_jiffies = msecs_to_jiffies(ms); | ||
332 | |||
333 | return count; | ||
334 | } | ||
335 | |||
336 | static ssize_t p2m_timeout_show(struct device *dev, | ||
337 | struct device_attribute *attr, | ||
338 | char *buf) | ||
339 | { | ||
340 | struct solo_dev *solo_dev = | ||
341 | container_of(dev, struct solo_dev, dev); | ||
342 | |||
343 | return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies)); | ||
344 | } | ||
345 | |||
346 | static ssize_t intervals_show(struct device *dev, | ||
347 | struct device_attribute *attr, | ||
348 | char *buf) | ||
349 | { | ||
350 | struct solo_dev *solo_dev = | ||
351 | container_of(dev, struct solo_dev, dev); | ||
352 | char *out = buf; | ||
353 | int fps = solo_dev->fps; | ||
354 | int i; | ||
355 | |||
356 | for (i = 0; i < solo_dev->nr_chans; i++) { | ||
357 | out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n", | ||
358 | i, solo_dev->v4l2_enc[i]->interval, fps, | ||
359 | solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i))); | ||
360 | } | ||
361 | |||
362 | return out - buf; | ||
363 | } | ||
364 | |||
365 | static ssize_t sdram_offsets_show(struct device *dev, | ||
366 | struct device_attribute *attr, | ||
367 | char *buf) | ||
368 | { | ||
369 | struct solo_dev *solo_dev = | ||
370 | container_of(dev, struct solo_dev, dev); | ||
371 | char *out = buf; | ||
372 | |||
373 | out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n", | ||
374 | SOLO_DISP_EXT_ADDR, | ||
375 | SOLO_DISP_EXT_SIZE); | ||
376 | |||
377 | out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n", | ||
378 | SOLO_EOSD_EXT_ADDR, | ||
379 | SOLO_EOSD_EXT_AREA(solo_dev), | ||
380 | SOLO_EOSD_EXT_SIZE(solo_dev), | ||
381 | SOLO_EOSD_EXT_AREA(solo_dev) / | ||
382 | SOLO_EOSD_EXT_SIZE(solo_dev)); | ||
383 | |||
384 | out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n", | ||
385 | SOLO_MOTION_EXT_ADDR(solo_dev), | ||
386 | SOLO_MOTION_EXT_SIZE); | ||
387 | |||
388 | out += sprintf(out, "G723: 0x%08x @ 0x%08x\n", | ||
389 | SOLO_G723_EXT_ADDR(solo_dev), | ||
390 | SOLO_G723_EXT_SIZE); | ||
391 | |||
392 | out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n", | ||
393 | SOLO_CAP_EXT_ADDR(solo_dev), | ||
394 | SOLO_CAP_EXT_SIZE(solo_dev), | ||
395 | SOLO_CAP_PAGE_SIZE, | ||
396 | SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE); | ||
397 | |||
398 | out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n", | ||
399 | SOLO_EREF_EXT_ADDR(solo_dev), | ||
400 | SOLO_EREF_EXT_AREA(solo_dev), | ||
401 | SOLO_EREF_EXT_SIZE, | ||
402 | SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE); | ||
403 | |||
404 | out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n", | ||
405 | SOLO_MP4E_EXT_ADDR(solo_dev), | ||
406 | SOLO_MP4E_EXT_SIZE(solo_dev)); | ||
407 | |||
408 | out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n", | ||
409 | SOLO_JPEG_EXT_ADDR(solo_dev), | ||
410 | SOLO_JPEG_EXT_SIZE(solo_dev)); | ||
411 | |||
412 | return out - buf; | ||
413 | } | ||
414 | |||
415 | static ssize_t sdram_show(struct file *file, struct kobject *kobj, | ||
416 | struct bin_attribute *a, char *buf, | ||
417 | loff_t off, size_t count) | ||
418 | { | ||
419 | struct device *dev = container_of(kobj, struct device, kobj); | ||
420 | struct solo_dev *solo_dev = | ||
421 | container_of(dev, struct solo_dev, dev); | ||
422 | const int size = solo_dev->sdram_size; | ||
423 | |||
424 | if (off >= size) | ||
425 | return 0; | ||
426 | |||
427 | if (off + count > size) | ||
428 | count = size - off; | ||
429 | |||
430 | if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0)) | ||
431 | return -EIO; | ||
432 | |||
433 | return count; | ||
434 | } | ||
435 | |||
436 | static const struct device_attribute solo_dev_attrs[] = { | ||
437 | __ATTR(eeprom, 0640, eeprom_show, eeprom_store), | ||
438 | __ATTR(video_type, 0644, video_type_show, video_type_store), | ||
439 | __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store), | ||
440 | __ATTR_RO(p2m_timeouts), | ||
441 | __ATTR_RO(sdram_size), | ||
442 | __ATTR_RO(tw28xx), | ||
443 | __ATTR_RO(input_map), | ||
444 | __ATTR_RO(intervals), | ||
445 | __ATTR_RO(sdram_offsets), | ||
446 | }; | ||
447 | |||
448 | static void solo_device_release(struct device *dev) | ||
449 | { | ||
450 | /* Do nothing */ | ||
451 | } | ||
452 | |||
453 | static int solo_sysfs_init(struct solo_dev *solo_dev) | ||
454 | { | ||
455 | struct bin_attribute *sdram_attr = &solo_dev->sdram_attr; | ||
456 | struct device *dev = &solo_dev->dev; | ||
457 | const char *driver; | ||
458 | int i; | ||
459 | |||
460 | if (solo_dev->type == SOLO_DEV_6110) | ||
461 | driver = "solo6110"; | ||
462 | else | ||
463 | driver = "solo6010"; | ||
464 | |||
465 | dev->release = solo_device_release; | ||
466 | dev->parent = &solo_dev->pdev->dev; | ||
467 | set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev)); | ||
468 | dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num, | ||
469 | solo_dev->nr_chans); | ||
470 | |||
471 | if (device_register(dev)) { | ||
472 | dev->parent = NULL; | ||
473 | return -ENOMEM; | ||
474 | } | ||
475 | |||
476 | for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) { | ||
477 | if (device_create_file(dev, &solo_dev_attrs[i])) { | ||
478 | device_unregister(dev); | ||
479 | return -ENOMEM; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | sdram_attr->attr.name = "sdram"; | ||
484 | sdram_attr->attr.mode = 0440; | ||
485 | sdram_attr->read = sdram_show; | ||
486 | sdram_attr->size = solo_dev->sdram_size; | ||
487 | |||
488 | if (device_create_bin_file(dev, sdram_attr)) { | ||
489 | device_unregister(dev); | ||
490 | return -ENOMEM; | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
134 | { | 497 | { |
135 | struct solo_dev *solo_dev; | 498 | struct solo_dev *solo_dev; |
136 | int ret; | 499 | int ret; |
137 | int sdram; | ||
138 | u8 chip_id; | 500 | u8 chip_id; |
139 | u32 reg; | ||
140 | 501 | ||
141 | solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); | 502 | solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); |
142 | if (solo_dev == NULL) | 503 | if (solo_dev == NULL) |
143 | return -ENOMEM; | 504 | return -ENOMEM; |
144 | 505 | ||
506 | if (id->driver_data == SOLO_DEV_6010) | ||
507 | dev_info(&pdev->dev, "Probing Softlogic 6010\n"); | ||
508 | else | ||
509 | dev_info(&pdev->dev, "Probing Softlogic 6110\n"); | ||
510 | |||
511 | solo_dev->type = id->driver_data; | ||
145 | solo_dev->pdev = pdev; | 512 | solo_dev->pdev = pdev; |
146 | spin_lock_init(&solo_dev->reg_io_lock); | 513 | spin_lock_init(&solo_dev->reg_io_lock); |
147 | pci_set_drvdata(pdev, solo_dev); | 514 | pci_set_drvdata(pdev, solo_dev); |
148 | 515 | ||
516 | /* Only for during init */ | ||
517 | solo_dev->p2m_jiffies = msecs_to_jiffies(100); | ||
518 | |||
149 | ret = pci_enable_device(pdev); | 519 | ret = pci_enable_device(pdev); |
150 | if (ret) | 520 | if (ret) |
151 | goto fail_probe; | 521 | goto fail_probe; |
152 | 522 | ||
153 | pci_set_master(pdev); | 523 | pci_set_master(pdev); |
154 | 524 | ||
525 | /* RETRY/TRDY Timeout disabled */ | ||
526 | pci_write_config_byte(pdev, 0x40, 0x00); | ||
527 | pci_write_config_byte(pdev, 0x41, 0x00); | ||
528 | |||
155 | ret = pci_request_regions(pdev, SOLO6X10_NAME); | 529 | ret = pci_request_regions(pdev, SOLO6X10_NAME); |
156 | if (ret) | 530 | if (ret) |
157 | goto fail_probe; | 531 | goto fail_probe; |
@@ -163,7 +537,7 @@ static int solo_pci_probe(struct pci_dev *pdev, | |||
163 | } | 537 | } |
164 | 538 | ||
165 | chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & | 539 | chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & |
166 | SOLO_CHIP_ID_MASK; | 540 | SOLO_CHIP_ID_MASK; |
167 | switch (chip_id) { | 541 | switch (chip_id) { |
168 | case 7: | 542 | case 7: |
169 | solo_dev->nr_chans = 16; | 543 | solo_dev->nr_chans = 16; |
@@ -174,52 +548,50 @@ static int solo_pci_probe(struct pci_dev *pdev, | |||
174 | solo_dev->nr_ext = 2; | 548 | solo_dev->nr_ext = 2; |
175 | break; | 549 | break; |
176 | default: | 550 | default: |
177 | dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, " | 551 | dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n", |
178 | "defaulting to 4 channels\n", | ||
179 | chip_id); | 552 | chip_id); |
180 | case 5: | 553 | case 5: |
181 | solo_dev->nr_chans = 4; | 554 | solo_dev->nr_chans = 4; |
182 | solo_dev->nr_ext = 1; | 555 | solo_dev->nr_ext = 1; |
183 | } | 556 | } |
184 | 557 | ||
185 | solo_dev->flags = id->driver_data; | ||
186 | |||
187 | /* Disable all interrupts to start */ | 558 | /* Disable all interrupts to start */ |
188 | solo_irq_off(solo_dev, ~0); | 559 | solo_irq_off(solo_dev, ~0); |
189 | 560 | ||
190 | reg = SOLO_SYS_CFG_SDRAM64BIT; | ||
191 | /* Initial global settings */ | 561 | /* Initial global settings */ |
192 | if (!(solo_dev->flags & FLAGS_6110)) | 562 | if (solo_dev->type == SOLO_DEV_6010) { |
193 | reg |= SOLO6010_SYS_CFG_INPUTDIV(25) | | 563 | solo_dev->clock_mhz = 108; |
194 | SOLO6010_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) | | 564 | solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT |
195 | SOLO6010_SYS_CFG_OUTDIV(3); | 565 | | SOLO_SYS_CFG_INPUTDIV(25) |
196 | solo_reg_write(solo_dev, SOLO_SYS_CFG, reg); | 566 | | SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2) |
197 | 567 | | SOLO_SYS_CFG_OUTDIV(3); | |
198 | if (solo_dev->flags & FLAGS_6110) { | 568 | solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); |
199 | u32 sys_clock_MHz = SOLO_CLOCK_MHZ; | 569 | } else { |
200 | u32 pll_DIVQ; | 570 | u32 divq, divf; |
201 | u32 pll_DIVF; | 571 | |
202 | 572 | solo_dev->clock_mhz = 135; | |
203 | if (sys_clock_MHz < 125) { | 573 | |
204 | pll_DIVQ = 3; | 574 | if (solo_dev->clock_mhz < 125) { |
205 | pll_DIVF = (sys_clock_MHz * 4) / 3; | 575 | divq = 3; |
576 | divf = (solo_dev->clock_mhz * 4) / 3 - 1; | ||
206 | } else { | 577 | } else { |
207 | pll_DIVQ = 2; | 578 | divq = 2; |
208 | pll_DIVF = (sys_clock_MHz * 2) / 3; | 579 | divf = (solo_dev->clock_mhz * 2) / 3 - 1; |
209 | } | 580 | } |
210 | 581 | ||
211 | solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG, | 582 | solo_reg_write(solo_dev, SOLO_PLL_CONFIG, |
212 | SOLO6110_PLL_RANGE_5_10MHZ | | 583 | (1 << 20) | /* PLL_RANGE */ |
213 | SOLO6110_PLL_DIVR(9) | | 584 | (8 << 15) | /* PLL_DIVR */ |
214 | SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) | | 585 | (divq << 12) | |
215 | SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN); | 586 | (divf << 4) | |
216 | mdelay(1); /* PLL Locking time (1ms) */ | 587 | (1 << 1) /* PLL_FSEN */); |
217 | 588 | ||
218 | solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */ | 589 | solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT; |
219 | } else | 590 | } |
220 | solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */ | ||
221 | 591 | ||
222 | solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1); | 592 | solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); |
593 | solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, | ||
594 | solo_dev->clock_mhz - 1); | ||
223 | 595 | ||
224 | /* PLL locking time of 1ms */ | 596 | /* PLL locking time of 1ms */ |
225 | mdelay(1); | 597 | mdelay(1); |
@@ -237,14 +609,27 @@ static int solo_pci_probe(struct pci_dev *pdev, | |||
237 | goto fail_probe; | 609 | goto fail_probe; |
238 | 610 | ||
239 | /* Setup the DMA engine */ | 611 | /* Setup the DMA engine */ |
240 | sdram = (solo_dev->nr_chans >= 8) ? 2 : 1; | ||
241 | solo_reg_write(solo_dev, SOLO_DMA_CTRL, | 612 | solo_reg_write(solo_dev, SOLO_DMA_CTRL, |
242 | SOLO_DMA_CTRL_REFRESH_CYCLE(1) | | 613 | SOLO_DMA_CTRL_REFRESH_CYCLE(1) | |
243 | SOLO_DMA_CTRL_SDRAM_SIZE(sdram) | | 614 | SOLO_DMA_CTRL_SDRAM_SIZE(2) | |
244 | SOLO_DMA_CTRL_SDRAM_CLK_INVERT | | 615 | SOLO_DMA_CTRL_SDRAM_CLK_INVERT | |
245 | SOLO_DMA_CTRL_READ_CLK_SELECT | | 616 | SOLO_DMA_CTRL_READ_CLK_SELECT | |
246 | SOLO_DMA_CTRL_LATENCY(1)); | 617 | SOLO_DMA_CTRL_LATENCY(1)); |
247 | 618 | ||
619 | /* Undocumented crap */ | ||
620 | solo_reg_write(solo_dev, SOLO_DMA_CTRL1, | ||
621 | solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300); | ||
622 | |||
623 | if (solo_dev->type != SOLO_DEV_6010) { | ||
624 | solo_dev->usec_lsb = 0x3f; | ||
625 | solo_set_time(solo_dev); | ||
626 | } | ||
627 | |||
628 | /* Disable watchdog */ | ||
629 | solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); | ||
630 | |||
631 | /* Initialize sub components */ | ||
632 | |||
248 | ret = solo_p2m_init(solo_dev); | 633 | ret = solo_p2m_init(solo_dev); |
249 | if (ret) | 634 | if (ret) |
250 | goto fail_probe; | 635 | goto fail_probe; |
@@ -261,7 +646,7 @@ static int solo_pci_probe(struct pci_dev *pdev, | |||
261 | if (ret) | 646 | if (ret) |
262 | goto fail_probe; | 647 | goto fail_probe; |
263 | 648 | ||
264 | ret = solo_v4l2_init(solo_dev); | 649 | ret = solo_v4l2_init(solo_dev, video_nr); |
265 | if (ret) | 650 | if (ret) |
266 | goto fail_probe; | 651 | goto fail_probe; |
267 | 652 | ||
@@ -269,7 +654,7 @@ static int solo_pci_probe(struct pci_dev *pdev, | |||
269 | if (ret) | 654 | if (ret) |
270 | goto fail_probe; | 655 | goto fail_probe; |
271 | 656 | ||
272 | ret = solo_enc_v4l2_init(solo_dev); | 657 | ret = solo_enc_v4l2_init(solo_dev, video_nr); |
273 | if (ret) | 658 | if (ret) |
274 | goto fail_probe; | 659 | goto fail_probe; |
275 | 660 | ||
@@ -277,6 +662,13 @@ static int solo_pci_probe(struct pci_dev *pdev, | |||
277 | if (ret) | 662 | if (ret) |
278 | goto fail_probe; | 663 | goto fail_probe; |
279 | 664 | ||
665 | ret = solo_sysfs_init(solo_dev); | ||
666 | if (ret) | ||
667 | goto fail_probe; | ||
668 | |||
669 | /* Now that init is over, set this lower */ | ||
670 | solo_dev->p2m_jiffies = msecs_to_jiffies(20); | ||
671 | |||
280 | return 0; | 672 | return 0; |
281 | 673 | ||
282 | fail_probe: | 674 | fail_probe: |
@@ -291,21 +683,31 @@ static void solo_pci_remove(struct pci_dev *pdev) | |||
291 | free_solo_dev(solo_dev); | 683 | free_solo_dev(solo_dev); |
292 | } | 684 | } |
293 | 685 | ||
294 | static struct pci_device_id solo_id_table[] = { | 686 | static DEFINE_PCI_DEVICE_TABLE(solo_id_table) = { |
295 | /* 6010 based cards */ | 687 | /* 6010 based cards */ |
296 | {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)}, | 688 | { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010), |
297 | {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), | 689 | .driver_data = SOLO_DEV_6010 }, |
298 | .driver_data = FLAGS_6110}, | 690 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4), |
299 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)}, | 691 | .driver_data = SOLO_DEV_6010 }, |
300 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)}, | 692 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9), |
301 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)}, | 693 | .driver_data = SOLO_DEV_6010 }, |
302 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)}, | 694 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16), |
303 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)}, | 695 | .driver_data = SOLO_DEV_6010 }, |
304 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)}, | 696 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4), |
697 | .driver_data = SOLO_DEV_6010 }, | ||
698 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9), | ||
699 | .driver_data = SOLO_DEV_6010 }, | ||
700 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16), | ||
701 | .driver_data = SOLO_DEV_6010 }, | ||
305 | /* 6110 based cards */ | 702 | /* 6110 based cards */ |
306 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)}, | 703 | { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), |
307 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)}, | 704 | .driver_data = SOLO_DEV_6110 }, |
308 | {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)}, | 705 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4), |
706 | .driver_data = SOLO_DEV_6110 }, | ||
707 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8), | ||
708 | .driver_data = SOLO_DEV_6110 }, | ||
709 | { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), | ||
710 | .driver_data = SOLO_DEV_6110 }, | ||
309 | {0,} | 711 | {0,} |
310 | }; | 712 | }; |
311 | 713 | ||
diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index 884c0eb757c4..ddd85e72dd70 100644 --- a/drivers/staging/media/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -21,6 +26,7 @@ | |||
21 | #include <linux/module.h> | 26 | #include <linux/module.h> |
22 | #include <linux/videodev2.h> | 27 | #include <linux/videodev2.h> |
23 | #include <media/v4l2-ioctl.h> | 28 | #include <media/v4l2-ioctl.h> |
29 | |||
24 | #include "solo6x10.h" | 30 | #include "solo6x10.h" |
25 | 31 | ||
26 | #define SOLO_VCLK_DELAY 3 | 32 | #define SOLO_VCLK_DELAY 3 |
@@ -30,8 +36,8 @@ | |||
30 | #define SOLO_MOT_THRESH_H 64 | 36 | #define SOLO_MOT_THRESH_H 64 |
31 | #define SOLO_MOT_THRESH_SIZE 8192 | 37 | #define SOLO_MOT_THRESH_SIZE 8192 |
32 | #define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) | 38 | #define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) |
33 | #define SOLO_MOT_FLAG_SIZE 512 | 39 | #define SOLO_MOT_FLAG_SIZE 1024 |
34 | #define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32) | 40 | #define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) |
35 | 41 | ||
36 | static unsigned video_type; | 42 | static unsigned video_type; |
37 | module_param(video_type, uint, 0644); | 43 | module_param(video_type, uint, 0644); |
@@ -73,7 +79,12 @@ static void solo_vin_config(struct solo_dev *solo_dev) | |||
73 | solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, | 79 | solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, |
74 | SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); | 80 | SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); |
75 | 81 | ||
76 | solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); | 82 | /* On 6110, initialize mozaic darkness stength */ |
83 | if (solo_dev->type == SOLO_DEV_6010) | ||
84 | solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); | ||
85 | else | ||
86 | solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22); | ||
87 | |||
77 | solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); | 88 | solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); |
78 | 89 | ||
79 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { | 90 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { |
@@ -97,21 +108,30 @@ static void solo_vin_config(struct solo_dev *solo_dev) | |||
97 | SOLO_VI_PB_HSTOP(16 + 720)); | 108 | SOLO_VI_PB_HSTOP(16 + 720)); |
98 | } | 109 | } |
99 | 110 | ||
100 | static void solo_disp_config(struct solo_dev *solo_dev) | 111 | static void solo_vout_config_cursor(struct solo_dev *dev) |
112 | { | ||
113 | int i; | ||
114 | |||
115 | /* Load (blank) cursor bitmap mask (2bpp) */ | ||
116 | for (i = 0; i < 20; i++) | ||
117 | solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0); | ||
118 | |||
119 | solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0); | ||
120 | |||
121 | solo_reg_write(dev, SOLO_VO_CURSOR_CLR, | ||
122 | (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80); | ||
123 | solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80); | ||
124 | } | ||
125 | |||
126 | static void solo_vout_config(struct solo_dev *solo_dev) | ||
101 | { | 127 | { |
102 | solo_dev->vout_hstart = 6; | 128 | solo_dev->vout_hstart = 6; |
103 | solo_dev->vout_vstart = 8; | 129 | solo_dev->vout_vstart = 8; |
104 | 130 | ||
105 | solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, | ||
106 | (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); | ||
107 | solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, | ||
108 | (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); | ||
109 | solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, | ||
110 | (16 << 24) | (128 << 16) | (16 << 8) | 128); | ||
111 | |||
112 | solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, | 131 | solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, |
113 | solo_dev->video_type | | 132 | solo_dev->video_type | |
114 | SOLO_VO_USER_COLOR_SET_NAV | | 133 | SOLO_VO_USER_COLOR_SET_NAV | |
134 | SOLO_VO_USER_COLOR_SET_NAH | | ||
115 | SOLO_VO_NA_COLOR_Y(0) | | 135 | SOLO_VO_NA_COLOR_Y(0) | |
116 | SOLO_VO_NA_COLOR_CB(0) | | 136 | SOLO_VO_NA_COLOR_CB(0) | |
117 | SOLO_VO_NA_COLOR_CR(0)); | 137 | SOLO_VO_NA_COLOR_CR(0)); |
@@ -130,19 +150,31 @@ static void solo_disp_config(struct solo_dev *solo_dev) | |||
130 | SOLO_VO_H_LEN(solo_dev->video_hsize) | | 150 | SOLO_VO_H_LEN(solo_dev->video_hsize) | |
131 | SOLO_VO_V_LEN(solo_dev->video_vsize)); | 151 | SOLO_VO_V_LEN(solo_dev->video_vsize)); |
132 | 152 | ||
133 | solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5); | 153 | /* Border & background colors */ |
154 | solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, | ||
155 | (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); | ||
156 | solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, | ||
157 | (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); | ||
158 | solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, | ||
159 | (16 << 24) | (128 << 16) | (16 << 8) | 128); | ||
160 | |||
161 | solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); | ||
162 | |||
163 | solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0); | ||
164 | |||
165 | solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); | ||
166 | solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); | ||
134 | 167 | ||
135 | solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | | 168 | solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | |
136 | SOLO_VO_DISP_ERASE_COUNT(8) | | 169 | SOLO_VO_DISP_ERASE_COUNT(8) | |
137 | SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); | 170 | SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); |
138 | 171 | ||
139 | solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); | ||
140 | 172 | ||
141 | /* Enable channels we support */ | 173 | solo_vout_config_cursor(solo_dev); |
142 | solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1); | ||
143 | 174 | ||
144 | /* Disable the watchdog */ | 175 | /* Enable channels we support */ |
145 | solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); | 176 | solo_reg_write(solo_dev, SOLO_VI_CH_ENA, |
177 | (1 << solo_dev->nr_chans) - 1); | ||
146 | } | 178 | } |
147 | 179 | ||
148 | static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, | 180 | static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, |
@@ -156,26 +188,53 @@ static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, | |||
156 | buf[i] = val; | 188 | buf[i] = val; |
157 | 189 | ||
158 | for (i = 0; i < reg_size; i += sizeof(buf)) | 190 | for (i = 0; i < reg_size; i += sizeof(buf)) |
159 | ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf, | 191 | ret |= solo_p2m_dma(solo_dev, 1, buf, |
160 | SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, | 192 | SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, |
161 | sizeof(buf)); | 193 | sizeof(buf), 0, 0); |
162 | 194 | ||
163 | return ret; | 195 | return ret; |
164 | } | 196 | } |
165 | 197 | ||
166 | void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) | 198 | int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) |
167 | { | 199 | { |
168 | if (ch > solo_dev->nr_chans) | 200 | if (ch > solo_dev->nr_chans) |
169 | return; | 201 | return -EINVAL; |
170 | 202 | ||
171 | solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + | 203 | return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + |
172 | (ch * SOLO_MOT_THRESH_SIZE * 2), | 204 | (ch * SOLO_MOT_THRESH_SIZE * 2), |
173 | val, SOLO_MOT_THRESH_REAL); | 205 | val, SOLO_MOT_THRESH_SIZE); |
206 | } | ||
207 | |||
208 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, | ||
209 | u16 block) | ||
210 | { | ||
211 | u16 buf[64]; | ||
212 | u32 addr; | ||
213 | int re; | ||
214 | |||
215 | addr = SOLO_MOTION_EXT_ADDR(solo_dev) + | ||
216 | SOLO_MOT_FLAG_AREA + | ||
217 | (SOLO_MOT_THRESH_SIZE * 2 * ch) + | ||
218 | (block * 2); | ||
219 | |||
220 | /* Read and write only on a 128-byte boundary; 4-byte writes with | ||
221 | solo_p2m_dma silently failed. Bluecherry bug #908. */ | ||
222 | re = solo_p2m_dma(solo_dev, 0, &buf, addr & ~0x7f, sizeof(buf), 0, 0); | ||
223 | if (re) | ||
224 | return re; | ||
225 | |||
226 | buf[(addr & 0x7f) / 2] = val; | ||
227 | |||
228 | re = solo_p2m_dma(solo_dev, 1, &buf, addr & ~0x7f, sizeof(buf), 0, 0); | ||
229 | if (re) | ||
230 | return re; | ||
231 | |||
232 | return 0; | ||
174 | } | 233 | } |
175 | 234 | ||
176 | /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k | 235 | /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k |
177 | * threshold and working table for each channel. Atleast that's what the | 236 | * threshold and working table for each channel. Atleast that's what the |
178 | * spec says. However, this code (take from rdk) has some mystery 8k | 237 | * spec says. However, this code (taken from rdk) has some mystery 8k |
179 | * block right after the flag area, before the first thresh table. */ | 238 | * block right after the flag area, before the first thresh table. */ |
180 | static void solo_motion_config(struct solo_dev *solo_dev) | 239 | static void solo_motion_config(struct solo_dev *solo_dev) |
181 | { | 240 | { |
@@ -188,9 +247,9 @@ static void solo_motion_config(struct solo_dev *solo_dev) | |||
188 | 247 | ||
189 | /* Clear working cache table */ | 248 | /* Clear working cache table */ |
190 | solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + | 249 | solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + |
191 | SOLO_MOT_THRESH_SIZE + | 250 | (i * SOLO_MOT_THRESH_SIZE * 2) + |
192 | (i * SOLO_MOT_THRESH_SIZE * 2), | 251 | SOLO_MOT_THRESH_SIZE, 0x0000, |
193 | 0x0000, SOLO_MOT_THRESH_REAL); | 252 | SOLO_MOT_THRESH_SIZE); |
194 | 253 | ||
195 | /* Set default threshold table */ | 254 | /* Set default threshold table */ |
196 | solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); | 255 | solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); |
@@ -202,8 +261,8 @@ static void solo_motion_config(struct solo_dev *solo_dev) | |||
202 | solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, | 261 | solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, |
203 | SOLO_VI_MOTION_FRAME_COUNT(3) | | 262 | SOLO_VI_MOTION_FRAME_COUNT(3) | |
204 | SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) | 263 | SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) |
205 | | /* SOLO_VI_MOTION_INTR_START_STOP | */ | 264 | /* | SOLO_VI_MOTION_INTR_START_STOP */ |
206 | SOLO_VI_MOTION_SAMPLE_COUNT(10)); | 265 | | SOLO_VI_MOTION_SAMPLE_COUNT(10)); |
207 | 266 | ||
208 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); | 267 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); |
209 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); | 268 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); |
@@ -226,7 +285,7 @@ int solo_disp_init(struct solo_dev *solo_dev) | |||
226 | 285 | ||
227 | solo_vin_config(solo_dev); | 286 | solo_vin_config(solo_dev); |
228 | solo_motion_config(solo_dev); | 287 | solo_motion_config(solo_dev); |
229 | solo_disp_config(solo_dev); | 288 | solo_vout_config(solo_dev); |
230 | 289 | ||
231 | for (i = 0; i < solo_dev->nr_chans; i++) | 290 | for (i = 0; i < solo_dev->nr_chans; i++) |
232 | solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); | 291 | solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); |
@@ -238,8 +297,6 @@ void solo_disp_exit(struct solo_dev *solo_dev) | |||
238 | { | 297 | { |
239 | int i; | 298 | int i; |
240 | 299 | ||
241 | solo_irq_off(solo_dev, SOLO_IRQ_MOTION); | ||
242 | |||
243 | solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); | 300 | solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); |
244 | solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); | 301 | solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); |
245 | solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); | 302 | solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); |
diff --git a/drivers/staging/media/solo6x10/eeprom.c b/drivers/staging/media/solo6x10/eeprom.c new file mode 100644 index 000000000000..9d1c9bb53d6b --- /dev/null +++ b/drivers/staging/media/solo6x10/eeprom.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | ||
3 | * | ||
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/delay.h> | ||
27 | |||
28 | #include "solo6x10.h" | ||
29 | |||
30 | /* Control */ | ||
31 | #define EE_SHIFT_CLK 0x04 | ||
32 | #define EE_CS 0x08 | ||
33 | #define EE_DATA_WRITE 0x02 | ||
34 | #define EE_DATA_READ 0x01 | ||
35 | #define EE_ENB (0x80 | EE_CS) | ||
36 | |||
37 | #define eeprom_delay() udelay(100) | ||
38 | #if 0 | ||
39 | #define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) | ||
40 | #define eeprom_delay() ({ \ | ||
41 | int i, ret; \ | ||
42 | udelay(100); \ | ||
43 | for (i = ret = 0; i < 1000 && !ret; i++) \ | ||
44 | ret = solo_eeprom_reg_read(solo_dev); \ | ||
45 | }) | ||
46 | #endif | ||
47 | #define ADDR_LEN 6 | ||
48 | |||
49 | /* Commands */ | ||
50 | #define EE_EWEN_CMD 4 | ||
51 | #define EE_EWDS_CMD 4 | ||
52 | #define EE_WRITE_CMD 5 | ||
53 | #define EE_READ_CMD 6 | ||
54 | #define EE_ERASE_CMD 7 | ||
55 | |||
56 | static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev) | ||
57 | { | ||
58 | return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ; | ||
59 | } | ||
60 | |||
61 | static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data) | ||
62 | { | ||
63 | solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); | ||
64 | eeprom_delay(); | ||
65 | } | ||
66 | |||
67 | static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd) | ||
68 | { | ||
69 | int i; | ||
70 | |||
71 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN); | ||
72 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); | ||
73 | |||
74 | for (i = 4 + ADDR_LEN; i >= 0; i--) { | ||
75 | int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; | ||
76 | |||
77 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval); | ||
78 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | | ||
79 | EE_SHIFT_CLK | dataval); | ||
80 | } | ||
81 | |||
82 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); | ||
83 | } | ||
84 | |||
85 | unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) | ||
86 | { | ||
87 | int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN); | ||
88 | unsigned int retval = 0; | ||
89 | int i; | ||
90 | |||
91 | solo_eeprom_cmd(solo_dev, ewen_cmd); | ||
92 | |||
93 | for (i = 0; i < 16; i++) { | ||
94 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | | ||
95 | EE_SHIFT_CLK); | ||
96 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); | ||
97 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); | ||
98 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); | ||
99 | } | ||
100 | |||
101 | solo_eeprom_reg_write(solo_dev, ~EE_CS); | ||
102 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); | ||
103 | |||
104 | return retval; | ||
105 | } | ||
106 | |||
107 | unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) | ||
108 | { | ||
109 | int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); | ||
110 | unsigned short retval = 0; | ||
111 | int i; | ||
112 | |||
113 | solo_eeprom_cmd(solo_dev, read_cmd); | ||
114 | |||
115 | for (i = 0; i < 16; i++) { | ||
116 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | | ||
117 | EE_SHIFT_CLK); | ||
118 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); | ||
119 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); | ||
120 | } | ||
121 | |||
122 | solo_eeprom_reg_write(solo_dev, ~EE_CS); | ||
123 | |||
124 | return retval; | ||
125 | } | ||
126 | |||
127 | int solo_eeprom_write(struct solo_dev *solo_dev, int loc, | ||
128 | unsigned short data) | ||
129 | { | ||
130 | int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); | ||
131 | unsigned int retval; | ||
132 | int i; | ||
133 | |||
134 | solo_eeprom_cmd(solo_dev, write_cmd); | ||
135 | |||
136 | for (i = 15; i >= 0; i--) { | ||
137 | unsigned int dataval = (data >> i) & 1; | ||
138 | |||
139 | solo_eeprom_reg_write(solo_dev, EE_ENB); | ||
140 | solo_eeprom_reg_write(solo_dev, | ||
141 | EE_ENB | (dataval << 1) | EE_SHIFT_CLK); | ||
142 | } | ||
143 | |||
144 | solo_eeprom_reg_write(solo_dev, EE_ENB); | ||
145 | solo_eeprom_reg_write(solo_dev, ~EE_CS); | ||
146 | solo_eeprom_reg_write(solo_dev, EE_ENB); | ||
147 | |||
148 | for (i = retval = 0; i < 10000 && !retval; i++) | ||
149 | retval = solo_eeprom_reg_read(solo_dev); | ||
150 | |||
151 | solo_eeprom_reg_write(solo_dev, ~EE_CS); | ||
152 | |||
153 | return !retval; | ||
154 | } | ||
diff --git a/drivers/staging/media/solo6x10/enc.c b/drivers/staging/media/solo6x10/enc.c index de502599bb19..94d5735abf85 100644 --- a/drivers/staging/media/solo6x10/enc.c +++ b/drivers/staging/media/solo6x10/enc.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -18,30 +23,41 @@ | |||
18 | */ | 23 | */ |
19 | 24 | ||
20 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/font.h> | ||
27 | #include <linux/bitrev.h> | ||
21 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
22 | #include "solo6x10.h" | ||
23 | #include "osd-font.h" | ||
24 | 29 | ||
25 | #define CAPTURE_MAX_BANDWIDTH 32 /* D1 4channel (D1 == 4) */ | 30 | #include "solo6x10.h" |
26 | #define OSG_BUFFER_SIZE 1024 | ||
27 | 31 | ||
28 | #define VI_PROG_HSIZE (1280 - 16) | 32 | #define VI_PROG_HSIZE (1280 - 16) |
29 | #define VI_PROG_VSIZE (1024 - 16) | 33 | #define VI_PROG_VSIZE (1024 - 16) |
30 | 34 | ||
35 | #define IRQ_LEVEL 2 | ||
36 | |||
31 | static void solo_capture_config(struct solo_dev *solo_dev) | 37 | static void solo_capture_config(struct solo_dev *solo_dev) |
32 | { | 38 | { |
33 | int i, j; | ||
34 | unsigned long height; | 39 | unsigned long height; |
35 | unsigned long width; | 40 | unsigned long width; |
36 | unsigned char *buf; | 41 | void *buf; |
42 | int i; | ||
37 | 43 | ||
38 | solo_reg_write(solo_dev, SOLO_CAP_BASE, | 44 | solo_reg_write(solo_dev, SOLO_CAP_BASE, |
39 | SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE * | 45 | SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev) |
40 | solo_dev->nr_chans) | | 46 | - SOLO_CAP_PAGE_SIZE) >> 16) |
41 | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); | 47 | | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); |
42 | solo_reg_write(solo_dev, SOLO_CAP_BTW, | 48 | |
43 | (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | | 49 | /* XXX: Undocumented bits at b17 and b24 */ |
44 | SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH)); | 50 | if (solo_dev->type == SOLO_DEV_6110) { |
51 | /* NOTE: Ref driver has (62 << 24) here as well, but it causes | ||
52 | * wacked out frame timing on 4-port 6110. */ | ||
53 | solo_reg_write(solo_dev, SOLO_CAP_BTW, | ||
54 | (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | | ||
55 | SOLO_CAP_MAX_BANDWIDTH(36)); | ||
56 | } else { | ||
57 | solo_reg_write(solo_dev, SOLO_CAP_BTW, | ||
58 | (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | | ||
59 | SOLO_CAP_MAX_BANDWIDTH(32)); | ||
60 | } | ||
45 | 61 | ||
46 | /* Set scale 1, 9 dimension */ | 62 | /* Set scale 1, 9 dimension */ |
47 | width = solo_dev->video_hsize; | 63 | width = solo_dev->video_hsize; |
@@ -96,115 +112,212 @@ static void solo_capture_config(struct solo_dev *solo_dev) | |||
96 | solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); | 112 | solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); |
97 | solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, | 113 | solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, |
98 | 0xF0 << 16 | 0x80 << 8 | 0x80); | 114 | 0xF0 << 16 | 0x80 << 8 | 0x80); |
99 | solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0); | 115 | |
116 | if (solo_dev->type == SOLO_DEV_6010) | ||
117 | solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, | ||
118 | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); | ||
119 | else | ||
120 | solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE | ||
121 | | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); | ||
100 | 122 | ||
101 | /* Clear OSG buffer */ | 123 | /* Clear OSG buffer */ |
102 | buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL); | 124 | buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL); |
103 | if (!buf) | 125 | if (!buf) |
104 | return; | 126 | return; |
105 | 127 | ||
106 | for (i = 0; i < solo_dev->nr_chans; i++) { | 128 | for (i = 0; i < solo_dev->nr_chans; i++) { |
107 | for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) { | 129 | solo_p2m_dma(solo_dev, 1, buf, |
108 | solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf, | 130 | SOLO_EOSD_EXT_ADDR + |
109 | SOLO_EOSD_EXT_ADDR + | 131 | (SOLO_EOSD_EXT_SIZE(solo_dev) * i), |
110 | (i * SOLO_EOSD_EXT_SIZE) + j, | 132 | SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); |
111 | OSG_BUFFER_SIZE); | ||
112 | } | ||
113 | } | 133 | } |
114 | kfree(buf); | 134 | kfree(buf); |
115 | } | 135 | } |
116 | 136 | ||
137 | /* Should be called with enable_lock held */ | ||
117 | int solo_osd_print(struct solo_enc_dev *solo_enc) | 138 | int solo_osd_print(struct solo_enc_dev *solo_enc) |
118 | { | 139 | { |
119 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 140 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
120 | char *str = solo_enc->osd_text; | 141 | unsigned char *str = solo_enc->osd_text; |
121 | u8 *buf; | 142 | u8 *buf = solo_enc->osd_buf; |
122 | u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); | 143 | u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); |
123 | int len = strlen(str); | 144 | const struct font_desc *vga = find_font("VGA8x16"); |
145 | const unsigned char *vga_data; | ||
146 | int len; | ||
124 | int i, j; | 147 | int i, j; |
125 | int x = 1, y = 1; | 148 | |
149 | if (WARN_ON_ONCE(!vga)) | ||
150 | return -ENODEV; | ||
151 | |||
152 | len = strlen(str); | ||
126 | 153 | ||
127 | if (len == 0) { | 154 | if (len == 0) { |
155 | /* Disable OSD on this channel */ | ||
128 | reg &= ~(1 << solo_enc->ch); | 156 | reg &= ~(1 << solo_enc->ch); |
129 | solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); | 157 | solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); |
130 | return 0; | 158 | return 0; |
131 | } | 159 | } |
132 | 160 | ||
133 | buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL); | 161 | memset(buf, 0, SOLO_EOSD_EXT_SIZE_MAX); |
134 | if (!buf) | 162 | vga_data = (const unsigned char *)vga->data; |
135 | return -ENOMEM; | ||
136 | 163 | ||
137 | for (i = 0; i < len; i++) { | 164 | for (i = 0; i < len; i++) { |
165 | unsigned char c = str[i]; | ||
166 | |||
138 | for (j = 0; j < 16; j++) { | 167 | for (j = 0; j < 16; j++) { |
139 | buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] = | 168 | buf[(j * 2) + (i % 2) + (i / 2 * 32)] = |
140 | (solo_osd_font[(str[i] * 4) + (j / 4)] | 169 | bitrev8(vga_data[(c * 16) + j]); |
141 | >> ((3 - (j % 4)) * 8)) & 0xff; | ||
142 | } | 170 | } |
143 | } | 171 | } |
144 | 172 | ||
145 | solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR + | 173 | solo_p2m_dma(solo_dev, 1, buf, |
146 | (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE); | 174 | SOLO_EOSD_EXT_ADDR + |
175 | (solo_enc->ch * SOLO_EOSD_EXT_SIZE(solo_dev)), | ||
176 | SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); | ||
177 | |||
178 | /* Enable OSD on this channel */ | ||
147 | reg |= (1 << solo_enc->ch); | 179 | reg |= (1 << solo_enc->ch); |
148 | solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); | 180 | solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); |
149 | 181 | ||
150 | kfree(buf); | ||
151 | |||
152 | return 0; | 182 | return 0; |
153 | } | 183 | } |
154 | 184 | ||
185 | /** | ||
186 | * Set channel Quality Profile (0-3). | ||
187 | */ | ||
188 | void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, | ||
189 | unsigned int qp) | ||
190 | { | ||
191 | unsigned long flags; | ||
192 | unsigned int idx, reg; | ||
193 | |||
194 | if ((ch > 31) || (qp > 3)) | ||
195 | return; | ||
196 | |||
197 | if (solo_dev->type == SOLO_DEV_6010) | ||
198 | return; | ||
199 | |||
200 | if (ch < 16) { | ||
201 | idx = 0; | ||
202 | reg = SOLO_VE_JPEG_QP_CH_L; | ||
203 | } else { | ||
204 | ch -= 16; | ||
205 | idx = 1; | ||
206 | reg = SOLO_VE_JPEG_QP_CH_H; | ||
207 | } | ||
208 | ch *= 2; | ||
209 | |||
210 | spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags); | ||
211 | |||
212 | solo_dev->jpeg_qp[idx] &= ~(3 << ch); | ||
213 | solo_dev->jpeg_qp[idx] |= (qp & 3) << ch; | ||
214 | |||
215 | solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]); | ||
216 | |||
217 | spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags); | ||
218 | } | ||
219 | |||
220 | int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch) | ||
221 | { | ||
222 | int idx; | ||
223 | |||
224 | if (solo_dev->type == SOLO_DEV_6010) | ||
225 | return 2; | ||
226 | |||
227 | if (WARN_ON_ONCE(ch > 31)) | ||
228 | return 2; | ||
229 | |||
230 | if (ch < 16) { | ||
231 | idx = 0; | ||
232 | } else { | ||
233 | ch -= 16; | ||
234 | idx = 1; | ||
235 | } | ||
236 | ch *= 2; | ||
237 | |||
238 | return (solo_dev->jpeg_qp[idx] >> ch) & 3; | ||
239 | } | ||
240 | |||
241 | #define SOLO_QP_INIT 0xaaaaaaaa | ||
242 | |||
155 | static void solo_jpeg_config(struct solo_dev *solo_dev) | 243 | static void solo_jpeg_config(struct solo_dev *solo_dev) |
156 | { | 244 | { |
157 | u32 reg; | 245 | if (solo_dev->type == SOLO_DEV_6010) { |
158 | if (solo_dev->flags & FLAGS_6110) | 246 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, |
159 | reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0); | 247 | (2 << 24) | (2 << 16) | (2 << 8) | 2); |
160 | else | 248 | } else { |
161 | reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0); | 249 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, |
162 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg); | 250 | (4 << 24) | (3 << 16) | (2 << 8) | 1); |
163 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0); | 251 | } |
164 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0); | 252 | |
253 | spin_lock_init(&solo_dev->jpeg_qp_lock); | ||
254 | |||
255 | /* Initialize Quality Profile for all channels */ | ||
256 | solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT; | ||
257 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT); | ||
258 | solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT); | ||
259 | |||
165 | solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, | 260 | solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, |
166 | (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | | 261 | (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | |
167 | ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); | 262 | ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); |
168 | solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); | 263 | solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); |
169 | /* que limit, samp limit, pos limit */ | 264 | if (solo_dev->type == SOLO_DEV_6110) { |
170 | solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60); | 265 | solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1, |
266 | (0 << 16) | (30 << 8) | 60); | ||
267 | } | ||
171 | } | 268 | } |
172 | 269 | ||
173 | static void solo_mp4e_config(struct solo_dev *solo_dev) | 270 | static void solo_mp4e_config(struct solo_dev *solo_dev) |
174 | { | 271 | { |
175 | int i; | 272 | int i; |
176 | u32 reg; | 273 | u32 cfg; |
177 | 274 | ||
178 | /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */ | ||
179 | solo_reg_write(solo_dev, SOLO_VE_CFG0, | 275 | solo_reg_write(solo_dev, SOLO_VE_CFG0, |
180 | SOLO_VE_INTR_CTRL(0) | | 276 | SOLO_VE_INTR_CTRL(IRQ_LEVEL) | |
181 | SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | | 277 | SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | |
182 | SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); | 278 | SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); |
183 | 279 | ||
184 | solo_reg_write(solo_dev, SOLO_VE_CFG1, | 280 | |
185 | SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0)); | 281 | cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX |
282 | | SOLO_VE_MOTION_MODE(0); | ||
283 | if (solo_dev->type != SOLO_DEV_6010) { | ||
284 | cfg |= SOLO_VE_MPEG_SIZE_H( | ||
285 | (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f); | ||
286 | cfg |= SOLO_VE_JPEG_SIZE_H( | ||
287 | (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f); | ||
288 | } | ||
289 | solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg); | ||
186 | 290 | ||
187 | solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); | 291 | solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); |
188 | solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); | 292 | solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); |
189 | solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); | 293 | solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); |
294 | if (solo_dev->type == SOLO_DEV_6110) | ||
295 | solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0); | ||
190 | solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); | 296 | solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); |
191 | solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); | 297 | solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); |
192 | 298 | ||
193 | reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) | | 299 | solo_reg_write(solo_dev, SOLO_VE_ATTR, |
194 | SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15); | 300 | SOLO_VE_LITTLE_ENDIAN | |
195 | if (solo_dev->flags & FLAGS_6110) | 301 | SOLO_COMP_ATTR_FCODE(1) | |
196 | reg |= SOLO_DCT_INTERVAL(10); | 302 | SOLO_COMP_TIME_INC(0) | |
197 | else | 303 | SOLO_COMP_TIME_WIDTH(15) | |
198 | reg |= SOLO_DCT_INTERVAL(36 / 4); | 304 | SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10)); |
199 | solo_reg_write(solo_dev, SOLO_VE_ATTR, reg); | ||
200 | 305 | ||
201 | for (i = 0; i < solo_dev->nr_chans; i++) | 306 | for (i = 0; i < solo_dev->nr_chans; i++) { |
202 | solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), | 307 | solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), |
203 | (SOLO_EREF_EXT_ADDR(solo_dev) + | 308 | (SOLO_EREF_EXT_ADDR(solo_dev) + |
204 | (i * SOLO_EREF_EXT_SIZE)) >> 16); | 309 | (i * SOLO_EREF_EXT_SIZE)) >> 16); |
310 | solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i), | ||
311 | (SOLO_EREF_EXT_ADDR(solo_dev) + | ||
312 | ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16); | ||
313 | } | ||
205 | 314 | ||
206 | if (solo_dev->flags & FLAGS_6110) | 315 | if (solo_dev->type == SOLO_DEV_6110) { |
207 | solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */ | 316 | solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008); |
317 | } else { | ||
318 | for (i = 0; i < solo_dev->nr_chans; i++) | ||
319 | solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100); | ||
320 | } | ||
208 | } | 321 | } |
209 | 322 | ||
210 | int solo_enc_init(struct solo_dev *solo_dev) | 323 | int solo_enc_init(struct solo_dev *solo_dev) |
@@ -220,8 +333,6 @@ int solo_enc_init(struct solo_dev *solo_dev) | |||
220 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); | 333 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); |
221 | } | 334 | } |
222 | 335 | ||
223 | solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); | ||
224 | |||
225 | return 0; | 336 | return 0; |
226 | } | 337 | } |
227 | 338 | ||
@@ -229,8 +340,6 @@ void solo_enc_exit(struct solo_dev *solo_dev) | |||
229 | { | 340 | { |
230 | int i; | 341 | int i; |
231 | 342 | ||
232 | solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); | ||
233 | |||
234 | for (i = 0; i < solo_dev->nr_chans; i++) { | 343 | for (i = 0; i < solo_dev->nr_chans; i++) { |
235 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); | 344 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); |
236 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); | 345 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); |
diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c index 2cd0de28a633..183222e7ee95 100644 --- a/drivers/staging/media/solo6x10/g723.c +++ b/drivers/staging/media/solo6x10/g723.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -21,17 +26,18 @@ | |||
21 | #include <linux/mempool.h> | 26 | #include <linux/mempool.h> |
22 | #include <linux/poll.h> | 27 | #include <linux/poll.h> |
23 | #include <linux/kthread.h> | 28 | #include <linux/kthread.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/freezer.h> | 29 | #include <linux/freezer.h> |
26 | #include <linux/export.h> | 30 | #include <linux/module.h> |
31 | #include <linux/slab.h> | ||
32 | |||
27 | #include <sound/core.h> | 33 | #include <sound/core.h> |
28 | #include <sound/initval.h> | 34 | #include <sound/initval.h> |
29 | #include <sound/pcm.h> | 35 | #include <sound/pcm.h> |
30 | #include <sound/control.h> | 36 | #include <sound/control.h> |
37 | |||
31 | #include "solo6x10.h" | 38 | #include "solo6x10.h" |
32 | #include "tw28.h" | 39 | #include "tw28.h" |
33 | 40 | ||
34 | #define G723_INTR_ORDER 0 | ||
35 | #define G723_FDMA_PAGES 32 | 41 | #define G723_FDMA_PAGES 32 |
36 | #define G723_PERIOD_BYTES 48 | 42 | #define G723_PERIOD_BYTES 48 |
37 | #define G723_PERIOD_BLOCK 1024 | 43 | #define G723_PERIOD_BLOCK 1024 |
@@ -46,36 +52,40 @@ | |||
46 | /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page | 52 | /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page |
47 | * is broken down to 20 * 48 byte regions (one for each channel possible) | 53 | * is broken down to 20 * 48 byte regions (one for each channel possible) |
48 | * with the rest of the page being dummy data. */ | 54 | * with the rest of the page being dummy data. */ |
49 | #define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) | 55 | #define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) |
50 | #define IRQ_PAGES 4 /* 0 - 4 */ | 56 | #define G723_INTR_ORDER 4 /* 0 - 4 */ |
51 | #define PERIODS_MIN (1 << IRQ_PAGES) | 57 | #define PERIODS_MIN (1 << G723_INTR_ORDER) |
52 | #define PERIODS_MAX G723_FDMA_PAGES | 58 | #define PERIODS_MAX G723_FDMA_PAGES |
53 | 59 | ||
54 | struct solo_snd_pcm { | 60 | struct solo_snd_pcm { |
55 | int on; | 61 | int on; |
56 | spinlock_t lock; | 62 | spinlock_t lock; |
57 | struct solo_dev *solo_dev; | 63 | struct solo_dev *solo_dev; |
58 | unsigned char g723_buf[G723_PERIOD_BYTES]; | 64 | unsigned char *g723_buf; |
65 | dma_addr_t g723_dma; | ||
59 | }; | 66 | }; |
60 | 67 | ||
61 | static void solo_g723_config(struct solo_dev *solo_dev) | 68 | static void solo_g723_config(struct solo_dev *solo_dev) |
62 | { | 69 | { |
63 | int clk_div; | 70 | int clk_div; |
64 | 71 | ||
65 | clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2); | 72 | clk_div = (solo_dev->clock_mhz * 1000000) |
73 | / (SAMPLERATE * (BITRATE * 2) * 2); | ||
66 | 74 | ||
67 | solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE, | 75 | solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE, |
68 | SOLO_AUDIO_BITRATE(BITRATE) | | 76 | SOLO_AUDIO_BITRATE(BITRATE) |
69 | SOLO_AUDIO_CLK_DIV(clk_div)); | 77 | | SOLO_AUDIO_CLK_DIV(clk_div)); |
70 | 78 | ||
71 | solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR, | 79 | solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR, |
72 | SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) | | 80 | SOLO_AUDIO_FDMA_INTERVAL(1) |
73 | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) | | 81 | | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
74 | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16)); | 82 | | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16)); |
75 | 83 | ||
76 | solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, | 84 | solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, |
77 | SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE | | 85 | SOLO_AUDIO_ENABLE |
78 | SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK)); | 86 | | SOLO_AUDIO_I2S_MODE |
87 | | SOLO_AUDIO_I2S_MULTI(3) | ||
88 | | SOLO_AUDIO_MODE(OUTMODE_MASK)); | ||
79 | } | 89 | } |
80 | 90 | ||
81 | void solo_g723_isr(struct solo_dev *solo_dev) | 91 | void solo_g723_isr(struct solo_dev *solo_dev) |
@@ -85,8 +95,6 @@ void solo_g723_isr(struct solo_dev *solo_dev) | |||
85 | struct snd_pcm_substream *ss; | 95 | struct snd_pcm_substream *ss; |
86 | struct solo_snd_pcm *solo_pcm; | 96 | struct solo_snd_pcm *solo_pcm; |
87 | 97 | ||
88 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723); | ||
89 | |||
90 | for (ss = pstr->substream; ss != NULL; ss = ss->next) { | 98 | for (ss = pstr->substream; ss != NULL; ss = ss->next) { |
91 | if (snd_pcm_substream_chip(ss) == NULL) | 99 | if (snd_pcm_substream_chip(ss) == NULL) |
92 | continue; | 100 | continue; |
@@ -115,18 +123,18 @@ static int snd_solo_hw_free(struct snd_pcm_substream *ss) | |||
115 | return snd_pcm_lib_free_pages(ss); | 123 | return snd_pcm_lib_free_pages(ss); |
116 | } | 124 | } |
117 | 125 | ||
118 | static struct snd_pcm_hardware snd_solo_pcm_hw = { | 126 | static const struct snd_pcm_hardware snd_solo_pcm_hw = { |
119 | .info = (SNDRV_PCM_INFO_MMAP | | 127 | .info = (SNDRV_PCM_INFO_MMAP | |
120 | SNDRV_PCM_INFO_INTERLEAVED | | 128 | SNDRV_PCM_INFO_INTERLEAVED | |
121 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 129 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
122 | SNDRV_PCM_INFO_MMAP_VALID), | 130 | SNDRV_PCM_INFO_MMAP_VALID), |
123 | .formats = SNDRV_PCM_FMTBIT_U8, | 131 | .formats = SNDRV_PCM_FMTBIT_U8, |
124 | .rates = SNDRV_PCM_RATE_8000, | 132 | .rates = SNDRV_PCM_RATE_8000, |
125 | .rate_min = 8000, | 133 | .rate_min = SAMPLERATE, |
126 | .rate_max = 8000, | 134 | .rate_max = SAMPLERATE, |
127 | .channels_min = 1, | 135 | .channels_min = 1, |
128 | .channels_max = 1, | 136 | .channels_max = 1, |
129 | .buffer_bytes_max = MAX_BUFFER, | 137 | .buffer_bytes_max = G723_MAX_BUFFER, |
130 | .period_bytes_min = G723_PERIOD_BYTES, | 138 | .period_bytes_min = G723_PERIOD_BYTES, |
131 | .period_bytes_max = G723_PERIOD_BYTES, | 139 | .period_bytes_max = G723_PERIOD_BYTES, |
132 | .periods_min = PERIODS_MIN, | 140 | .periods_min = PERIODS_MIN, |
@@ -140,7 +148,13 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss) | |||
140 | 148 | ||
141 | solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL); | 149 | solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL); |
142 | if (solo_pcm == NULL) | 150 | if (solo_pcm == NULL) |
143 | return -ENOMEM; | 151 | goto oom; |
152 | |||
153 | solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev, | ||
154 | G723_PERIOD_BYTES, | ||
155 | &solo_pcm->g723_dma); | ||
156 | if (solo_pcm->g723_buf == NULL) | ||
157 | goto oom; | ||
144 | 158 | ||
145 | spin_lock_init(&solo_pcm->lock); | 159 | spin_lock_init(&solo_pcm->lock); |
146 | solo_pcm->solo_dev = solo_dev; | 160 | solo_pcm->solo_dev = solo_dev; |
@@ -149,6 +163,10 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss) | |||
149 | snd_pcm_substream_chip(ss) = solo_pcm; | 163 | snd_pcm_substream_chip(ss) = solo_pcm; |
150 | 164 | ||
151 | return 0; | 165 | return 0; |
166 | |||
167 | oom: | ||
168 | kfree(solo_pcm); | ||
169 | return -ENOMEM; | ||
152 | } | 170 | } |
153 | 171 | ||
154 | static int snd_solo_pcm_close(struct snd_pcm_substream *ss) | 172 | static int snd_solo_pcm_close(struct snd_pcm_substream *ss) |
@@ -156,6 +174,8 @@ static int snd_solo_pcm_close(struct snd_pcm_substream *ss) | |||
156 | struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); | 174 | struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); |
157 | 175 | ||
158 | snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; | 176 | snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; |
177 | pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES, | ||
178 | solo_pcm->g723_buf, solo_pcm->g723_dma); | ||
159 | kfree(solo_pcm); | 179 | kfree(solo_pcm); |
160 | 180 | ||
161 | return 0; | 181 | return 0; |
@@ -220,12 +240,11 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, | |||
220 | for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { | 240 | for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { |
221 | int page = (pos / G723_FRAMES_PER_PAGE) + i; | 241 | int page = (pos / G723_FRAMES_PER_PAGE) + i; |
222 | 242 | ||
223 | err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0, | 243 | err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, |
224 | solo_pcm->g723_buf, | 244 | SOLO_G723_EXT_ADDR(solo_dev) + |
225 | SOLO_G723_EXT_ADDR(solo_dev) + | 245 | (page * G723_PERIOD_BLOCK) + |
226 | (page * G723_PERIOD_BLOCK) + | 246 | (ss->number * G723_PERIOD_BYTES), |
227 | (ss->number * G723_PERIOD_BYTES), | 247 | G723_PERIOD_BYTES, 0, 0); |
228 | G723_PERIOD_BYTES); | ||
229 | if (err) | 248 | if (err) |
230 | return err; | 249 | return err; |
231 | 250 | ||
@@ -325,7 +344,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) | |||
325 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | 344 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, |
326 | SNDRV_DMA_TYPE_CONTINUOUS, | 345 | SNDRV_DMA_TYPE_CONTINUOUS, |
327 | snd_dma_continuous_data(GFP_KERNEL), | 346 | snd_dma_continuous_data(GFP_KERNEL), |
328 | MAX_BUFFER, MAX_BUFFER); | 347 | G723_MAX_BUFFER, G723_MAX_BUFFER); |
329 | if (ret < 0) | 348 | if (ret < 0) |
330 | return ret; | 349 | return ret; |
331 | 350 | ||
@@ -368,6 +387,7 @@ int solo_g723_init(struct solo_dev *solo_dev) | |||
368 | strcpy(card->mixername, "SOLO-6x10"); | 387 | strcpy(card->mixername, "SOLO-6x10"); |
369 | kctl = snd_solo_capture_volume; | 388 | kctl = snd_solo_capture_volume; |
370 | kctl.count = solo_dev->nr_chans; | 389 | kctl.count = solo_dev->nr_chans; |
390 | |||
371 | ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); | 391 | ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); |
372 | if (ret < 0) | 392 | if (ret < 0) |
373 | return ret; | 393 | return ret; |
@@ -393,8 +413,12 @@ snd_error: | |||
393 | 413 | ||
394 | void solo_g723_exit(struct solo_dev *solo_dev) | 414 | void solo_g723_exit(struct solo_dev *solo_dev) |
395 | { | 415 | { |
416 | if (!solo_dev->snd_card) | ||
417 | return; | ||
418 | |||
396 | solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0); | 419 | solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0); |
397 | solo_irq_off(solo_dev, SOLO_IRQ_G723); | 420 | solo_irq_off(solo_dev, SOLO_IRQ_G723); |
398 | 421 | ||
399 | snd_card_free(solo_dev->snd_card); | 422 | snd_card_free(solo_dev->snd_card); |
423 | solo_dev->snd_card = NULL; | ||
400 | } | 424 | } |
diff --git a/drivers/staging/media/solo6x10/gpio.c b/drivers/staging/media/solo6x10/gpio.c index 0925e6f33a99..73276dc92875 100644 --- a/drivers/staging/media/solo6x10/gpio.c +++ b/drivers/staging/media/solo6x10/gpio.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -19,7 +24,9 @@ | |||
19 | 24 | ||
20 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
21 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
22 | #include <asm/uaccess.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/uaccess.h> | ||
29 | |||
23 | #include "solo6x10.h" | 30 | #include "solo6x10.h" |
24 | 31 | ||
25 | static void solo_gpio_mode(struct solo_dev *solo_dev, | 32 | static void solo_gpio_mode(struct solo_dev *solo_dev, |
diff --git a/drivers/staging/media/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c index 398070a3d293..01aa417c9258 100644 --- a/drivers/staging/media/solo6x10/i2c.c +++ b/drivers/staging/media/solo6x10/i2c.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -26,6 +31,7 @@ | |||
26 | * thread context, ACK the interrupt, and move on. -- BenC */ | 31 | * thread context, ACK the interrupt, and move on. -- BenC */ |
27 | 32 | ||
28 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | |||
29 | #include "solo6x10.h" | 35 | #include "solo6x10.h" |
30 | 36 | ||
31 | u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off) | 37 | u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off) |
@@ -173,10 +179,9 @@ int solo_i2c_isr(struct solo_dev *solo_dev) | |||
173 | u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); | 179 | u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); |
174 | int ret = -EINVAL; | 180 | int ret = -EINVAL; |
175 | 181 | ||
176 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC); | ||
177 | 182 | ||
178 | if (status & (SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) || | 183 | if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) |
179 | solo_dev->i2c_id < 0) { | 184 | || solo_dev->i2c_id < 0) { |
180 | solo_i2c_stop(solo_dev); | 185 | solo_i2c_stop(solo_dev); |
181 | return -ENXIO; | 186 | return -ENXIO; |
182 | } | 187 | } |
@@ -239,7 +244,8 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap, | |||
239 | timeout = HZ / 2; | 244 | timeout = HZ / 2; |
240 | 245 | ||
241 | for (;;) { | 246 | for (;;) { |
242 | prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE); | 247 | prepare_to_wait(&solo_dev->i2c_wait, &wait, |
248 | TASK_INTERRUPTIBLE); | ||
243 | 249 | ||
244 | if (solo_dev->i2c_state == IIC_STATE_STOP) | 250 | if (solo_dev->i2c_state == IIC_STATE_STOP) |
245 | break; | 251 | break; |
@@ -267,7 +273,7 @@ static u32 solo_i2c_functionality(struct i2c_adapter *adap) | |||
267 | return I2C_FUNC_I2C; | 273 | return I2C_FUNC_I2C; |
268 | } | 274 | } |
269 | 275 | ||
270 | static struct i2c_algorithm solo_i2c_algo = { | 276 | static const struct i2c_algorithm solo_i2c_algo = { |
271 | .master_xfer = solo_i2c_master_xfer, | 277 | .master_xfer = solo_i2c_master_xfer, |
272 | .functionality = solo_i2c_functionality, | 278 | .functionality = solo_i2c_functionality, |
273 | }; | 279 | }; |
@@ -288,7 +294,8 @@ int solo_i2c_init(struct solo_dev *solo_dev) | |||
288 | for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { | 294 | for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { |
289 | struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; | 295 | struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; |
290 | 296 | ||
291 | snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6X10_NAME, i); | 297 | snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", |
298 | SOLO6X10_NAME, i); | ||
292 | adap->algo = &solo_i2c_algo; | 299 | adap->algo = &solo_i2c_algo; |
293 | adap->algo_data = solo_dev; | 300 | adap->algo_data = solo_dev; |
294 | adap->retries = 1; | 301 | adap->retries = 1; |
@@ -311,9 +318,6 @@ int solo_i2c_init(struct solo_dev *solo_dev) | |||
311 | return ret; | 318 | return ret; |
312 | } | 319 | } |
313 | 320 | ||
314 | dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n", | ||
315 | SOLO_I2C_ADAPTERS); | ||
316 | |||
317 | return 0; | 321 | return 0; |
318 | } | 322 | } |
319 | 323 | ||
diff --git a/drivers/staging/media/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h index 3d7e569f1cf8..f005dca501f1 100644 --- a/drivers/staging/media/solo6x10/offsets.h +++ b/drivers/staging/media/solo6x10/offsets.h | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -20,55 +25,61 @@ | |||
20 | #ifndef __SOLO6X10_OFFSETS_H | 25 | #ifndef __SOLO6X10_OFFSETS_H |
21 | #define __SOLO6X10_OFFSETS_H | 26 | #define __SOLO6X10_OFFSETS_H |
22 | 27 | ||
23 | /* Offsets and sizes of the external address */ | ||
24 | #define SOLO_DISP_EXT_ADDR 0x00000000 | 28 | #define SOLO_DISP_EXT_ADDR 0x00000000 |
25 | #define SOLO_DISP_EXT_SIZE 0x00480000 | 29 | #define SOLO_DISP_EXT_SIZE 0x00480000 |
26 | 30 | ||
27 | #define SOLO_DEC2LIVE_EXT_ADDR (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE) | 31 | #define SOLO_EOSD_EXT_ADDR \ |
28 | #define SOLO_DEC2LIVE_EXT_SIZE 0x00240000 | 32 | (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE) |
29 | 33 | #define SOLO_EOSD_EXT_SIZE(__solo) \ | |
30 | #define SOLO_OSG_EXT_ADDR (SOLO_DEC2LIVE_EXT_ADDR + SOLO_DEC2LIVE_EXT_SIZE) | 34 | (__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000) |
31 | #define SOLO_OSG_EXT_SIZE 0x00120000 | 35 | #define SOLO_EOSD_EXT_SIZE_MAX 0x20000 |
36 | #define SOLO_EOSD_EXT_AREA(__solo) \ | ||
37 | (SOLO_EOSD_EXT_SIZE(__solo) * 32) | ||
32 | 38 | ||
33 | #define SOLO_EOSD_EXT_ADDR (SOLO_OSG_EXT_ADDR + SOLO_OSG_EXT_SIZE) | 39 | #define SOLO_MOTION_EXT_ADDR(__solo) \ |
34 | #define SOLO_EOSD_EXT_SIZE 0x00010000 | 40 | (SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo)) |
35 | |||
36 | #define SOLO_MOTION_EXT_ADDR(__solo) (SOLO_EOSD_EXT_ADDR + \ | ||
37 | (SOLO_EOSD_EXT_SIZE * __solo->nr_chans)) | ||
38 | #define SOLO_MOTION_EXT_SIZE 0x00080000 | 41 | #define SOLO_MOTION_EXT_SIZE 0x00080000 |
39 | 42 | ||
40 | #define SOLO_G723_EXT_ADDR(__solo) \ | 43 | #define SOLO_G723_EXT_ADDR(__solo) \ |
41 | (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE) | 44 | (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE) |
42 | #define SOLO_G723_EXT_SIZE 0x00010000 | 45 | #define SOLO_G723_EXT_SIZE 0x00010000 |
43 | 46 | ||
44 | #define SOLO_CAP_EXT_ADDR(__solo) \ | 47 | #define SOLO_CAP_EXT_ADDR(__solo) \ |
45 | (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE) | 48 | (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE) |
46 | #define SOLO_CAP_EXT_MAX_PAGE (18 + 15) | 49 | |
47 | #define SOLO_CAP_EXT_SIZE (SOLO_CAP_EXT_MAX_PAGE * 65536) | 50 | /* 18 is the maximum number of pages required for PAL@D1, the largest frame |
51 | * possible */ | ||
52 | #define SOLO_CAP_PAGE_SIZE (18 << 16) | ||
53 | |||
54 | /* Always allow the encoder enough for 16 channels, even if we have less. The | ||
55 | * exception is if we have card with only 32Megs of memory. */ | ||
56 | #define SOLO_CAP_EXT_SIZE(__solo) \ | ||
57 | ((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1) \ | ||
58 | * SOLO_CAP_PAGE_SIZE) | ||
48 | 59 | ||
49 | /* This +1 is very important -- Why?! -- BenC */ | ||
50 | #define SOLO_EREF_EXT_ADDR(__solo) \ | 60 | #define SOLO_EREF_EXT_ADDR(__solo) \ |
51 | (SOLO_CAP_EXT_ADDR(__solo) + \ | 61 | (SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo)) |
52 | (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1))) | ||
53 | #define SOLO_EREF_EXT_SIZE 0x00140000 | 62 | #define SOLO_EREF_EXT_SIZE 0x00140000 |
63 | #define SOLO_EREF_EXT_AREA(__solo) \ | ||
64 | (SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2) | ||
65 | |||
66 | #define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) | ||
54 | 67 | ||
55 | #define SOLO_MP4E_EXT_ADDR(__solo) \ | 68 | #define SOLO_MP4E_EXT_ADDR(__solo) \ |
56 | (SOLO_EREF_EXT_ADDR(__solo) + \ | 69 | (SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo)) |
57 | (SOLO_EREF_EXT_SIZE * __solo->nr_chans)) | 70 | #define SOLO_MP4E_EXT_SIZE(__solo) \ |
58 | #define SOLO_MP4E_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans) | 71 | max((__solo->nr_chans * 0x00080000), \ |
72 | min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \ | ||
73 | __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000)) | ||
59 | 74 | ||
60 | #define SOLO_DREF_EXT_ADDR(__solo) \ | 75 | #define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) |
76 | #define SOLO_JPEG_EXT_ADDR(__solo) \ | ||
61 | (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo)) | 77 | (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo)) |
62 | #define SOLO_DREF_EXT_SIZE 0x00140000 | 78 | #define SOLO_JPEG_EXT_SIZE(__solo) \ |
79 | max(__SOLO_JPEG_MIN_SIZE(__solo), \ | ||
80 | min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000)) | ||
63 | 81 | ||
64 | #define SOLO_MP4D_EXT_ADDR(__solo) \ | 82 | #define SOLO_SDRAM_END(__solo) \ |
65 | (SOLO_DREF_EXT_ADDR(__solo) + \ | 83 | (SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo)) |
66 | (SOLO_DREF_EXT_SIZE * __solo->nr_chans)) | ||
67 | #define SOLO_MP4D_EXT_SIZE 0x00080000 | ||
68 | |||
69 | #define SOLO_JPEG_EXT_ADDR(__solo) \ | ||
70 | (SOLO_MP4D_EXT_ADDR(__solo) + \ | ||
71 | (SOLO_MP4D_EXT_SIZE * __solo->nr_chans)) | ||
72 | #define SOLO_JPEG_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans) | ||
73 | 84 | ||
74 | #endif /* __SOLO6X10_OFFSETS_H */ | 85 | #endif /* __SOLO6X10_OFFSETS_H */ |
diff --git a/drivers/staging/media/solo6x10/osd-font.h b/drivers/staging/media/solo6x10/osd-font.h deleted file mode 100644 index 591e0e82e0e8..000000000000 --- a/drivers/staging/media/solo6x10/osd-font.h +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | ||
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef __SOLO6X10_OSD_FONT_H | ||
21 | #define __SOLO6X10_OSD_FONT_H | ||
22 | |||
23 | static const unsigned int solo_osd_font[] = { | ||
24 | 0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000, | ||
25 | 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */ | ||
26 | 0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000, | ||
27 | 0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000, | ||
28 | 0x00000000, 0x00001038, 0x10000000, 0x00000000, | ||
29 | 0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000, | ||
30 | 0x00000000, 0x00384444, 0x44380000, 0x00000000, | ||
31 | 0x00000000, 0x38448282, 0x82443800, 0x00000000, | ||
32 | 0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000, | ||
33 | 0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000, | ||
34 | 0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000, | ||
35 | 0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000, | ||
36 | 0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000, | ||
37 | 0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000, | ||
38 | 0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000, | ||
39 | 0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000, | ||
40 | 0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000, | ||
41 | 0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000, | ||
42 | 0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000, | ||
43 | 0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000, | ||
44 | 0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000, | ||
45 | 0x00000082, 0x44288244, 0x38c6827c, 0x00000000, | ||
46 | 0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000, | ||
47 | 0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000, | ||
48 | 0x00000000, 0x3854929a, 0x82443800, 0x00000000, | ||
49 | 0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000, | ||
50 | 0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000, | ||
51 | 0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000, | ||
52 | 0x0000007c, 0x82829292, 0x929282fe, 0x00000000, | ||
53 | 0x000000f8, 0xfc046494, 0x946404fc, 0x00000000, | ||
54 | 0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000, | ||
55 | 0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000, | ||
56 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
57 | 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32 ! */ | ||
58 | 0x00000066, 0x66240000, 0x00000000, 0x00000000, | ||
59 | 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */ | ||
60 | 0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000, | ||
61 | 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */ | ||
62 | 0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000, | ||
63 | 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */ | ||
64 | 0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000, | ||
65 | 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */ | ||
66 | 0x00000000, 0x0000663c, 0xff3c6600, 0x00000000, | ||
67 | 0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */ | ||
68 | 0x00000000, 0x00000000, 0x00000e0e, 0x0c060000, | ||
69 | 0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */ | ||
70 | 0x00000000, 0x00000000, 0x00000006, 0x06000000, | ||
71 | 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */ | ||
72 | 0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000, | ||
73 | 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */ | ||
74 | 0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000, | ||
75 | 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */ | ||
76 | 0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000, | ||
77 | 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */ | ||
78 | 0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000, | ||
79 | 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */ | ||
80 | 0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000, | ||
81 | 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */ | ||
82 | 0x00000000, 0x18180000, 0x00181800, 0x00000000, | ||
83 | 0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */ | ||
84 | 0x00000060, 0x30180c06, 0x0c183060, 0x00000000, | ||
85 | 0x00000000, 0x007e0000, 0x007e0000, 0x00000000, | ||
86 | 0x00000006, 0x0c183060, 0x30180c06, 0x00000000, | ||
87 | 0x0000007c, 0xc6c66030, 0x30003030, 0x00000000, | ||
88 | 0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000, | ||
89 | 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */ | ||
90 | 0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000, | ||
91 | 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */ | ||
92 | 0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000, | ||
93 | 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */ | ||
94 | 0x000000fe, 0x0606063e, 0x06060606, 0x00000000, | ||
95 | 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */ | ||
96 | 0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000, | ||
97 | 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */ | ||
98 | 0x00000060, 0x60606060, 0x6066663c, 0x00000000, | ||
99 | 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */ | ||
100 | 0x00000006, 0x06060606, 0x060606fe, 0x00000000, | ||
101 | 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */ | ||
102 | 0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000, | ||
103 | 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */ | ||
104 | 0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000, | ||
105 | 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */ | ||
106 | 0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000, | ||
107 | 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */ | ||
108 | 0x0000007e, 0x18181818, 0x18181818, 0x00000000, | ||
109 | 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */ | ||
110 | 0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000, | ||
111 | 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */ | ||
112 | 0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000, | ||
113 | 0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */ | ||
114 | 0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000, | ||
115 | 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */ | ||
116 | 0x00000002, 0x060c1830, 0x60c08000, 0x00000000, | ||
117 | 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */ | ||
118 | 0x00001038, 0x6cc60000, 0x00000000, 0x00000000, | ||
119 | 0x00000000, 0x00000000, 0x00000000, 0x00fe0000, | ||
120 | 0x00001818, 0x30000000, 0x00000000, 0x00000000, | ||
121 | 0x00000000, 0x00003c60, 0x7c66667c, 0x00000000, | ||
122 | 0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000, | ||
123 | 0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000, | ||
124 | 0x00000060, 0x60607c66, 0x6666667c, 0x00000000, | ||
125 | 0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000, | ||
126 | 0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000, | ||
127 | 0x00000000, 0x00007c66, 0x6666667c, 0x60603e00, | ||
128 | 0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000, | ||
129 | 0x00000030, 0x30003830, 0x30303078, 0x00000000, | ||
130 | 0x00000030, 0x30003c30, 0x30303030, 0x30301f00, | ||
131 | 0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000, | ||
132 | 0x00000030, 0x30303030, 0x30303030, 0x00000000, | ||
133 | 0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000, | ||
134 | 0x00000000, 0x000078cc, 0xcccccccc, 0x00000000, | ||
135 | 0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000, | ||
136 | 0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00, | ||
137 | 0x00000000, 0x00007c66, 0x6666667c, 0x60606000, | ||
138 | 0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000, | ||
139 | 0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000, | ||
140 | 0x00000000, 0x1818fe18, 0x18181870, 0x00000000, | ||
141 | 0x00000000, 0x00006666, 0x6666663c, 0x00000000, | ||
142 | 0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000, | ||
143 | 0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000, | ||
144 | 0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000, | ||
145 | 0x00000000, 0x00006666, 0x6666667c, 0x60603e00, | ||
146 | 0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000, | ||
147 | 0x00000070, 0x1818180e, 0x18181870, 0x00000000, | ||
148 | 0x00000018, 0x18181800, 0x18181818, 0x00000000, | ||
149 | 0x0000000e, 0x18181870, 0x1818180e, 0x00000000, | ||
150 | 0x000000dc, 0x76000000, 0x00000000, 0x00000000, | ||
151 | 0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000 | ||
152 | }; | ||
153 | |||
154 | #endif /* __SOLO6X10_OSD_FONT_H */ | ||
diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c index 58ab61b1f1d9..b3a933906b90 100644 --- a/drivers/staging/media/solo6x10/p2m.c +++ b/drivers/staging/media/solo6x10/p2m.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -18,28 +23,38 @@ | |||
18 | */ | 23 | */ |
19 | 24 | ||
20 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
22 | #include <linux/scatterlist.h> | 28 | |
23 | #include "solo6x10.h" | 29 | #include "solo6x10.h" |
24 | 30 | ||
25 | /* #define SOLO_TEST_P2M */ | 31 | static int multi_p2m; |
32 | module_param(multi_p2m, uint, 0644); | ||
33 | MODULE_PARM_DESC(multi_p2m, | ||
34 | "Use multiple P2M DMA channels (default: no, 6010-only)"); | ||
26 | 35 | ||
27 | int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr, | 36 | static int desc_mode; |
28 | void *sys_addr, u32 ext_addr, u32 size) | 37 | module_param(desc_mode, uint, 0644); |
38 | MODULE_PARM_DESC(desc_mode, | ||
39 | "Allow use of descriptor mode DMA (default: no, 6010-only)"); | ||
40 | |||
41 | int solo_p2m_dma(struct solo_dev *solo_dev, int wr, | ||
42 | void *sys_addr, u32 ext_addr, u32 size, | ||
43 | int repeat, u32 ext_size) | ||
29 | { | 44 | { |
30 | dma_addr_t dma_addr; | 45 | dma_addr_t dma_addr; |
31 | int ret; | 46 | int ret; |
32 | 47 | ||
33 | WARN_ON(!size); | 48 | if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03)) |
34 | BUG_ON(id >= SOLO_NR_P2M); | 49 | return -EINVAL; |
35 | 50 | if (WARN_ON_ONCE(!size)) | |
36 | if (!size) | ||
37 | return -EINVAL; | 51 | return -EINVAL; |
38 | 52 | ||
39 | dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, | 53 | dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, |
40 | wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); | 54 | wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); |
41 | 55 | ||
42 | ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size); | 56 | ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size, |
57 | repeat, ext_size); | ||
43 | 58 | ||
44 | pci_unmap_single(solo_dev->pdev, dma_addr, size, | 59 | pci_unmap_single(solo_dev->pdev, dma_addr, size, |
45 | wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); | 60 | wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); |
@@ -47,221 +62,141 @@ int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr, | |||
47 | return ret; | 62 | return ret; |
48 | } | 63 | } |
49 | 64 | ||
50 | int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr, | 65 | /* Mutex must be held for p2m_id before calling this!! */ |
51 | dma_addr_t dma_addr, u32 ext_addr, u32 size) | 66 | int solo_p2m_dma_desc(struct solo_dev *solo_dev, |
52 | { | 67 | struct solo_p2m_desc *desc, dma_addr_t desc_dma, |
53 | struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA); | 68 | int desc_cnt) |
54 | int ret; | ||
55 | |||
56 | if (desc == NULL) | ||
57 | return -ENOMEM; | ||
58 | |||
59 | solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0); | ||
60 | ret = solo_p2m_dma_desc(solo_dev, id, desc, 2); | ||
61 | kfree(desc); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, | ||
67 | u32 ext_addr, u32 size, int repeat, u32 ext_size) | ||
68 | { | ||
69 | desc->ta = cpu_to_le32(dma_addr); | ||
70 | desc->fa = cpu_to_le32(ext_addr); | ||
71 | |||
72 | desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2)); | ||
73 | desc->ctrl = cpu_to_le32(SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | | ||
74 | (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON); | ||
75 | |||
76 | /* Ext size only matters when we're repeating */ | ||
77 | if (repeat) { | ||
78 | desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2)); | ||
79 | desc->ctrl |= cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) | | ||
80 | SOLO_P2M_REPEAT(repeat)); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id, | ||
85 | struct p2m_desc *desc, int desc_count) | ||
86 | { | 69 | { |
87 | struct solo_p2m_dev *p2m_dev; | 70 | struct solo_p2m_dev *p2m_dev; |
88 | unsigned int timeout; | 71 | unsigned int timeout; |
72 | unsigned int config = 0; | ||
89 | int ret = 0; | 73 | int ret = 0; |
90 | u32 config = 0; | 74 | int p2m_id = 0; |
91 | dma_addr_t desc_dma = 0; | ||
92 | 75 | ||
93 | BUG_ON(id >= SOLO_NR_P2M); | 76 | /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ |
94 | BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC); | 77 | if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { |
78 | p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; | ||
79 | if (p2m_id < 0) | ||
80 | p2m_id = -p2m_id; | ||
81 | } | ||
95 | 82 | ||
96 | p2m_dev = &solo_dev->p2m_dev[id]; | 83 | p2m_dev = &solo_dev->p2m_dev[p2m_id]; |
97 | 84 | ||
98 | mutex_lock(&p2m_dev->mutex); | 85 | if (mutex_lock_interruptible(&p2m_dev->mutex)) |
99 | 86 | return -EINTR; | |
100 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); | ||
101 | 87 | ||
102 | INIT_COMPLETION(p2m_dev->completion); | 88 | INIT_COMPLETION(p2m_dev->completion); |
103 | p2m_dev->error = 0; | 89 | p2m_dev->error = 0; |
104 | 90 | ||
105 | /* Enable the descriptors */ | 91 | if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) { |
106 | config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id)); | 92 | /* For 6010 with more than one desc, we can do a one-shot */ |
107 | desc_dma = pci_map_single(solo_dev->pdev, desc, | 93 | p2m_dev->desc_count = p2m_dev->desc_idx = 0; |
108 | desc_count * sizeof(*desc), | 94 | config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id)); |
109 | PCI_DMA_TODEVICE); | 95 | |
110 | solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma); | 96 | solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma); |
111 | solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1); | 97 | solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt); |
112 | solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config | | 98 | solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config | |
113 | SOLO_P2M_DESC_MODE); | 99 | SOLO_P2M_DESC_MODE); |
114 | 100 | } else { | |
115 | /* Should have all descriptors completed from one interrupt */ | 101 | /* For single descriptors and 6110, we need to run each desc */ |
116 | timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ); | 102 | p2m_dev->desc_count = desc_cnt; |
117 | 103 | p2m_dev->desc_idx = 1; | |
118 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); | 104 | p2m_dev->descs = desc; |
105 | |||
106 | solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id), | ||
107 | desc[1].dma_addr); | ||
108 | solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id), | ||
109 | desc[1].ext_addr); | ||
110 | solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id), | ||
111 | desc[1].cfg); | ||
112 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), | ||
113 | desc[1].ctrl); | ||
114 | } | ||
119 | 115 | ||
120 | /* Reset back to non-descriptor mode */ | 116 | timeout = wait_for_completion_timeout(&p2m_dev->completion, |
121 | solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config); | 117 | solo_dev->p2m_jiffies); |
122 | solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0); | ||
123 | solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0); | ||
124 | pci_unmap_single(solo_dev->pdev, desc_dma, | ||
125 | desc_count * sizeof(*desc), | ||
126 | PCI_DMA_TODEVICE); | ||
127 | 118 | ||
128 | if (p2m_dev->error) | 119 | if (WARN_ON_ONCE(p2m_dev->error)) |
129 | ret = -EIO; | 120 | ret = -EIO; |
130 | else if (timeout == 0) | 121 | else if (timeout == 0) { |
122 | solo_dev->p2m_timeouts++; | ||
131 | ret = -EAGAIN; | 123 | ret = -EAGAIN; |
132 | |||
133 | mutex_unlock(&p2m_dev->mutex); | ||
134 | |||
135 | WARN_ON_ONCE(ret); | ||
136 | |||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id, | ||
141 | struct p2m_desc *pdesc, int wr, | ||
142 | struct scatterlist *sg, u32 sg_off, | ||
143 | u32 ext_addr, u32 size) | ||
144 | { | ||
145 | int i; | ||
146 | int idx; | ||
147 | |||
148 | BUG_ON(id >= SOLO_NR_P2M); | ||
149 | |||
150 | if (WARN_ON_ONCE(!size)) | ||
151 | return -EINVAL; | ||
152 | |||
153 | memset(pdesc, 0, sizeof(*pdesc)); | ||
154 | |||
155 | /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */ | ||
156 | for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0; | ||
157 | i++, sg = sg_next(sg)) { | ||
158 | struct p2m_desc *desc = &pdesc[idx]; | ||
159 | u32 sg_len = sg_dma_len(sg); | ||
160 | u32 len; | ||
161 | |||
162 | if (sg_off >= sg_len) { | ||
163 | sg_off -= sg_len; | ||
164 | continue; | ||
165 | } | ||
166 | |||
167 | sg_len -= sg_off; | ||
168 | len = min(sg_len, size); | ||
169 | |||
170 | solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off, | ||
171 | ext_addr, len, 0, 0); | ||
172 | |||
173 | size -= len; | ||
174 | ext_addr += len; | ||
175 | idx++; | ||
176 | |||
177 | sg_off = 0; | ||
178 | } | 124 | } |
179 | 125 | ||
180 | WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC); | 126 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0); |
181 | 127 | ||
182 | return solo_p2m_dma_desc(solo_dev, id, pdesc, idx); | 128 | /* Don't write here for the no_desc_mode case, because config is 0. |
183 | } | 129 | * We can't test no_desc_mode again, it might race. */ |
130 | if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config) | ||
131 | solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config); | ||
184 | 132 | ||
185 | #ifdef SOLO_TEST_P2M | 133 | mutex_unlock(&p2m_dev->mutex); |
186 | 134 | ||
187 | #define P2M_TEST_CHAR 0xbe | 135 | return ret; |
136 | } | ||
188 | 137 | ||
189 | static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id, | 138 | void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr, |
190 | u32 base, int size) | 139 | dma_addr_t dma_addr, u32 ext_addr, u32 size, |
140 | int repeat, u32 ext_size) | ||
191 | { | 141 | { |
192 | u8 *wr_buf; | 142 | WARN_ON_ONCE(dma_addr & 0x03); |
193 | u8 *rd_buf; | 143 | WARN_ON_ONCE(!size); |
194 | int i; | ||
195 | unsigned long long err_cnt = 0; | ||
196 | 144 | ||
197 | wr_buf = kmalloc(size, GFP_KERNEL); | 145 | desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2); |
198 | if (!wr_buf) { | 146 | desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | |
199 | printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n"); | 147 | (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON; |
200 | return size; | ||
201 | } | ||
202 | 148 | ||
203 | rd_buf = kmalloc(size, GFP_KERNEL); | 149 | if (repeat) { |
204 | if (!rd_buf) { | 150 | desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2); |
205 | printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n"); | 151 | desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) | |
206 | kfree(wr_buf); | 152 | SOLO_P2M_REPEAT(repeat); |
207 | return size; | ||
208 | } | 153 | } |
209 | 154 | ||
210 | memset(wr_buf, P2M_TEST_CHAR, size); | 155 | desc->dma_addr = dma_addr; |
211 | memset(rd_buf, P2M_TEST_CHAR + 1, size); | 156 | desc->ext_addr = ext_addr; |
212 | |||
213 | solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size); | ||
214 | solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size); | ||
215 | |||
216 | for (i = 0; i < size; i++) | ||
217 | if (wr_buf[i] != rd_buf[i]) | ||
218 | err_cnt++; | ||
219 | |||
220 | kfree(wr_buf); | ||
221 | kfree(rd_buf); | ||
222 | |||
223 | return err_cnt; | ||
224 | } | 157 | } |
225 | 158 | ||
226 | #define TEST_CHUNK_SIZE (8 * 1024) | 159 | int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr, |
227 | 160 | dma_addr_t dma_addr, u32 ext_addr, u32 size, | |
228 | static void run_p2m_test(struct solo_dev *solo_dev) | 161 | int repeat, u32 ext_size) |
229 | { | 162 | { |
230 | unsigned long long errs = 0; | 163 | struct solo_p2m_desc desc[2]; |
231 | u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev); | ||
232 | int i, d; | ||
233 | 164 | ||
234 | dev_warn(&solo_dev->pdev->dev, "Testing %u bytes of external ram\n", | 165 | solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat, |
235 | size); | 166 | ext_size); |
236 | 167 | ||
237 | for (i = 0; i < size; i += TEST_CHUNK_SIZE) | 168 | /* No need for desc_dma since we know it is a single-shot */ |
238 | for (d = 0; d < 4; d++) | 169 | return solo_p2m_dma_desc(solo_dev, desc, 0, 1); |
239 | errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE); | ||
240 | |||
241 | dev_warn(&solo_dev->pdev->dev, "Found %llu errors during p2m test\n", | ||
242 | errs); | ||
243 | |||
244 | return; | ||
245 | } | 170 | } |
246 | #else | ||
247 | #define run_p2m_test(__solo) do {} while (0) | ||
248 | #endif | ||
249 | 171 | ||
250 | void solo_p2m_isr(struct solo_dev *solo_dev, int id) | 172 | void solo_p2m_isr(struct solo_dev *solo_dev, int id) |
251 | { | 173 | { |
252 | struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; | 174 | struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; |
175 | struct solo_p2m_desc *desc; | ||
176 | |||
177 | if (p2m_dev->desc_count <= p2m_dev->desc_idx) { | ||
178 | complete(&p2m_dev->completion); | ||
179 | return; | ||
180 | } | ||
253 | 181 | ||
254 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id)); | 182 | /* Setup next descriptor */ |
183 | p2m_dev->desc_idx++; | ||
184 | desc = &p2m_dev->descs[p2m_dev->desc_idx]; | ||
255 | 185 | ||
256 | complete(&p2m_dev->completion); | 186 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); |
187 | solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr); | ||
188 | solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr); | ||
189 | solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg); | ||
190 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl); | ||
257 | } | 191 | } |
258 | 192 | ||
259 | void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status) | 193 | void solo_p2m_error_isr(struct solo_dev *solo_dev) |
260 | { | 194 | { |
195 | unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR); | ||
261 | struct solo_p2m_dev *p2m_dev; | 196 | struct solo_p2m_dev *p2m_dev; |
262 | int i; | 197 | int i; |
263 | 198 | ||
264 | if (!(status & SOLO_PCI_ERR_P2M)) | 199 | if (!(err & SOLO_PCI_ERR_P2M)) |
265 | return; | 200 | return; |
266 | 201 | ||
267 | for (i = 0; i < SOLO_NR_P2M; i++) { | 202 | for (i = 0; i < SOLO_NR_P2M; i++) { |
@@ -280,6 +215,52 @@ void solo_p2m_exit(struct solo_dev *solo_dev) | |||
280 | solo_irq_off(solo_dev, SOLO_IRQ_P2M(i)); | 215 | solo_irq_off(solo_dev, SOLO_IRQ_P2M(i)); |
281 | } | 216 | } |
282 | 217 | ||
218 | static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size) | ||
219 | { | ||
220 | u32 *wr_buf; | ||
221 | u32 *rd_buf; | ||
222 | int i; | ||
223 | int ret = -EIO; | ||
224 | int order = get_order(size); | ||
225 | |||
226 | wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); | ||
227 | if (wr_buf == NULL) | ||
228 | return -1; | ||
229 | |||
230 | rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); | ||
231 | if (rd_buf == NULL) { | ||
232 | free_pages((unsigned long)wr_buf, order); | ||
233 | return -1; | ||
234 | } | ||
235 | |||
236 | for (i = 0; i < (size >> 3); i++) | ||
237 | *(wr_buf + i) = (i << 16) | (i + 1); | ||
238 | |||
239 | for (i = (size >> 3); i < (size >> 2); i++) | ||
240 | *(wr_buf + i) = ~((i << 16) | (i + 1)); | ||
241 | |||
242 | memset(rd_buf, 0x55, size); | ||
243 | |||
244 | if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0)) | ||
245 | goto test_fail; | ||
246 | |||
247 | if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0)) | ||
248 | goto test_fail; | ||
249 | |||
250 | for (i = 0; i < (size >> 2); i++) { | ||
251 | if (*(wr_buf + i) != *(rd_buf + i)) | ||
252 | goto test_fail; | ||
253 | } | ||
254 | |||
255 | ret = 0; | ||
256 | |||
257 | test_fail: | ||
258 | free_pages((unsigned long)wr_buf, order); | ||
259 | free_pages((unsigned long)rd_buf, order); | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
283 | int solo_p2m_init(struct solo_dev *solo_dev) | 264 | int solo_p2m_init(struct solo_dev *solo_dev) |
284 | { | 265 | { |
285 | struct solo_p2m_dev *p2m_dev; | 266 | struct solo_p2m_dev *p2m_dev; |
@@ -294,13 +275,57 @@ int solo_p2m_init(struct solo_dev *solo_dev) | |||
294 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); | 275 | solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); |
295 | solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), | 276 | solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), |
296 | SOLO_P2M_CSC_16BIT_565 | | 277 | SOLO_P2M_CSC_16BIT_565 | |
297 | SOLO_P2M_DMA_INTERVAL(3) | | ||
298 | SOLO_P2M_DESC_INTR_OPT | | 278 | SOLO_P2M_DESC_INTR_OPT | |
279 | SOLO_P2M_DMA_INTERVAL(0) | | ||
299 | SOLO_P2M_PCI_MASTER_MODE); | 280 | SOLO_P2M_PCI_MASTER_MODE); |
300 | solo_irq_on(solo_dev, SOLO_IRQ_P2M(i)); | 281 | solo_irq_on(solo_dev, SOLO_IRQ_P2M(i)); |
301 | } | 282 | } |
302 | 283 | ||
303 | run_p2m_test(solo_dev); | 284 | /* Find correct SDRAM size */ |
285 | for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) { | ||
286 | solo_reg_write(solo_dev, SOLO_DMA_CTRL, | ||
287 | SOLO_DMA_CTRL_REFRESH_CYCLE(1) | | ||
288 | SOLO_DMA_CTRL_SDRAM_SIZE(i) | | ||
289 | SOLO_DMA_CTRL_SDRAM_CLK_INVERT | | ||
290 | SOLO_DMA_CTRL_READ_CLK_SELECT | | ||
291 | SOLO_DMA_CTRL_LATENCY(1)); | ||
292 | |||
293 | solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config | | ||
294 | SOLO_SYS_CFG_RESET); | ||
295 | solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); | ||
296 | |||
297 | switch (i) { | ||
298 | case 2: | ||
299 | if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) || | ||
300 | solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000)) | ||
301 | continue; | ||
302 | break; | ||
303 | |||
304 | case 1: | ||
305 | if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000)) | ||
306 | continue; | ||
307 | break; | ||
308 | |||
309 | default: | ||
310 | if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000)) | ||
311 | continue; | ||
312 | } | ||
313 | |||
314 | solo_dev->sdram_size = (32 << 20) << i; | ||
315 | break; | ||
316 | } | ||
317 | |||
318 | if (!solo_dev->sdram_size) { | ||
319 | dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n"); | ||
320 | return -EIO; | ||
321 | } | ||
322 | |||
323 | if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) { | ||
324 | dev_err(&solo_dev->pdev->dev, | ||
325 | "SDRAM is not large enough (%u < %u)\n", | ||
326 | solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev)); | ||
327 | return -EIO; | ||
328 | } | ||
304 | 329 | ||
305 | return 0; | 330 | return 0; |
306 | } | 331 | } |
diff --git a/drivers/staging/media/solo6x10/registers.h b/drivers/staging/media/solo6x10/registers.h index aca544472c93..5e5c7e6b43bf 100644 --- a/drivers/staging/media/solo6x10/registers.h +++ b/drivers/staging/media/solo6x10/registers.h | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -22,18 +27,18 @@ | |||
22 | 27 | ||
23 | #include "offsets.h" | 28 | #include "offsets.h" |
24 | 29 | ||
25 | /* Global 6X10 system configuration */ | 30 | /* Global 6010 system configuration */ |
26 | #define SOLO_SYS_CFG 0x0000 | 31 | #define SOLO_SYS_CFG 0x0000 |
27 | #define SOLO6010_SYS_CFG_FOUT_EN 0x00000001 /* 6010 only */ | 32 | #define SOLO_SYS_CFG_FOUT_EN 0x00000001 |
28 | #define SOLO6010_SYS_CFG_PLL_BYPASS 0x00000002 /* 6010 only */ | 33 | #define SOLO_SYS_CFG_PLL_BYPASS 0x00000002 |
29 | #define SOLO6010_SYS_CFG_PLL_PWDN 0x00000004 /* 6010 only */ | 34 | #define SOLO_SYS_CFG_PLL_PWDN 0x00000004 |
30 | #define SOLO6010_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) /* 6010 only */ | 35 | #define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) |
31 | #define SOLO6010_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) /* 6010 only */ | 36 | #define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) |
32 | #define SOLO6010_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) /* 6010 only */ | 37 | #define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) |
33 | #define SOLO_SYS_CFG_CLOCK_DIV 0x00080000 | 38 | #define SOLO_SYS_CFG_CLOCK_DIV 0x00080000 |
34 | #define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24) | 39 | #define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24) |
35 | #define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26) | 40 | #define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26) |
36 | #define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 /* 6110: must be set */ | 41 | #define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 |
37 | #define SOLO_SYS_CFG_RESET 0x80000000 | 42 | #define SOLO_SYS_CFG_RESET 0x80000000 |
38 | 43 | ||
39 | #define SOLO_DMA_CTRL 0x0004 | 44 | #define SOLO_DMA_CTRL 0x0004 |
@@ -45,7 +50,9 @@ | |||
45 | #define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) | 50 | #define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) |
46 | #define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) | 51 | #define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) |
47 | #define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) | 52 | #define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) |
48 | #define SOLO_DMA_CTRL1 0x0008 | 53 | |
54 | /* Some things we set in this are undocumented. Why Softlogic?!?! */ | ||
55 | #define SOLO_DMA_CTRL1 0x0008 | ||
49 | 56 | ||
50 | #define SOLO_SYS_VCLK 0x000C | 57 | #define SOLO_SYS_VCLK 0x000C |
51 | #define SOLO_VCLK_INVERT (1<<22) | 58 | #define SOLO_VCLK_INVERT (1<<22) |
@@ -61,7 +68,7 @@ | |||
61 | #define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0) | 68 | #define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0) |
62 | 69 | ||
63 | #define SOLO_IRQ_STAT 0x0010 | 70 | #define SOLO_IRQ_STAT 0x0010 |
64 | #define SOLO_IRQ_ENABLE 0x0014 | 71 | #define SOLO_IRQ_MASK 0x0014 |
65 | #define SOLO_IRQ_P2M(n) (1<<((n)+17)) | 72 | #define SOLO_IRQ_P2M(n) (1<<((n)+17)) |
66 | #define SOLO_IRQ_GPIO (1<<16) | 73 | #define SOLO_IRQ_GPIO (1<<16) |
67 | #define SOLO_IRQ_VIDEO_LOSS (1<<15) | 74 | #define SOLO_IRQ_VIDEO_LOSS (1<<15) |
@@ -82,22 +89,7 @@ | |||
82 | #define SOLO_CHIP_OPTION 0x001C | 89 | #define SOLO_CHIP_OPTION 0x001C |
83 | #define SOLO_CHIP_ID_MASK 0x00000007 | 90 | #define SOLO_CHIP_ID_MASK 0x00000007 |
84 | 91 | ||
85 | #define SOLO6110_PLL_CONFIG 0x0020 | 92 | #define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */ |
86 | #define SOLO6110_PLL_RANGE_BYPASS (0 << 20) | ||
87 | #define SOLO6110_PLL_RANGE_5_10MHZ (1 << 20) | ||
88 | #define SOLO6110_PLL_RANGE_8_16MHZ (2 << 20) | ||
89 | #define SOLO6110_PLL_RANGE_13_26MHZ (3 << 20) | ||
90 | #define SOLO6110_PLL_RANGE_21_42MHZ (4 << 20) | ||
91 | #define SOLO6110_PLL_RANGE_34_68MHZ (5 << 20) | ||
92 | #define SOLO6110_PLL_RANGE_54_108MHZ (6 << 20) | ||
93 | #define SOLO6110_PLL_RANGE_88_200MHZ (7 << 20) | ||
94 | #define SOLO6110_PLL_DIVR(x) (((x) - 1) << 15) | ||
95 | #define SOLO6110_PLL_DIVQ_EXP(x) ((x) << 12) | ||
96 | #define SOLO6110_PLL_DIVF(x) (((x) - 1) << 4) | ||
97 | #define SOLO6110_PLL_RESET (1 << 3) | ||
98 | #define SOLO6110_PLL_BYPASS (1 << 2) | ||
99 | #define SOLO6110_PLL_FSEN (1 << 1) | ||
100 | #define SOLO6110_PLL_FB (1 << 0) | ||
101 | 93 | ||
102 | #define SOLO_EEPROM_CTRL 0x0060 | 94 | #define SOLO_EEPROM_CTRL 0x0060 |
103 | #define SOLO_EEPROM_ACCESS_EN (1<<7) | 95 | #define SOLO_EEPROM_ACCESS_EN (1<<7) |
@@ -105,7 +97,7 @@ | |||
105 | #define SOLO_EEPROM_CLK (1<<2) | 97 | #define SOLO_EEPROM_CLK (1<<2) |
106 | #define SOLO_EEPROM_DO (1<<1) | 98 | #define SOLO_EEPROM_DO (1<<1) |
107 | #define SOLO_EEPROM_DI (1<<0) | 99 | #define SOLO_EEPROM_DI (1<<0) |
108 | #define SOLO_EEPROM_ENABLE (EEPROM_ACCESS_EN | EEPROM_CS) | 100 | #define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS) |
109 | 101 | ||
110 | #define SOLO_PCI_ERR 0x0070 | 102 | #define SOLO_PCI_ERR 0x0070 |
111 | #define SOLO_PCI_ERR_FATAL 0x00000001 | 103 | #define SOLO_PCI_ERR_FATAL 0x00000001 |
@@ -274,8 +266,8 @@ | |||
274 | #define SOLO_VO_FI_CHANGE (1<<20) | 266 | #define SOLO_VO_FI_CHANGE (1<<20) |
275 | #define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) | 267 | #define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) |
276 | #define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) | 268 | #define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) |
277 | #define SOLO_VO_USER_COLOR_SET_NAV (1<<17) | 269 | #define SOLO_VO_USER_COLOR_SET_NAH (1<<17) |
278 | #define SOLO_VO_USER_COLOR_SET_NAH (1<<16) | 270 | #define SOLO_VO_USER_COLOR_SET_NAV (1<<16) |
279 | #define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) | 271 | #define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) |
280 | #define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) | 272 | #define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) |
281 | #define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) | 273 | #define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) |
@@ -401,12 +393,13 @@ | |||
401 | #define SOLO_VE_BLOCK_BASE(n) ((n)<<0) | 393 | #define SOLO_VE_BLOCK_BASE(n) ((n)<<0) |
402 | 394 | ||
403 | #define SOLO_VE_CFG1 0x0614 | 395 | #define SOLO_VE_CFG1 0x0614 |
404 | #define SOLO6110_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 only */ | 396 | #define SOLO_VE_BYTE_ALIGN(n) ((n)<<24) |
405 | #define SOLO6010_VE_BYTE_ALIGN(n) ((n)<<24) /* 6010 only */ | ||
406 | #define SOLO6110_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 only */ | ||
407 | #define SOLO_VE_INSERT_INDEX (1<<18) | 397 | #define SOLO_VE_INSERT_INDEX (1<<18) |
408 | #define SOLO_VE_MOTION_MODE(n) ((n)<<16) | 398 | #define SOLO_VE_MOTION_MODE(n) ((n)<<16) |
409 | #define SOLO_VE_MOTION_BASE(n) ((n)<<0) | 399 | #define SOLO_VE_MOTION_BASE(n) ((n)<<0) |
400 | #define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */ | ||
401 | #define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */ | ||
402 | #define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */ | ||
410 | 403 | ||
411 | #define SOLO_VE_WMRK_POLY 0x061C | 404 | #define SOLO_VE_WMRK_POLY 0x061C |
412 | #define SOLO_VE_VMRK_INIT_KEY 0x0620 | 405 | #define SOLO_VE_VMRK_INIT_KEY 0x0620 |
@@ -420,6 +413,7 @@ | |||
420 | #define SOLO_COMP_TIME_INC(n) ((n)<<25) | 413 | #define SOLO_COMP_TIME_INC(n) ((n)<<25) |
421 | #define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) | 414 | #define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) |
422 | #define SOLO_DCT_INTERVAL(n) ((n)<<16) | 415 | #define SOLO_DCT_INTERVAL(n) ((n)<<16) |
416 | #define SOLO_VE_COMPT_MOT 0x0634 /* 6110 Only */ | ||
423 | 417 | ||
424 | #define SOLO_VE_STATE(n) (0x0640+((n)*4)) | 418 | #define SOLO_VE_STATE(n) (0x0640+((n)*4)) |
425 | 419 | ||
@@ -428,14 +422,21 @@ | |||
428 | #define SOLO_VE_JPEG_QP_CH_H 0x0678 | 422 | #define SOLO_VE_JPEG_QP_CH_H 0x0678 |
429 | #define SOLO_VE_JPEG_CFG 0x067C | 423 | #define SOLO_VE_JPEG_CFG 0x067C |
430 | #define SOLO_VE_JPEG_CTRL 0x0680 | 424 | #define SOLO_VE_JPEG_CTRL 0x0680 |
431 | 425 | #define SOLO_VE_CODE_ENCRYPT 0x0684 /* 6110 Only */ | |
426 | #define SOLO_VE_JPEG_CFG1 0x0688 /* 6110 Only */ | ||
427 | #define SOLO_VE_WMRK_ENABLE 0x068C /* 6110 Only */ | ||
432 | #define SOLO_VE_OSD_CH 0x0690 | 428 | #define SOLO_VE_OSD_CH 0x0690 |
433 | #define SOLO_VE_OSD_BASE 0x0694 | 429 | #define SOLO_VE_OSD_BASE 0x0694 |
434 | #define SOLO_VE_OSD_CLR 0x0698 | 430 | #define SOLO_VE_OSD_CLR 0x0698 |
435 | #define SOLO_VE_OSD_OPT 0x069C | 431 | #define SOLO_VE_OSD_OPT 0x069C |
432 | #define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */ | ||
433 | #define SOLO_VE_OSD_H_SHADOW (1<<15) | ||
434 | #define SOLO_VE_OSD_V_SHADOW (1<<14) | ||
435 | #define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7) | ||
436 | #define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f) | ||
436 | 437 | ||
437 | #define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4)) | 438 | #define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4)) |
438 | #define SOLO6010_VE_CH_MOT(ch) (0x0740+((ch)*4)) /* 6010 only */ | 439 | #define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4)) |
439 | #define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4)) | 440 | #define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4)) |
440 | #define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4)) | 441 | #define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4)) |
441 | #define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4)) | 442 | #define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4)) |
@@ -447,7 +448,7 @@ | |||
447 | #define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) | 448 | #define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) |
448 | 449 | ||
449 | #define SOLO_VD_CFG0 0x0900 | 450 | #define SOLO_VD_CFG0 0x0900 |
450 | #define SOLO6010_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) /* 6010 only */ | 451 | #define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) |
451 | #define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) | 452 | #define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) |
452 | #define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) | 453 | #define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) |
453 | #define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) | 454 | #define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) |
@@ -599,9 +600,9 @@ | |||
599 | #define SOLO_UART_RX_DATA_POP (1<<8) | 600 | #define SOLO_UART_RX_DATA_POP (1<<8) |
600 | 601 | ||
601 | #define SOLO_TIMER_CLOCK_NUM 0x0be0 | 602 | #define SOLO_TIMER_CLOCK_NUM 0x0be0 |
602 | #define SOLO_TIMER_WATCHDOG 0x0be4 | ||
603 | #define SOLO_TIMER_USEC 0x0be8 | 603 | #define SOLO_TIMER_USEC 0x0be8 |
604 | #define SOLO_TIMER_SEC 0x0bec | 604 | #define SOLO_TIMER_SEC 0x0bec |
605 | #define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */ | ||
605 | 606 | ||
606 | #define SOLO_AUDIO_CONTROL 0x0D00 | 607 | #define SOLO_AUDIO_CONTROL 0x0D00 |
607 | #define SOLO_AUDIO_ENABLE (1<<31) | 608 | #define SOLO_AUDIO_ENABLE (1<<31) |
@@ -629,9 +630,10 @@ | |||
629 | #define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10)) | 630 | #define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10)) |
630 | #define SOLO_AUDIO_STA 0x0D14 | 631 | #define SOLO_AUDIO_STA 0x0D14 |
631 | 632 | ||
632 | 633 | /* | |
633 | #define SOLO_WATCHDOG 0x0BE4 | 634 | * Watchdog configuration |
634 | #define WATCHDOG_STAT(status) (status<<8) | 635 | */ |
635 | #define WATCHDOG_TIME(sec) (sec&0xff) | 636 | #define SOLO_WATCHDOG 0x0be4 |
637 | #define SOLO_WATCHDOG_SET(status, sec) (status << 8 | (sec & 0xff)) | ||
636 | 638 | ||
637 | #endif /* __SOLO6X10_REGISTERS_H */ | 639 | #endif /* __SOLO6X10_REGISTERS_H */ |
diff --git a/drivers/staging/media/solo6x10/solo6x10-jpeg.h b/drivers/staging/media/solo6x10/solo6x10-jpeg.h index 50defec318cc..c5218ceeabca 100644 --- a/drivers/staging/media/solo6x10/solo6x10-jpeg.h +++ b/drivers/staging/media/solo6x10/solo6x10-jpeg.h | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -20,7 +25,7 @@ | |||
20 | #ifndef __SOLO6X10_JPEG_H | 25 | #ifndef __SOLO6X10_JPEG_H |
21 | #define __SOLO6X10_JPEG_H | 26 | #define __SOLO6X10_JPEG_H |
22 | 27 | ||
23 | static unsigned char jpeg_header[] = { | 28 | static const unsigned char jpeg_header[] = { |
24 | 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c, | 29 | 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c, |
25 | 0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79, | 30 | 0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79, |
26 | 0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16, | 31 | 0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16, |
@@ -102,4 +107,87 @@ static unsigned char jpeg_header[] = { | |||
102 | /* This is the byte marker for the start of SOF0: 0xffc0 marker */ | 107 | /* This is the byte marker for the start of SOF0: 0xffc0 marker */ |
103 | #define SOF0_START 575 | 108 | #define SOF0_START 575 |
104 | 109 | ||
110 | /* This is the byte marker for the start of the DQT */ | ||
111 | #define DQT_START 17 | ||
112 | #define DQT_LEN 138 | ||
113 | const unsigned char jpeg_dqt[4][DQT_LEN] = { | ||
114 | { | ||
115 | 0xff, 0xdb, 0x00, 0x43, 0x00, | ||
116 | 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, | ||
117 | 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, | ||
118 | 0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, | ||
119 | 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, | ||
120 | 0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, | ||
121 | 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, | ||
122 | 0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, | ||
123 | 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, | ||
124 | 0xff, 0xdb, 0x00, 0x43, 0x01, | ||
125 | 0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, | ||
126 | 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32, | ||
127 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, | ||
128 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, | ||
129 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, | ||
130 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, | ||
131 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, | ||
132 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 | ||
133 | }, { | ||
134 | 0xff, 0xdb, 0x00, 0x43, 0x00, | ||
135 | 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, | ||
136 | 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, | ||
137 | 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, | ||
138 | 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, | ||
139 | 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, | ||
140 | 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, | ||
141 | 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, | ||
142 | 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, | ||
143 | 0xff, 0xdb, 0x00, 0x43, 0x01, | ||
144 | 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, | ||
145 | 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, | ||
146 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | ||
147 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | ||
148 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | ||
149 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | ||
150 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | ||
151 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 | ||
152 | }, { | ||
153 | 0xff, 0xdb, 0x00, 0x43, 0x00, | ||
154 | 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, | ||
155 | 0x1a, 0x1c, 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, | ||
156 | 0x34, 0x30, 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, | ||
157 | 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, | ||
158 | 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, | ||
159 | 0xae, 0x8a, 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, | ||
160 | 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, | ||
161 | 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, | ||
162 | 0xff, 0xdb, 0x00, 0x43, 0x01, | ||
163 | 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, | ||
164 | 0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6, | ||
165 | 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, | ||
166 | 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, | ||
167 | 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, | ||
168 | 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, | ||
169 | 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, | ||
170 | 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6 | ||
171 | }, { | ||
172 | 0xff, 0xdb, 0x00, 0x43, 0x00, | ||
173 | 0x30, 0x21, 0x24, 0x2a, 0x24, 0x1e, 0x30, 0x2a, | ||
174 | 0x27, 0x2a, 0x36, 0x33, 0x30, 0x39, 0x48, 0x78, | ||
175 | 0x4e, 0x48, 0x42, 0x42, 0x48, 0x93, 0x69, 0x6f, | ||
176 | 0x57, 0x78, 0xae, 0x99, 0xb7, 0xb4, 0xab, 0x99, | ||
177 | 0xa8, 0xa5, 0xc0, 0xd8, 0xff, 0xea, 0xc0, 0xcc, | ||
178 | 0xff, 0xcf, 0xa5, 0xa8, 0xf0, 0xff, 0xf3, 0xff, | ||
179 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xba, 0xe7, 0xff, | ||
180 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
181 | 0xff, 0xdb, 0x00, 0x43, 0x01, | ||
182 | 0x33, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e, | ||
183 | 0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff, | ||
184 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
185 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
186 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
187 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
188 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
189 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
190 | } | ||
191 | }; | ||
192 | |||
105 | #endif /* __SOLO6X10_JPEG_H */ | 193 | #endif /* __SOLO6X10_JPEG_H */ |
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index abee7213202f..a75d9395b7b1 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -20,20 +25,20 @@ | |||
20 | #ifndef __SOLO6X10_H | 25 | #ifndef __SOLO6X10_H |
21 | #define __SOLO6X10_H | 26 | #define __SOLO6X10_H |
22 | 27 | ||
23 | #include <linux/version.h> | ||
24 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
25 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
26 | #include <linux/semaphore.h> | ||
27 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
28 | #include <linux/list.h> | 31 | #include <linux/list.h> |
29 | #include <linux/wait.h> | 32 | #include <linux/wait.h> |
30 | #include <linux/delay.h> | 33 | #include <linux/stringify.h> |
31 | #include <linux/slab.h> | 34 | #include <linux/io.h> |
32 | #include <asm/io.h> | ||
33 | #include <linux/atomic.h> | 35 | #include <linux/atomic.h> |
36 | #include <linux/slab.h> | ||
34 | #include <linux/videodev2.h> | 37 | #include <linux/videodev2.h> |
38 | |||
35 | #include <media/v4l2-dev.h> | 39 | #include <media/v4l2-dev.h> |
36 | #include <media/videobuf-core.h> | 40 | #include <media/videobuf-core.h> |
41 | |||
37 | #include "registers.h" | 42 | #include "registers.h" |
38 | 43 | ||
39 | #ifndef PCI_VENDOR_ID_SOFTLOGIC | 44 | #ifndef PCI_VENDOR_ID_SOFTLOGIC |
@@ -58,19 +63,24 @@ | |||
58 | #define PCI_DEVICE_ID_BC_6110_16 0x5310 | 63 | #define PCI_DEVICE_ID_BC_6110_16 0x5310 |
59 | #endif /* Bluecherry */ | 64 | #endif /* Bluecherry */ |
60 | 65 | ||
66 | /* Used in pci_device_id, and solo_dev->type */ | ||
67 | #define SOLO_DEV_6010 0 | ||
68 | #define SOLO_DEV_6110 1 | ||
69 | |||
61 | #define SOLO6X10_NAME "solo6x10" | 70 | #define SOLO6X10_NAME "solo6x10" |
62 | 71 | ||
63 | #define SOLO_MAX_CHANNELS 16 | 72 | #define SOLO_MAX_CHANNELS 16 |
64 | 73 | ||
65 | /* Make sure these two match */ | 74 | /* Make sure these two match */ |
66 | #define SOLO6X10_VERSION "2.1.0" | ||
67 | #define SOLO6X10_VER_MAJOR 2 | 75 | #define SOLO6X10_VER_MAJOR 2 |
68 | #define SOLO6X10_VER_MINOR 0 | 76 | #define SOLO6X10_VER_MINOR 4 |
69 | #define SOLO6X10_VER_SUB 0 | 77 | #define SOLO6X10_VER_SUB 4 |
70 | #define SOLO6X10_VER_NUM \ | 78 | #define SOLO6X10_VER_NUM \ |
71 | KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB) | 79 | KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB) |
72 | 80 | #define SOLO6X10_VERSION \ | |
73 | #define FLAGS_6110 1 | 81 | __stringify(SOLO6X10_VER_MAJOR) "." \ |
82 | __stringify(SOLO6X10_VER_MINOR) "." \ | ||
83 | __stringify(SOLO6X10_VER_SUB) | ||
74 | 84 | ||
75 | /* | 85 | /* |
76 | * The SOLO6x10 actually has 8 i2c channels, but we only use 2. | 86 | * The SOLO6x10 actually has 8 i2c channels, but we only use 2. |
@@ -84,16 +94,7 @@ | |||
84 | /* DMA Engine setup */ | 94 | /* DMA Engine setup */ |
85 | #define SOLO_NR_P2M 4 | 95 | #define SOLO_NR_P2M 4 |
86 | #define SOLO_NR_P2M_DESC 256 | 96 | #define SOLO_NR_P2M_DESC 256 |
87 | /* MPEG and JPEG share the same interrupt and locks so they must be together | 97 | #define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16) |
88 | * in the same dma channel. */ | ||
89 | #define SOLO_P2M_DMA_ID_MP4E 0 | ||
90 | #define SOLO_P2M_DMA_ID_JPEG 0 | ||
91 | #define SOLO_P2M_DMA_ID_MP4D 1 | ||
92 | #define SOLO_P2M_DMA_ID_G723D 1 | ||
93 | #define SOLO_P2M_DMA_ID_DISP 2 | ||
94 | #define SOLO_P2M_DMA_ID_OSG 2 | ||
95 | #define SOLO_P2M_DMA_ID_G723E 3 | ||
96 | #define SOLO_P2M_DMA_ID_VIN 3 | ||
97 | 98 | ||
98 | /* Encoder standard modes */ | 99 | /* Encoder standard modes */ |
99 | #define SOLO_ENC_MODE_CIF 2 | 100 | #define SOLO_ENC_MODE_CIF 2 |
@@ -103,12 +104,6 @@ | |||
103 | #define SOLO_DEFAULT_GOP 30 | 104 | #define SOLO_DEFAULT_GOP 30 |
104 | #define SOLO_DEFAULT_QP 3 | 105 | #define SOLO_DEFAULT_QP 3 |
105 | 106 | ||
106 | /* There is 8MB memory available for solo to buffer MPEG4 frames. | ||
107 | * This gives us 512 * 16kbyte queues. */ | ||
108 | #define SOLO_NR_RING_BUFS 512 | ||
109 | |||
110 | #define SOLO_CLOCK_MHZ 108 | ||
111 | |||
112 | #ifndef V4L2_BUF_FLAG_MOTION_ON | 107 | #ifndef V4L2_BUF_FLAG_MOTION_ON |
113 | #define V4L2_BUF_FLAG_MOTION_ON 0x0400 | 108 | #define V4L2_BUF_FLAG_MOTION_ON 0x0400 |
114 | #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 | 109 | #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 |
@@ -128,64 +123,67 @@ enum SOLO_I2C_STATE { | |||
128 | IIC_STATE_STOP | 123 | IIC_STATE_STOP |
129 | }; | 124 | }; |
130 | 125 | ||
131 | struct p2m_desc { | 126 | /* Defined in Table 4-16, Page 68-69 of the 6010 Datasheet */ |
132 | u32 ctrl; | 127 | struct solo_p2m_desc { |
133 | u32 ext; | 128 | u32 ctrl; |
134 | u32 ta; | 129 | u32 cfg; |
135 | u32 fa; | 130 | u32 dma_addr; |
131 | u32 ext_addr; | ||
136 | }; | 132 | }; |
137 | 133 | ||
138 | struct solo_p2m_dev { | 134 | struct solo_p2m_dev { |
139 | struct mutex mutex; | 135 | struct mutex mutex; |
140 | struct completion completion; | 136 | struct completion completion; |
137 | int desc_count; | ||
138 | int desc_idx; | ||
139 | struct solo_p2m_desc *descs; | ||
141 | int error; | 140 | int error; |
142 | }; | 141 | }; |
143 | 142 | ||
144 | #define OSD_TEXT_MAX 30 | 143 | #define OSD_TEXT_MAX 44 |
145 | |||
146 | enum solo_enc_types { | ||
147 | SOLO_ENC_TYPE_STD, | ||
148 | SOLO_ENC_TYPE_EXT, | ||
149 | }; | ||
150 | 144 | ||
151 | struct solo_enc_dev { | 145 | struct solo_enc_dev { |
152 | struct solo_dev *solo_dev; | 146 | struct solo_dev *solo_dev; |
153 | /* V4L2 Items */ | 147 | /* V4L2 Items */ |
154 | struct video_device *vfd; | 148 | struct video_device *vfd; |
155 | /* General accounting */ | 149 | /* General accounting */ |
156 | wait_queue_head_t thread_wait; | 150 | struct mutex enable_lock; |
157 | spinlock_t lock; | 151 | spinlock_t motion_lock; |
158 | atomic_t readers; | 152 | atomic_t readers; |
153 | atomic_t mpeg_readers; | ||
159 | u8 ch; | 154 | u8 ch; |
160 | u8 mode, gop, qp, interlaced, interval; | 155 | u8 mode, gop, qp, interlaced, interval; |
161 | u8 reset_gop; | ||
162 | u8 bw_weight; | 156 | u8 bw_weight; |
163 | u8 motion_detected; | ||
164 | u16 motion_thresh; | 157 | u16 motion_thresh; |
165 | u16 width; | 158 | u16 width; |
166 | u16 height; | 159 | u16 height; |
160 | |||
161 | /* OSD buffers */ | ||
167 | char osd_text[OSD_TEXT_MAX + 1]; | 162 | char osd_text[OSD_TEXT_MAX + 1]; |
168 | }; | 163 | u8 osd_buf[SOLO_EOSD_EXT_SIZE_MAX] |
164 | __aligned(4); | ||
169 | 165 | ||
170 | struct solo_enc_buf { | 166 | /* VOP stuff */ |
171 | u8 vop; | 167 | unsigned char vop[64]; |
172 | u8 ch; | 168 | int vop_len; |
173 | enum solo_enc_types type; | 169 | unsigned char jpeg_header[1024]; |
174 | u32 off; | 170 | int jpeg_len; |
175 | u32 size; | 171 | |
176 | u32 jpeg_off; | 172 | /* File handles that are listening for buffers */ |
177 | u32 jpeg_size; | 173 | struct list_head listeners; |
178 | struct timeval ts; | ||
179 | }; | 174 | }; |
180 | 175 | ||
181 | /* The SOLO6x10 PCI Device */ | 176 | /* The SOLO6x10 PCI Device */ |
182 | struct solo_dev { | 177 | struct solo_dev { |
183 | /* General stuff */ | 178 | /* General stuff */ |
184 | struct pci_dev *pdev; | 179 | struct pci_dev *pdev; |
180 | int type; | ||
181 | unsigned int time_sync; | ||
182 | unsigned int usec_lsb; | ||
183 | unsigned int clock_mhz; | ||
185 | u8 __iomem *reg_base; | 184 | u8 __iomem *reg_base; |
186 | int nr_chans; | 185 | int nr_chans; |
187 | int nr_ext; | 186 | int nr_ext; |
188 | u32 flags; | ||
189 | u32 irq_mask; | 187 | u32 irq_mask; |
190 | u32 motion_mask; | 188 | u32 motion_mask; |
191 | spinlock_t reg_io_lock; | 189 | spinlock_t reg_io_lock; |
@@ -206,6 +204,9 @@ struct solo_dev { | |||
206 | 204 | ||
207 | /* P2M DMA Engine */ | 205 | /* P2M DMA Engine */ |
208 | struct solo_p2m_dev p2m_dev[SOLO_NR_P2M]; | 206 | struct solo_p2m_dev p2m_dev[SOLO_NR_P2M]; |
207 | atomic_t p2m_count; | ||
208 | int p2m_jiffies; | ||
209 | unsigned int p2m_timeouts; | ||
209 | 210 | ||
210 | /* V4L2 Display items */ | 211 | /* V4L2 Display items */ |
211 | struct video_device *vfd; | 212 | struct video_device *vfd; |
@@ -219,9 +220,6 @@ struct solo_dev { | |||
219 | u16 enc_bw_remain; | 220 | u16 enc_bw_remain; |
220 | /* IDX into hw mp4 encoder */ | 221 | /* IDX into hw mp4 encoder */ |
221 | u8 enc_idx; | 222 | u8 enc_idx; |
222 | /* Our software ring of enc buf references */ | ||
223 | u16 enc_wr_idx; | ||
224 | struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS]; | ||
225 | 223 | ||
226 | /* Current video settings */ | 224 | /* Current video settings */ |
227 | u32 video_type; | 225 | u32 video_type; |
@@ -230,11 +228,32 @@ struct solo_dev { | |||
230 | u16 vin_hstart, vin_vstart; | 228 | u16 vin_hstart, vin_vstart; |
231 | u8 fps; | 229 | u8 fps; |
232 | 230 | ||
231 | /* JPEG Qp setting */ | ||
232 | spinlock_t jpeg_qp_lock; | ||
233 | u32 jpeg_qp[2]; | ||
234 | |||
233 | /* Audio components */ | 235 | /* Audio components */ |
234 | struct snd_card *snd_card; | 236 | struct snd_card *snd_card; |
235 | struct snd_pcm *snd_pcm; | 237 | struct snd_pcm *snd_pcm; |
236 | atomic_t snd_users; | 238 | atomic_t snd_users; |
237 | int g723_hw_idx; | 239 | int g723_hw_idx; |
240 | |||
241 | /* sysfs stuffs */ | ||
242 | struct device dev; | ||
243 | int sdram_size; | ||
244 | struct bin_attribute sdram_attr; | ||
245 | unsigned int sys_config; | ||
246 | |||
247 | /* Ring thread */ | ||
248 | struct task_struct *ring_thread; | ||
249 | wait_queue_head_t ring_thread_wait; | ||
250 | atomic_t enc_users; | ||
251 | atomic_t disp_users; | ||
252 | |||
253 | /* VOP_HEADER handling */ | ||
254 | void *vh_buf; | ||
255 | dma_addr_t vh_dma; | ||
256 | int vh_size; | ||
238 | }; | 257 | }; |
239 | 258 | ||
240 | static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) | 259 | static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) |
@@ -255,7 +274,8 @@ static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) | |||
255 | return ret; | 274 | return ret; |
256 | } | 275 | } |
257 | 276 | ||
258 | static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) | 277 | static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, |
278 | u32 data) | ||
259 | { | 279 | { |
260 | unsigned long flags; | 280 | unsigned long flags; |
261 | u16 val; | 281 | u16 val; |
@@ -270,8 +290,17 @@ static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) | |||
270 | spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); | 290 | spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); |
271 | } | 291 | } |
272 | 292 | ||
273 | void solo_irq_on(struct solo_dev *solo_dev, u32 mask); | 293 | static inline void solo_irq_on(struct solo_dev *dev, u32 mask) |
274 | void solo_irq_off(struct solo_dev *solo_dev, u32 mask); | 294 | { |
295 | dev->irq_mask |= mask; | ||
296 | solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask); | ||
297 | } | ||
298 | |||
299 | static inline void solo_irq_off(struct solo_dev *dev, u32 mask) | ||
300 | { | ||
301 | dev->irq_mask &= ~mask; | ||
302 | solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask); | ||
303 | } | ||
275 | 304 | ||
276 | /* Init/exit routeines for subsystems */ | 305 | /* Init/exit routeines for subsystems */ |
277 | int solo_disp_init(struct solo_dev *solo_dev); | 306 | int solo_disp_init(struct solo_dev *solo_dev); |
@@ -286,13 +315,13 @@ void solo_i2c_exit(struct solo_dev *solo_dev); | |||
286 | int solo_p2m_init(struct solo_dev *solo_dev); | 315 | int solo_p2m_init(struct solo_dev *solo_dev); |
287 | void solo_p2m_exit(struct solo_dev *solo_dev); | 316 | void solo_p2m_exit(struct solo_dev *solo_dev); |
288 | 317 | ||
289 | int solo_v4l2_init(struct solo_dev *solo_dev); | 318 | int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr); |
290 | void solo_v4l2_exit(struct solo_dev *solo_dev); | 319 | void solo_v4l2_exit(struct solo_dev *solo_dev); |
291 | 320 | ||
292 | int solo_enc_init(struct solo_dev *solo_dev); | 321 | int solo_enc_init(struct solo_dev *solo_dev); |
293 | void solo_enc_exit(struct solo_dev *solo_dev); | 322 | void solo_enc_exit(struct solo_dev *solo_dev); |
294 | 323 | ||
295 | int solo_enc_v4l2_init(struct solo_dev *solo_dev); | 324 | int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr); |
296 | void solo_enc_v4l2_exit(struct solo_dev *solo_dev); | 325 | void solo_enc_v4l2_exit(struct solo_dev *solo_dev); |
297 | 326 | ||
298 | int solo_g723_init(struct solo_dev *solo_dev); | 327 | int solo_g723_init(struct solo_dev *solo_dev); |
@@ -301,7 +330,7 @@ void solo_g723_exit(struct solo_dev *solo_dev); | |||
301 | /* ISR's */ | 330 | /* ISR's */ |
302 | int solo_i2c_isr(struct solo_dev *solo_dev); | 331 | int solo_i2c_isr(struct solo_dev *solo_dev); |
303 | void solo_p2m_isr(struct solo_dev *solo_dev, int id); | 332 | void solo_p2m_isr(struct solo_dev *solo_dev, int id); |
304 | void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status); | 333 | void solo_p2m_error_isr(struct solo_dev *solo_dev); |
305 | void solo_enc_v4l2_isr(struct solo_dev *solo_dev); | 334 | void solo_enc_v4l2_isr(struct solo_dev *solo_dev); |
306 | void solo_g723_isr(struct solo_dev *solo_dev); | 335 | void solo_g723_isr(struct solo_dev *solo_dev); |
307 | void solo_motion_isr(struct solo_dev *solo_dev); | 336 | void solo_motion_isr(struct solo_dev *solo_dev); |
@@ -313,24 +342,39 @@ void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off, | |||
313 | u8 data); | 342 | u8 data); |
314 | 343 | ||
315 | /* P2M DMA */ | 344 | /* P2M DMA */ |
316 | int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr, | 345 | int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr, |
317 | dma_addr_t dma_addr, u32 ext_addr, u32 size); | 346 | dma_addr_t dma_addr, u32 ext_addr, u32 size, |
318 | int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr, | 347 | int repeat, u32 ext_size); |
319 | void *sys_addr, u32 ext_addr, u32 size); | 348 | int solo_p2m_dma(struct solo_dev *solo_dev, int wr, |
320 | int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id, | 349 | void *sys_addr, u32 ext_addr, u32 size, |
321 | struct p2m_desc *pdesc, int wr, | 350 | int repeat, u32 ext_size); |
322 | struct scatterlist *sglist, u32 sg_off, | 351 | void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr, |
323 | u32 ext_addr, u32 size); | 352 | dma_addr_t dma_addr, u32 ext_addr, u32 size, |
324 | void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, | 353 | int repeat, u32 ext_size); |
325 | u32 ext_addr, u32 size, int repeat, u32 ext_size); | 354 | int solo_p2m_dma_desc(struct solo_dev *solo_dev, |
326 | int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id, | 355 | struct solo_p2m_desc *desc, dma_addr_t desc_dma, |
327 | struct p2m_desc *desc, int desc_count); | 356 | int desc_cnt); |
328 | 357 | ||
329 | /* Set the threshold for motion detection */ | 358 | /* Set the threshold for motion detection */ |
330 | void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); | 359 | int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); |
360 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, | ||
361 | u16 block); | ||
331 | #define SOLO_DEF_MOT_THRESH 0x0300 | 362 | #define SOLO_DEF_MOT_THRESH 0x0300 |
332 | 363 | ||
333 | /* Write text on OSD */ | 364 | /* Write text on OSD */ |
334 | int solo_osd_print(struct solo_enc_dev *solo_enc); | 365 | int solo_osd_print(struct solo_enc_dev *solo_enc); |
335 | 366 | ||
367 | /* EEPROM commands */ | ||
368 | unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en); | ||
369 | unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc); | ||
370 | int solo_eeprom_write(struct solo_dev *solo_dev, int loc, | ||
371 | unsigned short data); | ||
372 | |||
373 | /* JPEG Qp functions */ | ||
374 | void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, | ||
375 | unsigned int qp); | ||
376 | int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch); | ||
377 | |||
378 | #define CHK_FLAGS(v, flags) (((v) & (flags)) == (flags)) | ||
379 | |||
336 | #endif /* __SOLO6X10_H */ | 380 | #endif /* __SOLO6X10_H */ |
diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index db56b42c56c6..365ab1012881 100644 --- a/drivers/staging/media/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -18,12 +23,12 @@ | |||
18 | */ | 23 | */ |
19 | 24 | ||
20 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/delay.h> | ||
27 | |||
21 | #include "solo6x10.h" | 28 | #include "solo6x10.h" |
22 | #include "tw28.h" | 29 | #include "tw28.h" |
23 | 30 | ||
24 | /* XXX: Some of these values are masked into an 8-bit regs, and shifted | 31 | #define DEFAULT_HDELAY_NTSC (32 - 8) |
25 | * around for other 8-bit regs. What are the magic bits in these values? */ | ||
26 | #define DEFAULT_HDELAY_NTSC (32 - 4) | ||
27 | #define DEFAULT_HACTIVE_NTSC (720 + 16) | 32 | #define DEFAULT_HACTIVE_NTSC (720 + 16) |
28 | #define DEFAULT_VDELAY_NTSC (7 - 2) | 33 | #define DEFAULT_VDELAY_NTSC (7 - 2) |
29 | #define DEFAULT_VACTIVE_NTSC (240 + 4) | 34 | #define DEFAULT_VACTIVE_NTSC (240 + 4) |
@@ -33,15 +38,16 @@ | |||
33 | #define DEFAULT_VDELAY_PAL (6) | 38 | #define DEFAULT_VDELAY_PAL (6) |
34 | #define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) | 39 | #define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) |
35 | 40 | ||
36 | static u8 tbl_tw2864_template[] = { | 41 | |
37 | 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ | 42 | static const u8 tbl_tw2864_ntsc_template[] = { |
38 | 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, | 43 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ |
39 | 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ | 44 | 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, |
40 | 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, | 45 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ |
41 | 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ | 46 | 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, |
42 | 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, | 47 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ |
43 | 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ | 48 | 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, |
44 | 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, | 49 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ |
50 | 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, | ||
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ | 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ |
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ | 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ |
@@ -61,14 +67,49 @@ static u8 tbl_tw2864_template[] = { | |||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ | 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ |
62 | 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, | 68 | 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, |
63 | 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ | 69 | 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ |
64 | 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, | 70 | 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, |
65 | 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ | 71 | 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ |
66 | 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, | 72 | 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, |
67 | 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ | 73 | 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ |
68 | 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, | 74 | 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, |
69 | }; | 75 | }; |
70 | 76 | ||
71 | static u8 tbl_tw2865_ntsc_template[] = { | 77 | static const u8 tbl_tw2864_pal_template[] = { |
78 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ | ||
79 | 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, | ||
80 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ | ||
81 | 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, | ||
82 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ | ||
83 | 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, | ||
84 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ | ||
85 | 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, | ||
86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ | ||
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ | ||
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ | ||
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ | ||
93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, | ||
94 | 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ | ||
95 | 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, | ||
96 | 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ | ||
97 | 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01, | ||
98 | 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ | ||
99 | 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, | ||
100 | 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ | ||
101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ | ||
103 | 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, | ||
104 | 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ | ||
105 | 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, | ||
106 | 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ | ||
107 | 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, | ||
108 | 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */ | ||
109 | 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, | ||
110 | }; | ||
111 | |||
112 | static const u8 tbl_tw2865_ntsc_template[] = { | ||
72 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ | 113 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ |
73 | 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, | 114 | 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, |
74 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ | 115 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ |
@@ -103,7 +144,7 @@ static u8 tbl_tw2865_ntsc_template[] = { | |||
103 | 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, | 144 | 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, |
104 | }; | 145 | }; |
105 | 146 | ||
106 | static u8 tbl_tw2865_pal_template[] = { | 147 | static const u8 tbl_tw2865_pal_template[] = { |
107 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ | 148 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ |
108 | 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, | 149 | 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, |
109 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ | 150 | 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ |
@@ -180,8 +221,8 @@ static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off, | |||
180 | msleep_interruptible(1); | 221 | msleep_interruptible(1); |
181 | } | 222 | } |
182 | 223 | ||
183 | /* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", | 224 | /* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */ |
184 | addr, off, val); */ | 225 | /* addr, off, val); */ |
185 | } | 226 | } |
186 | 227 | ||
187 | static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) | 228 | static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) |
@@ -216,16 +257,17 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) | |||
216 | 257 | ||
217 | for (i = 0; i < 0xff; i++) { | 258 | for (i = 0; i < 0xff; i++) { |
218 | /* Skip read only registers */ | 259 | /* Skip read only registers */ |
219 | if (i >= 0xb8 && i <= 0xc1) | 260 | switch (i) { |
220 | continue; | 261 | case 0xb8 ... 0xc1: |
221 | if ((i & ~0x30) == 0x00 || | 262 | case 0xc4 ... 0xc7: |
222 | (i & ~0x30) == 0x0c || | 263 | case 0xfd: |
223 | (i & ~0x30) == 0x0d) | ||
224 | continue; | ||
225 | if (i >= 0xc4 && i <= 0xc7) | ||
226 | continue; | 264 | continue; |
227 | if (i == 0xfd) | 265 | } |
266 | switch (i & ~0x30) { | ||
267 | case 0x00: | ||
268 | case 0x0c ... 0x0d: | ||
228 | continue; | 269 | continue; |
270 | } | ||
229 | 271 | ||
230 | tw_write_and_verify(solo_dev, dev_addr, i, | 272 | tw_write_and_verify(solo_dev, dev_addr, i, |
231 | tbl_tw2865_common[i]); | 273 | tbl_tw2865_common[i]); |
@@ -236,11 +278,15 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) | |||
236 | 278 | ||
237 | static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) | 279 | static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) |
238 | { | 280 | { |
239 | u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)]; | 281 | u8 tbl_tw2864_common[256]; |
240 | int i; | 282 | int i; |
241 | 283 | ||
242 | memcpy(tbl_tw2864_common, tbl_tw2864_template, | 284 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) |
243 | sizeof(tbl_tw2864_common)); | 285 | memcpy(tbl_tw2864_common, tbl_tw2864_pal_template, |
286 | sizeof(tbl_tw2864_common)); | ||
287 | else | ||
288 | memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template, | ||
289 | sizeof(tbl_tw2864_common)); | ||
244 | 290 | ||
245 | if (solo_dev->tw2865 == 0) { | 291 | if (solo_dev->tw2865 == 0) { |
246 | /* IRQ Mode */ | 292 | /* IRQ Mode */ |
@@ -285,33 +331,19 @@ static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) | |||
285 | } | 331 | } |
286 | } | 332 | } |
287 | 333 | ||
288 | /* NTSC or PAL */ | ||
289 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) { | ||
290 | for (i = 0; i < 4; i++) { | ||
291 | tbl_tw2864_common[0x07 | (i << 4)] |= 0x10; | ||
292 | tbl_tw2864_common[0x08 | (i << 4)] |= 0x06; | ||
293 | tbl_tw2864_common[0x0a | (i << 4)] |= 0x08; | ||
294 | tbl_tw2864_common[0x0b | (i << 4)] |= 0x13; | ||
295 | tbl_tw2864_common[0x0e | (i << 4)] |= 0x01; | ||
296 | } | ||
297 | tbl_tw2864_common[0x9d] = 0x90; | ||
298 | tbl_tw2864_common[0xf3] = 0x00; | ||
299 | tbl_tw2864_common[0xf4] = 0xa0; | ||
300 | } | ||
301 | |||
302 | for (i = 0; i < 0xff; i++) { | 334 | for (i = 0; i < 0xff; i++) { |
303 | /* Skip read only registers */ | 335 | /* Skip read only registers */ |
304 | if (i >= 0xb8 && i <= 0xc1) | 336 | switch (i) { |
305 | continue; | 337 | case 0xb8 ... 0xc1: |
306 | if ((i & ~0x30) == 0x00 || | 338 | case 0xfd: |
307 | (i & ~0x30) == 0x0c || | ||
308 | (i & ~0x30) == 0x0d) | ||
309 | continue; | ||
310 | if (i == 0x74 || i == 0x77 || i == 0x78 || | ||
311 | i == 0x79 || i == 0x7a) | ||
312 | continue; | 339 | continue; |
313 | if (i == 0xfd) | 340 | } |
341 | switch (i & ~0x30) { | ||
342 | case 0x00: | ||
343 | case 0x0c: | ||
344 | case 0x0d: | ||
314 | continue; | 345 | continue; |
346 | } | ||
315 | 347 | ||
316 | tw_write_and_verify(solo_dev, dev_addr, i, | 348 | tw_write_and_verify(solo_dev, dev_addr, i, |
317 | tbl_tw2864_common[i]); | 349 | tbl_tw2864_common[i]); |
@@ -544,8 +576,8 @@ int solo_tw28_init(struct solo_dev *solo_dev) | |||
544 | int i; | 576 | int i; |
545 | u8 value; | 577 | u8 value; |
546 | 578 | ||
547 | /* Detect techwell chip type */ | 579 | /* Detect techwell chip type(s) */ |
548 | for (i = 0; i < TW_NUM_CHIP; i++) { | 580 | for (i = 0; i < solo_dev->nr_chans / 4; i++) { |
549 | value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, | 581 | value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, |
550 | TW_CHIP_OFFSET_ADDR(i), 0xFF); | 582 | TW_CHIP_OFFSET_ADDR(i), 0xFF); |
551 | 583 | ||
@@ -560,7 +592,8 @@ int solo_tw28_init(struct solo_dev *solo_dev) | |||
560 | break; | 592 | break; |
561 | default: | 593 | default: |
562 | value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, | 594 | value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, |
563 | TW_CHIP_OFFSET_ADDR(i), 0x59); | 595 | TW_CHIP_OFFSET_ADDR(i), |
596 | 0x59); | ||
564 | if ((value >> 3) == 0x04) { | 597 | if ((value >> 3) == 0x04) { |
565 | solo_dev->tw2815 |= 1 << i; | 598 | solo_dev->tw2815 |= 1 << i; |
566 | solo_dev->tw28_cnt++; | 599 | solo_dev->tw28_cnt++; |
@@ -568,8 +601,11 @@ int solo_tw28_init(struct solo_dev *solo_dev) | |||
568 | } | 601 | } |
569 | } | 602 | } |
570 | 603 | ||
571 | if (!solo_dev->tw28_cnt) | 604 | if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) { |
605 | dev_err(&solo_dev->pdev->dev, | ||
606 | "Could not initialize any techwell chips\n"); | ||
572 | return -EINVAL; | 607 | return -EINVAL; |
608 | } | ||
573 | 609 | ||
574 | saa7128_setup(solo_dev); | 610 | saa7128_setup(solo_dev); |
575 | 611 | ||
@@ -582,17 +618,6 @@ int solo_tw28_init(struct solo_dev *solo_dev) | |||
582 | tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); | 618 | tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); |
583 | } | 619 | } |
584 | 620 | ||
585 | dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:", | ||
586 | solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s"); | ||
587 | |||
588 | if (solo_dev->tw2865) | ||
589 | printk(" tw2865[%d]", hweight32(solo_dev->tw2865)); | ||
590 | if (solo_dev->tw2864) | ||
591 | printk(" tw2864[%d]", hweight32(solo_dev->tw2864)); | ||
592 | if (solo_dev->tw2815) | ||
593 | printk(" tw2815[%d]", hweight32(solo_dev->tw2815)); | ||
594 | printk("\n"); | ||
595 | |||
596 | return 0; | 621 | return 0; |
597 | } | 622 | } |
598 | 623 | ||
@@ -610,7 +635,7 @@ int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch) | |||
610 | chip_num = ch / 4; | 635 | chip_num = ch / 4; |
611 | ch %= 4; | 636 | ch %= 4; |
612 | 637 | ||
613 | val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR, | 638 | val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR, |
614 | TW_AV_STAT_ADDR) & 0x0f; | 639 | TW_AV_STAT_ADDR) & 0x0f; |
615 | 640 | ||
616 | return val & (1 << ch) ? 1 : 0; | 641 | return val & (1 << ch) ? 1 : 0; |
@@ -626,7 +651,7 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) | |||
626 | int i; | 651 | int i; |
627 | 652 | ||
628 | for (i = 0; i < solo_dev->tw28_cnt; i++) { | 653 | for (i = 0; i < solo_dev->tw28_cnt; i++) { |
629 | val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR, | 654 | val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR, |
630 | TW_AV_STAT_ADDR) & 0xf0) >> 4; | 655 | TW_AV_STAT_ADDR) & 0xf0) >> 4; |
631 | status |= val << (i * 4); | 656 | status |= val << (i * 4); |
632 | } | 657 | } |
@@ -635,7 +660,8 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) | |||
635 | } | 660 | } |
636 | #endif | 661 | #endif |
637 | 662 | ||
638 | int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val) | 663 | int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, |
664 | s32 val) | ||
639 | { | 665 | { |
640 | char sval; | 666 | char sval; |
641 | u8 chip_num; | 667 | u8 chip_num; |
@@ -676,6 +702,7 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val) | |||
676 | break; | 702 | break; |
677 | 703 | ||
678 | case V4L2_CID_SATURATION: | 704 | case V4L2_CID_SATURATION: |
705 | /* 286x chips have a U and V component for saturation */ | ||
679 | if (is_tw286x(solo_dev, chip_num)) { | 706 | if (is_tw286x(solo_dev, chip_num)) { |
680 | solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, | 707 | solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, |
681 | TW_CHIP_OFFSET_ADDR(chip_num), | 708 | TW_CHIP_OFFSET_ADDR(chip_num), |
diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h index a44a03afbd30..a03b429d44d4 100644 --- a/drivers/staging/media/solo6x10/tw28.h +++ b/drivers/staging/media/solo6x10/tw28.h | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -36,7 +41,7 @@ | |||
36 | #define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0)) | 41 | #define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0)) |
37 | 42 | ||
38 | /* tw286x */ | 43 | /* tw286x */ |
39 | #define TW286X_AV_STAT_ADDR 0xfd | 44 | #define TW286x_AV_STAT_ADDR 0xfd |
40 | #define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4)) | 45 | #define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4)) |
41 | #define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4)) | 46 | #define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4)) |
42 | #define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4)) | 47 | #define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4)) |
diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 310b126e1288..bb4d60a4c723 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -21,33 +26,100 @@ | |||
21 | #include <linux/module.h> | 26 | #include <linux/module.h> |
22 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
23 | #include <linux/freezer.h> | 28 | #include <linux/freezer.h> |
29 | |||
24 | #include <media/v4l2-ioctl.h> | 30 | #include <media/v4l2-ioctl.h> |
25 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
26 | #include <media/videobuf-dma-sg.h> | 32 | #include <media/videobuf-dma-sg.h> |
33 | |||
27 | #include "solo6x10.h" | 34 | #include "solo6x10.h" |
28 | #include "tw28.h" | 35 | #include "tw28.h" |
29 | #include "solo6x10-jpeg.h" | 36 | #include "solo6x10-jpeg.h" |
30 | 37 | ||
31 | #define MIN_VID_BUFFERS 4 | 38 | #define MIN_VID_BUFFERS 2 |
32 | #define FRAME_BUF_SIZE (128 * 1024) | 39 | #define FRAME_BUF_SIZE (196 * 1024) |
33 | #define MP4_QS 16 | 40 | #define MP4_QS 16 |
41 | #define DMA_ALIGN 4096 | ||
34 | 42 | ||
35 | static int solo_enc_thread(void *data); | 43 | enum solo_enc_types { |
36 | 44 | SOLO_ENC_TYPE_STD, | |
37 | extern unsigned video_nr; | 45 | SOLO_ENC_TYPE_EXT, |
46 | }; | ||
38 | 47 | ||
39 | struct solo_enc_fh { | 48 | struct solo_enc_fh { |
40 | struct solo_enc_dev *enc; | 49 | struct solo_enc_dev *enc; |
41 | u32 fmt; | 50 | u32 fmt; |
42 | u16 rd_idx; | ||
43 | u8 enc_on; | 51 | u8 enc_on; |
44 | enum solo_enc_types type; | 52 | enum solo_enc_types type; |
45 | struct videobuf_queue vidq; | 53 | struct videobuf_queue vidq; |
46 | struct list_head vidq_active; | 54 | struct list_head vidq_active; |
47 | struct task_struct *kthread; | 55 | int desc_count; |
48 | struct p2m_desc desc[SOLO_NR_P2M_DESC]; | 56 | int desc_nelts; |
57 | struct solo_p2m_desc *desc_items; | ||
58 | dma_addr_t desc_dma; | ||
59 | spinlock_t av_lock; | ||
60 | struct list_head list; | ||
61 | }; | ||
62 | |||
63 | struct solo_videobuf { | ||
64 | struct videobuf_buffer vb; | ||
65 | unsigned int flags; | ||
66 | }; | ||
67 | |||
68 | /* 6010 M4V */ | ||
69 | static unsigned char vop_6010_ntsc_d1[] = { | ||
70 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, | ||
71 | 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, | ||
72 | 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, | ||
73 | 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f, | ||
74 | }; | ||
75 | |||
76 | static unsigned char vop_6010_ntsc_cif[] = { | ||
77 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, | ||
78 | 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, | ||
79 | 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, | ||
80 | 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f, | ||
81 | }; | ||
82 | |||
83 | static unsigned char vop_6010_pal_d1[] = { | ||
84 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, | ||
85 | 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, | ||
86 | 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, | ||
87 | 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f, | ||
88 | }; | ||
89 | |||
90 | static unsigned char vop_6010_pal_cif[] = { | ||
91 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, | ||
92 | 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, | ||
93 | 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, | ||
94 | 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f, | ||
95 | }; | ||
96 | |||
97 | /* 6110 h.264 */ | ||
98 | static unsigned char vop_6110_ntsc_d1[] = { | ||
99 | 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, | ||
100 | 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00, | ||
101 | 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, | ||
102 | }; | ||
103 | |||
104 | static unsigned char vop_6110_ntsc_cif[] = { | ||
105 | 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, | ||
106 | 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00, | ||
107 | 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, | ||
108 | }; | ||
109 | |||
110 | static unsigned char vop_6110_pal_d1[] = { | ||
111 | 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, | ||
112 | 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00, | ||
113 | 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, | ||
114 | }; | ||
115 | |||
116 | static unsigned char vop_6110_pal_cif[] = { | ||
117 | 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, | ||
118 | 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00, | ||
119 | 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, | ||
49 | }; | 120 | }; |
50 | 121 | ||
122 | |||
51 | static const u32 solo_user_ctrls[] = { | 123 | static const u32 solo_user_ctrls[] = { |
52 | V4L2_CID_BRIGHTNESS, | 124 | V4L2_CID_BRIGHTNESS, |
53 | V4L2_CID_CONTRAST, | 125 | V4L2_CID_CONTRAST, |
@@ -82,79 +154,179 @@ static const u32 *solo_ctrl_classes[] = { | |||
82 | NULL | 154 | NULL |
83 | }; | 155 | }; |
84 | 156 | ||
157 | struct vop_header { | ||
158 | /* VE_STATUS0 */ | ||
159 | u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, | ||
160 | channel:5, source_fl:1, interlace:1, progressive:1; | ||
161 | |||
162 | /* VE_STATUS1 */ | ||
163 | u32 vsize:8, hsize:8, last_queue:4, nop0:8, scale:4; | ||
164 | |||
165 | /* VE_STATUS2 */ | ||
166 | u32 mpeg_off; | ||
167 | |||
168 | /* VE_STATUS3 */ | ||
169 | u32 jpeg_off; | ||
170 | |||
171 | /* VE_STATUS4 */ | ||
172 | u32 jpeg_size:20, interval:10, nop1:2; | ||
173 | |||
174 | /* VE_STATUS5/6 */ | ||
175 | u32 sec, usec; | ||
176 | |||
177 | /* VE_STATUS7/8/9 */ | ||
178 | u32 nop2[3]; | ||
179 | |||
180 | /* VE_STATUS10 */ | ||
181 | u32 mpeg_size_alt:20, nop3:12; | ||
182 | |||
183 | u32 end_nops[5]; | ||
184 | } __packed; | ||
185 | |||
186 | struct solo_enc_buf { | ||
187 | enum solo_enc_types type; | ||
188 | struct vop_header *vh; | ||
189 | int motion; | ||
190 | }; | ||
191 | |||
85 | static int solo_is_motion_on(struct solo_enc_dev *solo_enc) | 192 | static int solo_is_motion_on(struct solo_enc_dev *solo_enc) |
86 | { | 193 | { |
87 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 194 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
88 | u8 ch = solo_enc->ch; | ||
89 | 195 | ||
90 | if (solo_dev->motion_mask & (1 << ch)) | 196 | return (solo_dev->motion_mask >> solo_enc->ch) & 1; |
91 | return 1; | 197 | } |
92 | return 0; | 198 | |
199 | static int solo_motion_detected(struct solo_enc_dev *solo_enc) | ||
200 | { | ||
201 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
202 | unsigned long flags; | ||
203 | u32 ch_mask = 1 << solo_enc->ch; | ||
204 | int ret = 0; | ||
205 | |||
206 | spin_lock_irqsave(&solo_enc->motion_lock, flags); | ||
207 | if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) { | ||
208 | solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask); | ||
209 | ret = 1; | ||
210 | } | ||
211 | spin_unlock_irqrestore(&solo_enc->motion_lock, flags); | ||
212 | |||
213 | return ret; | ||
93 | } | 214 | } |
94 | 215 | ||
95 | static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) | 216 | static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) |
96 | { | 217 | { |
97 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 218 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
98 | u8 ch = solo_enc->ch; | 219 | u32 mask = 1 << solo_enc->ch; |
220 | unsigned long flags; | ||
99 | 221 | ||
100 | spin_lock(&solo_enc->lock); | 222 | spin_lock_irqsave(&solo_enc->motion_lock, flags); |
101 | 223 | ||
102 | if (on) | 224 | if (on) |
103 | solo_dev->motion_mask |= (1 << ch); | 225 | solo_dev->motion_mask |= mask; |
104 | else | 226 | else |
105 | solo_dev->motion_mask &= ~(1 << ch); | 227 | solo_dev->motion_mask &= ~mask; |
106 | 228 | ||
107 | /* Do this regardless of if we are turning on or off */ | 229 | solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask); |
108 | solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, | ||
109 | 1 << solo_enc->ch); | ||
110 | solo_enc->motion_detected = 0; | ||
111 | 230 | ||
112 | solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, | 231 | solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, |
113 | SOLO_VI_MOTION_EN(solo_dev->motion_mask) | | 232 | SOLO_VI_MOTION_EN(solo_dev->motion_mask) | |
114 | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); | 233 | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); |
115 | 234 | ||
116 | if (solo_dev->motion_mask) | 235 | spin_unlock_irqrestore(&solo_enc->motion_lock, flags); |
117 | solo_irq_on(solo_dev, SOLO_IRQ_MOTION); | ||
118 | else | ||
119 | solo_irq_off(solo_dev, SOLO_IRQ_MOTION); | ||
120 | |||
121 | spin_unlock(&solo_enc->lock); | ||
122 | } | 236 | } |
123 | 237 | ||
124 | /* Should be called with solo_enc->lock held */ | 238 | /* MUST be called with solo_enc->enable_lock held */ |
125 | static void solo_update_mode(struct solo_enc_dev *solo_enc) | 239 | static void solo_update_mode(struct solo_enc_dev *solo_enc) |
126 | { | 240 | { |
127 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 241 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
128 | 242 | int vop_len; | |
129 | assert_spin_locked(&solo_enc->lock); | 243 | unsigned char *vop; |
130 | 244 | ||
131 | solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; | 245 | solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; |
132 | solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); | 246 | solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); |
133 | 247 | ||
134 | switch (solo_enc->mode) { | 248 | if (solo_enc->mode == SOLO_ENC_MODE_CIF) { |
135 | case SOLO_ENC_MODE_CIF: | ||
136 | solo_enc->width = solo_dev->video_hsize >> 1; | 249 | solo_enc->width = solo_dev->video_hsize >> 1; |
137 | solo_enc->height = solo_dev->video_vsize; | 250 | solo_enc->height = solo_dev->video_vsize; |
138 | break; | 251 | if (solo_dev->type == SOLO_DEV_6110) { |
139 | case SOLO_ENC_MODE_D1: | 252 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { |
253 | vop = vop_6110_ntsc_cif; | ||
254 | vop_len = sizeof(vop_6110_ntsc_cif); | ||
255 | } else { | ||
256 | vop = vop_6110_pal_cif; | ||
257 | vop_len = sizeof(vop_6110_pal_cif); | ||
258 | } | ||
259 | } else { | ||
260 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { | ||
261 | vop = vop_6010_ntsc_cif; | ||
262 | vop_len = sizeof(vop_6010_ntsc_cif); | ||
263 | } else { | ||
264 | vop = vop_6010_pal_cif; | ||
265 | vop_len = sizeof(vop_6010_pal_cif); | ||
266 | } | ||
267 | } | ||
268 | } else { | ||
140 | solo_enc->width = solo_dev->video_hsize; | 269 | solo_enc->width = solo_dev->video_hsize; |
141 | solo_enc->height = solo_dev->video_vsize << 1; | 270 | solo_enc->height = solo_dev->video_vsize << 1; |
142 | solo_enc->bw_weight <<= 2; | 271 | solo_enc->bw_weight <<= 2; |
143 | break; | 272 | if (solo_dev->type == SOLO_DEV_6110) { |
144 | default: | 273 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { |
145 | WARN(1, "mode is unknown\n"); | 274 | vop = vop_6110_ntsc_d1; |
275 | vop_len = sizeof(vop_6110_ntsc_d1); | ||
276 | } else { | ||
277 | vop = vop_6110_pal_d1; | ||
278 | vop_len = sizeof(vop_6110_pal_d1); | ||
279 | } | ||
280 | } else { | ||
281 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { | ||
282 | vop = vop_6010_ntsc_d1; | ||
283 | vop_len = sizeof(vop_6010_ntsc_d1); | ||
284 | } else { | ||
285 | vop = vop_6010_pal_d1; | ||
286 | vop_len = sizeof(vop_6010_pal_d1); | ||
287 | } | ||
288 | } | ||
146 | } | 289 | } |
290 | |||
291 | memcpy(solo_enc->vop, vop, vop_len); | ||
292 | |||
293 | /* Some fixups for 6010/M4V */ | ||
294 | if (solo_dev->type == SOLO_DEV_6010) { | ||
295 | u16 fps = solo_dev->fps * 1000; | ||
296 | u16 interval = solo_enc->interval * 1000; | ||
297 | |||
298 | vop = solo_enc->vop; | ||
299 | |||
300 | /* Frame rate and interval */ | ||
301 | vop[22] = fps >> 4; | ||
302 | vop[23] = ((fps << 4) & 0xf0) | 0x0c | ||
303 | | ((interval >> 13) & 0x3); | ||
304 | vop[24] = (interval >> 5) & 0xff; | ||
305 | vop[25] = ((interval << 3) & 0xf8) | 0x04; | ||
306 | } | ||
307 | |||
308 | solo_enc->vop_len = vop_len; | ||
309 | |||
310 | /* Now handle the jpeg header */ | ||
311 | vop = solo_enc->jpeg_header; | ||
312 | vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8); | ||
313 | vop[SOF0_START + 6] = 0xff & solo_enc->height; | ||
314 | vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8); | ||
315 | vop[SOF0_START + 8] = 0xff & solo_enc->width; | ||
316 | |||
317 | memcpy(vop + DQT_START, | ||
318 | jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN); | ||
147 | } | 319 | } |
148 | 320 | ||
149 | /* Should be called with solo_enc->lock held */ | 321 | /* MUST be called with solo_enc->enable_lock held */ |
150 | static int solo_enc_on(struct solo_enc_fh *fh) | 322 | static int __solo_enc_on(struct solo_enc_fh *fh) |
151 | { | 323 | { |
152 | struct solo_enc_dev *solo_enc = fh->enc; | 324 | struct solo_enc_dev *solo_enc = fh->enc; |
153 | u8 ch = solo_enc->ch; | 325 | u8 ch = solo_enc->ch; |
154 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 326 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
155 | u8 interval; | 327 | u8 interval; |
156 | 328 | ||
157 | assert_spin_locked(&solo_enc->lock); | 329 | BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); |
158 | 330 | ||
159 | if (fh->enc_on) | 331 | if (fh->enc_on) |
160 | return 0; | 332 | return 0; |
@@ -170,13 +342,20 @@ static int solo_enc_on(struct solo_enc_fh *fh) | |||
170 | } | 342 | } |
171 | 343 | ||
172 | fh->enc_on = 1; | 344 | fh->enc_on = 1; |
173 | fh->rd_idx = solo_enc->solo_dev->enc_wr_idx; | 345 | list_add(&fh->list, &solo_enc->listeners); |
174 | 346 | ||
175 | if (fh->type == SOLO_ENC_TYPE_EXT) | 347 | if (fh->type == SOLO_ENC_TYPE_EXT) |
176 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); | 348 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); |
177 | 349 | ||
178 | if (atomic_inc_return(&solo_enc->readers) > 1) | 350 | /* Reset the encoder if we are the first mpeg reader, else only reset |
351 | * on the first mjpeg reader. */ | ||
352 | if (fh->fmt == V4L2_PIX_FMT_MPEG) { | ||
353 | atomic_inc(&solo_enc->readers); | ||
354 | if (atomic_inc_return(&solo_enc->mpeg_readers) > 1) | ||
355 | return 0; | ||
356 | } else if (atomic_inc_return(&solo_enc->readers) > 1) { | ||
179 | return 0; | 357 | return 0; |
358 | } | ||
180 | 359 | ||
181 | /* Disable all encoding for this channel */ | 360 | /* Disable all encoding for this channel */ |
182 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); | 361 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); |
@@ -203,701 +382,414 @@ static int solo_enc_on(struct solo_enc_fh *fh) | |||
203 | /* Enables the standard encoder */ | 382 | /* Enables the standard encoder */ |
204 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode); | 383 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode); |
205 | 384 | ||
206 | /* Settle down Beavis... */ | ||
207 | mdelay(10); | ||
208 | |||
209 | return 0; | 385 | return 0; |
210 | } | 386 | } |
211 | 387 | ||
212 | static void solo_enc_off(struct solo_enc_fh *fh) | 388 | static int solo_enc_on(struct solo_enc_fh *fh) |
213 | { | 389 | { |
214 | struct solo_enc_dev *solo_enc = fh->enc; | 390 | struct solo_enc_dev *solo_enc = fh->enc; |
215 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 391 | int ret; |
216 | |||
217 | if (!fh->enc_on) | ||
218 | return; | ||
219 | |||
220 | if (fh->kthread) { | ||
221 | kthread_stop(fh->kthread); | ||
222 | fh->kthread = NULL; | ||
223 | } | ||
224 | |||
225 | solo_dev->enc_bw_remain += solo_enc->bw_weight; | ||
226 | fh->enc_on = 0; | ||
227 | 392 | ||
228 | if (atomic_dec_return(&solo_enc->readers) > 0) | 393 | mutex_lock(&solo_enc->enable_lock); |
229 | return; | 394 | ret = __solo_enc_on(fh); |
395 | mutex_unlock(&solo_enc->enable_lock); | ||
230 | 396 | ||
231 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); | 397 | return ret; |
232 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); | ||
233 | } | 398 | } |
234 | 399 | ||
235 | static int solo_start_fh_thread(struct solo_enc_fh *fh) | 400 | static void __solo_enc_off(struct solo_enc_fh *fh) |
236 | { | 401 | { |
237 | struct solo_enc_dev *solo_enc = fh->enc; | 402 | struct solo_enc_dev *solo_enc = fh->enc; |
403 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
238 | 404 | ||
239 | fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc"); | 405 | BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); |
240 | |||
241 | /* Oops, we had a problem */ | ||
242 | if (IS_ERR(fh->kthread)) { | ||
243 | spin_lock(&solo_enc->lock); | ||
244 | solo_enc_off(fh); | ||
245 | spin_unlock(&solo_enc->lock); | ||
246 | |||
247 | return PTR_ERR(fh->kthread); | ||
248 | } | ||
249 | 406 | ||
250 | return 0; | 407 | if (!fh->enc_on) |
251 | } | 408 | return; |
252 | 409 | ||
253 | static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch) | 410 | list_del(&fh->list); |
254 | { | 411 | fh->enc_on = 0; |
255 | BUG_ON(ch >= solo_dev->nr_chans); | ||
256 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1); | ||
257 | solo_dev->v4l2_enc[ch]->reset_gop = 1; | ||
258 | } | ||
259 | 412 | ||
260 | static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop) | 413 | if (fh->fmt == V4L2_PIX_FMT_MPEG) |
261 | { | 414 | atomic_dec(&solo_enc->mpeg_readers); |
262 | BUG_ON(ch >= solo_dev->nr_chans); | ||
263 | if (!solo_dev->v4l2_enc[ch]->reset_gop) | ||
264 | return 0; | ||
265 | if (vop) | ||
266 | return 1; | ||
267 | solo_dev->v4l2_enc[ch]->reset_gop = 0; | ||
268 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), | ||
269 | solo_dev->v4l2_enc[ch]->gop); | ||
270 | return 0; | ||
271 | } | ||
272 | 415 | ||
273 | static void enc_write_sg(struct scatterlist *sglist, void *buf, int size) | 416 | if (atomic_dec_return(&solo_enc->readers) > 0) |
274 | { | 417 | return; |
275 | struct scatterlist *sg; | ||
276 | u8 *src = buf; | ||
277 | 418 | ||
278 | for (sg = sglist; sg && size > 0; sg = sg_next(sg)) { | 419 | solo_dev->enc_bw_remain += solo_enc->bw_weight; |
279 | u8 *p = sg_virt(sg); | ||
280 | size_t len = sg_dma_len(sg); | ||
281 | int i; | ||
282 | 420 | ||
283 | for (i = 0; i < len && size; i++) | 421 | solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); |
284 | p[i] = *(src++); | 422 | solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); |
285 | } | ||
286 | } | 423 | } |
287 | 424 | ||
288 | static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev, | 425 | static void solo_enc_off(struct solo_enc_fh *fh) |
289 | struct p2m_desc *desc, | ||
290 | struct scatterlist *sglist, int skip, | ||
291 | unsigned int off, unsigned int size) | ||
292 | { | 426 | { |
293 | int ret; | 427 | struct solo_enc_dev *solo_enc = fh->enc; |
294 | |||
295 | if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) | ||
296 | return -EINVAL; | ||
297 | |||
298 | if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { | ||
299 | return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, | ||
300 | desc, 0, sglist, skip, | ||
301 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); | ||
302 | } | ||
303 | |||
304 | /* Buffer wrap */ | ||
305 | ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, | ||
306 | sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off, | ||
307 | SOLO_MP4E_EXT_SIZE(solo_dev) - off); | ||
308 | |||
309 | ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, | ||
310 | sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off, | ||
311 | SOLO_MP4E_EXT_ADDR(solo_dev), | ||
312 | size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); | ||
313 | 428 | ||
314 | return ret; | 429 | mutex_lock(&solo_enc->enable_lock); |
430 | __solo_enc_off(fh); | ||
431 | mutex_unlock(&solo_enc->enable_lock); | ||
315 | } | 432 | } |
316 | 433 | ||
317 | static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev, | 434 | static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, |
318 | dma_addr_t buf, unsigned int off, | 435 | unsigned int off, unsigned int size) |
319 | unsigned int size) | ||
320 | { | 436 | { |
321 | int ret; | 437 | int ret; |
322 | 438 | ||
323 | if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) | 439 | if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) |
324 | return -EINVAL; | 440 | return -EINVAL; |
325 | 441 | ||
442 | /* Single shot */ | ||
326 | if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { | 443 | if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { |
327 | return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, | 444 | return solo_p2m_dma_t(solo_dev, 0, dma, |
328 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); | 445 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, size, |
446 | 0, 0); | ||
329 | } | 447 | } |
330 | 448 | ||
331 | /* Buffer wrap */ | 449 | /* Buffer wrap */ |
332 | ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, | 450 | ret = solo_p2m_dma_t(solo_dev, 0, dma, |
333 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, | 451 | SOLO_MP4E_EXT_ADDR(solo_dev) + off, |
334 | SOLO_MP4E_EXT_SIZE(solo_dev) - off); | 452 | SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0); |
335 | |||
336 | ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, | ||
337 | buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off, | ||
338 | SOLO_MP4E_EXT_ADDR(solo_dev), | ||
339 | size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); | ||
340 | |||
341 | return ret; | ||
342 | } | ||
343 | 453 | ||
344 | static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf, | 454 | if (!ret) { |
345 | unsigned int off, unsigned int size) | 455 | ret = solo_p2m_dma_t(solo_dev, 0, |
346 | { | 456 | dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off, |
347 | int ret; | 457 | SOLO_MP4E_EXT_ADDR(solo_dev), |
348 | 458 | size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0); | |
349 | dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size, | 459 | } |
350 | PCI_DMA_FROMDEVICE); | ||
351 | ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size); | ||
352 | pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE); | ||
353 | 460 | ||
354 | return ret; | 461 | return ret; |
355 | } | 462 | } |
356 | 463 | ||
357 | static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev, | 464 | /* Build a descriptor queue out of an SG list and send it to the P2M for |
358 | struct p2m_desc *desc, | 465 | * processing. */ |
359 | struct scatterlist *sglist, int skip, | 466 | static int solo_send_desc(struct solo_enc_fh *fh, int skip, |
360 | unsigned int off, unsigned int size) | 467 | struct videobuf_dmabuf *vbuf, int off, int size, |
468 | unsigned int base, unsigned int base_size) | ||
361 | { | 469 | { |
470 | struct solo_dev *solo_dev = fh->enc->solo_dev; | ||
471 | struct scatterlist *sg; | ||
472 | int i; | ||
362 | int ret; | 473 | int ret; |
363 | 474 | ||
364 | if (off > SOLO_JPEG_EXT_SIZE(solo_dev)) | 475 | if (WARN_ON_ONCE(size > FRAME_BUF_SIZE)) |
365 | return -EINVAL; | 476 | return -EINVAL; |
366 | 477 | ||
367 | if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) { | 478 | fh->desc_count = 1; |
368 | return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, | 479 | |
369 | desc, 0, sglist, skip, | 480 | for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { |
370 | SOLO_JPEG_EXT_ADDR(solo_dev) + off, size); | 481 | struct solo_p2m_desc *desc; |
371 | } | 482 | dma_addr_t dma; |
372 | 483 | int len; | |
373 | /* Buffer wrap */ | 484 | int left = base_size - off; |
374 | ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, | 485 | |
375 | sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off, | 486 | desc = &fh->desc_items[fh->desc_count++]; |
376 | SOLO_JPEG_EXT_SIZE(solo_dev) - off); | 487 | dma = sg_dma_address(sg); |
488 | len = sg_dma_len(sg); | ||
489 | |||
490 | /* We assume this is smaller than the scatter size */ | ||
491 | BUG_ON(skip >= len); | ||
492 | if (skip) { | ||
493 | len -= skip; | ||
494 | dma += skip; | ||
495 | size -= skip; | ||
496 | skip = 0; | ||
497 | } | ||
377 | 498 | ||
378 | ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, | 499 | len = min(len, size); |
379 | sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off, | ||
380 | SOLO_JPEG_EXT_ADDR(solo_dev), | ||
381 | size + off - SOLO_JPEG_EXT_SIZE(solo_dev)); | ||
382 | 500 | ||
383 | return ret; | 501 | if (len <= left) { |
384 | } | 502 | /* Single descriptor */ |
503 | solo_p2m_fill_desc(desc, 0, dma, base + off, | ||
504 | len, 0, 0); | ||
505 | } else { | ||
506 | /* Buffer wrap */ | ||
507 | /* XXX: Do these as separate DMA requests, to avoid | ||
508 | timeout errors triggered by awkwardly sized | ||
509 | descriptors. See | ||
510 | <https://github.com/bluecherrydvr/solo6x10/issues/8> | ||
511 | */ | ||
512 | ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off, | ||
513 | left, 0, 0); | ||
514 | if (ret) | ||
515 | return ret; | ||
516 | |||
517 | ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base, | ||
518 | len - left, 0, 0); | ||
519 | if (ret) | ||
520 | return ret; | ||
521 | |||
522 | fh->desc_count--; | ||
523 | } | ||
385 | 524 | ||
386 | /* Returns true of __chk is within the first __range bytes of __off */ | 525 | size -= len; |
387 | #define OFF_IN_RANGE(__off, __range, __chk) \ | 526 | if (size <= 0) |
388 | ((__off <= __chk) && ((__off + __range) >= __chk)) | 527 | break; |
389 | 528 | ||
390 | static void solo_jpeg_header(struct solo_enc_dev *solo_enc, | 529 | off += len; |
391 | struct videobuf_dmabuf *vbuf) | 530 | if (off >= base_size) |
392 | { | 531 | off -= base_size; |
393 | struct scatterlist *sg; | 532 | |
394 | void *src = jpeg_header; | 533 | /* Because we may use two descriptors per loop */ |
395 | size_t copied = 0; | 534 | if (fh->desc_count >= (fh->desc_nelts - 1)) { |
396 | size_t to_copy = sizeof(jpeg_header); | 535 | ret = solo_p2m_dma_desc(solo_dev, fh->desc_items, |
397 | 536 | fh->desc_dma, | |
398 | for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) { | 537 | fh->desc_count - 1); |
399 | size_t this_copy = min(sg_dma_len(sg), | 538 | if (ret) |
400 | (unsigned int)(to_copy - copied)); | 539 | return ret; |
401 | u8 *p = sg_virt(sg); | 540 | fh->desc_count = 1; |
402 | 541 | } | |
403 | memcpy(p, src + copied, this_copy); | ||
404 | |||
405 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5)) | ||
406 | p[(SOF0_START + 5) - copied] = | ||
407 | 0xff & (solo_enc->height >> 8); | ||
408 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6)) | ||
409 | p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height; | ||
410 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7)) | ||
411 | p[(SOF0_START + 7) - copied] = | ||
412 | 0xff & (solo_enc->width >> 8); | ||
413 | if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8)) | ||
414 | p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width; | ||
415 | |||
416 | copied += this_copy; | ||
417 | } | 542 | } |
418 | } | ||
419 | |||
420 | static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, | ||
421 | struct videobuf_buffer *vb, | ||
422 | struct videobuf_dmabuf *vbuf) | ||
423 | { | ||
424 | struct solo_dev *solo_dev = fh->enc->solo_dev; | ||
425 | int size = enc_buf->jpeg_size; | ||
426 | |||
427 | /* Copy the header first (direct write) */ | ||
428 | solo_jpeg_header(fh->enc, vbuf); | ||
429 | |||
430 | vb->size = size + sizeof(jpeg_header); | ||
431 | |||
432 | /* Grab the jpeg frame */ | ||
433 | return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, | ||
434 | sizeof(jpeg_header), | ||
435 | enc_buf->jpeg_off, size); | ||
436 | } | ||
437 | |||
438 | static inline int vop_interlaced(__le32 *vh) | ||
439 | { | ||
440 | return (__le32_to_cpu(vh[0]) >> 30) & 1; | ||
441 | } | ||
442 | 543 | ||
443 | static inline u32 vop_size(__le32 *vh) | 544 | if (fh->desc_count <= 1) |
444 | { | 545 | return 0; |
445 | return __le32_to_cpu(vh[0]) & 0xFFFFF; | ||
446 | } | ||
447 | |||
448 | static inline u8 vop_hsize(__le32 *vh) | ||
449 | { | ||
450 | return (__le32_to_cpu(vh[1]) >> 8) & 0xFF; | ||
451 | } | ||
452 | |||
453 | static inline u8 vop_vsize(__le32 *vh) | ||
454 | { | ||
455 | return __le32_to_cpu(vh[1]) & 0xFF; | ||
456 | } | ||
457 | |||
458 | /* must be called with *bits % 8 = 0 */ | ||
459 | static void write_bytes(u8 **out, unsigned *bits, const u8 *src, unsigned count) | ||
460 | { | ||
461 | memcpy(*out, src, count); | ||
462 | *out += count; | ||
463 | *bits += count * 8; | ||
464 | } | ||
465 | |||
466 | static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count) | ||
467 | { | ||
468 | |||
469 | value <<= 32 - count; // shift to the right | ||
470 | 546 | ||
471 | while (count--) { | 547 | return solo_p2m_dma_desc(solo_dev, fh->desc_items, fh->desc_dma, |
472 | **out <<= 1; | 548 | fh->desc_count - 1); |
473 | **out |= !!(value & (1 << 31)); /* MSB */ | ||
474 | value <<= 1; | ||
475 | if (++(*bits) % 8 == 0) | ||
476 | (*out)++; | ||
477 | } | ||
478 | } | 549 | } |
479 | 550 | ||
480 | static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */ | 551 | static int solo_fill_jpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, |
552 | struct videobuf_dmabuf *vbuf, struct vop_header *vh) | ||
481 | { | 553 | { |
482 | uint32_t max = 0, cnt = 0; | 554 | struct solo_enc_dev *solo_enc = fh->enc; |
555 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
556 | struct solo_videobuf *svb = (struct solo_videobuf *)vb; | ||
557 | int frame_size; | ||
483 | 558 | ||
484 | while (value > max) { | 559 | svb->flags |= V4L2_BUF_FLAG_KEYFRAME; |
485 | max = (max + 2) * 2 - 2; | ||
486 | cnt++; | ||
487 | } | ||
488 | write_bits(out, bits, 1, cnt + 1); | ||
489 | write_bits(out, bits, ~(max - value), cnt); | ||
490 | } | ||
491 | 560 | ||
492 | static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */ | 561 | if (vb->bsize < (vh->jpeg_size + solo_enc->jpeg_len)) |
493 | { | 562 | return -EIO; |
494 | if (value <= 0) | ||
495 | write_ue(out, bits, -value * 2); | ||
496 | else | ||
497 | write_ue(out, bits, value * 2 - 1); | ||
498 | } | ||
499 | 563 | ||
500 | static void write_mpeg4_end(u8 **out, unsigned *bits) | 564 | vb->width = solo_enc->width; |
501 | { | 565 | vb->height = solo_enc->height; |
502 | write_bits(out, bits, 0, 1); | 566 | vb->size = vh->jpeg_size + solo_enc->jpeg_len; |
503 | /* align on 32-bit boundary */ | ||
504 | if (*bits % 32) | ||
505 | write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32); | ||
506 | } | ||
507 | 567 | ||
508 | static void write_h264_end(u8 **out, unsigned *bits, int align) | 568 | sg_copy_from_buffer(vbuf->sglist, vbuf->sglen, |
509 | { | 569 | solo_enc->jpeg_header, |
510 | write_bits(out, bits, 1, 1); | 570 | solo_enc->jpeg_len); |
511 | while ((*bits) % 8) | ||
512 | write_bits(out, bits, 0, 1); | ||
513 | if (align) | ||
514 | while ((*bits) % 32) | ||
515 | write_bits(out, bits, 0, 1); | ||
516 | } | ||
517 | 571 | ||
518 | static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev, | 572 | frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1)) |
519 | __le32 *vh, unsigned fps, unsigned interval) | 573 | & ~(DMA_ALIGN - 1); |
520 | { | ||
521 | static const u8 hdr[] = { | ||
522 | 0, 0, 1, 0x00 /* video_object_start_code */, | ||
523 | 0, 0, 1, 0x20 /* video_object_layer_start_code */ | ||
524 | }; | ||
525 | unsigned bits = 0; | ||
526 | unsigned width = vop_hsize(vh) << 4; | ||
527 | unsigned height = vop_vsize(vh) << 4; | ||
528 | unsigned interlaced = vop_interlaced(vh); | ||
529 | |||
530 | write_bytes(out, &bits, hdr, sizeof(hdr)); | ||
531 | write_bits(out, &bits, 0, 1); /* random_accessible_vol */ | ||
532 | write_bits(out, &bits, 0x04, 8); /* video_object_type_indication: main */ | ||
533 | write_bits(out, &bits, 1, 1); /* is_object_layer_identifier */ | ||
534 | write_bits(out, &bits, 2, 4); /* video_object_layer_verid: table V2-39 */ | ||
535 | write_bits(out, &bits, 0, 3); /* video_object_layer_priority */ | ||
536 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) | ||
537 | write_bits(out, &bits, 3, 4); /* aspect_ratio_info, assuming 4:3 */ | ||
538 | else | ||
539 | write_bits(out, &bits, 2, 4); | ||
540 | write_bits(out, &bits, 1, 1); /* vol_control_parameters */ | ||
541 | write_bits(out, &bits, 1, 2); /* chroma_format: 4:2:0 */ | ||
542 | write_bits(out, &bits, 1, 1); /* low_delay */ | ||
543 | write_bits(out, &bits, 0, 1); /* vbv_parameters */ | ||
544 | write_bits(out, &bits, 0, 2); /* video_object_layer_shape: rectangular */ | ||
545 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
546 | write_bits(out, &bits, fps, 16); /* vop_time_increment_resolution */ | ||
547 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
548 | write_bits(out, &bits, 1, 1); /* fixed_vop_rate */ | ||
549 | write_bits(out, &bits, interval, 15); /* fixed_vop_time_increment */ | ||
550 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
551 | write_bits(out, &bits, width, 13); /* video_object_layer_width */ | ||
552 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
553 | write_bits(out, &bits, height, 13); /* video_object_layer_height */ | ||
554 | write_bits(out, &bits, 1, 1); /* marker_bit */ | ||
555 | write_bits(out, &bits, interlaced, 1); /* interlaced */ | ||
556 | write_bits(out, &bits, 1, 1); /* obmc_disable */ | ||
557 | write_bits(out, &bits, 0, 2); /* sprite_enable */ | ||
558 | write_bits(out, &bits, 0, 1); /* not_8_bit */ | ||
559 | write_bits(out, &bits, 1, 0); /* quant_type */ | ||
560 | write_bits(out, &bits, 0, 1); /* load_intra_quant_mat */ | ||
561 | write_bits(out, &bits, 0, 1); /* load_nonintra_quant_mat */ | ||
562 | write_bits(out, &bits, 0, 1); /* quarter_sample */ | ||
563 | write_bits(out, &bits, 1, 1); /* complexity_estimation_disable */ | ||
564 | write_bits(out, &bits, 1, 1); /* resync_marker_disable */ | ||
565 | write_bits(out, &bits, 0, 1); /* data_partitioned */ | ||
566 | write_bits(out, &bits, 0, 1); /* newpred_enable */ | ||
567 | write_bits(out, &bits, 0, 1); /* reduced_resolution_vop_enable */ | ||
568 | write_bits(out, &bits, 0, 1); /* scalability */ | ||
569 | write_mpeg4_end(out, &bits); | ||
570 | } | ||
571 | 574 | ||
572 | static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh) | 575 | return solo_send_desc(fh, solo_enc->jpeg_len, vbuf, vh->jpeg_off, |
573 | { | 576 | frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), |
574 | static const u8 sps[] = { | 577 | SOLO_JPEG_EXT_SIZE(solo_dev)); |
575 | 0, 0, 0, 1 /* start code */, 0x67, 66 /* profile_idc */, | ||
576 | 0 /* constraints */, 30 /* level_idc */ | ||
577 | }; | ||
578 | static const u8 pps[] = { | ||
579 | 0, 0, 0, 1 /* start code */, 0x68 | ||
580 | }; | ||
581 | |||
582 | unsigned bits = 0; | ||
583 | unsigned mbs_w = vop_hsize(vh); | ||
584 | unsigned mbs_h = vop_vsize(vh); | ||
585 | |||
586 | write_bytes(out, &bits, sps, sizeof(sps)); | ||
587 | write_ue(out, &bits, 0); /* seq_parameter_set_id */ | ||
588 | write_ue(out, &bits, 5); /* log2_max_frame_num_minus4 */ | ||
589 | write_ue(out, &bits, 0); /* pic_order_cnt_type */ | ||
590 | write_ue(out, &bits, 6); /* log2_max_pic_order_cnt_lsb_minus4 */ | ||
591 | write_ue(out, &bits, 1); /* max_num_ref_frames */ | ||
592 | write_bits(out, &bits, 0, 1); /* gaps_in_frame_num_value_allowed_flag */ | ||
593 | write_ue(out, &bits, mbs_w - 1); /* pic_width_in_mbs_minus1 */ | ||
594 | write_ue(out, &bits, mbs_h - 1); /* pic_height_in_map_units_minus1 */ | ||
595 | write_bits(out, &bits, 1, 1); /* frame_mbs_only_flag */ | ||
596 | write_bits(out, &bits, 1, 1); /* direct_8x8_frame_field_flag */ | ||
597 | write_bits(out, &bits, 0, 1); /* frame_cropping_flag */ | ||
598 | write_bits(out, &bits, 0, 1); /* vui_parameters_present_flag */ | ||
599 | write_h264_end(out, &bits, 0); | ||
600 | |||
601 | write_bytes(out, &bits, pps, sizeof(pps)); | ||
602 | write_ue(out, &bits, 0); /* pic_parameter_set_id */ | ||
603 | write_ue(out, &bits, 0); /* seq_parameter_set_id */ | ||
604 | write_bits(out, &bits, 0, 1); /* entropy_coding_mode_flag */ | ||
605 | write_bits(out, &bits, 0, 1); /* bottom_field_pic_order_in_frame_present_flag */ | ||
606 | write_ue(out, &bits, 0); /* num_slice_groups_minus1 */ | ||
607 | write_ue(out, &bits, 0); /* num_ref_idx_l0_default_active_minus1 */ | ||
608 | write_ue(out, &bits, 0); /* num_ref_idx_l1_default_active_minus1 */ | ||
609 | write_bits(out, &bits, 0, 1); /* weighted_pred_flag */ | ||
610 | write_bits(out, &bits, 0, 2); /* weighted_bipred_idc */ | ||
611 | write_se(out, &bits, 0); /* pic_init_qp_minus26 */ | ||
612 | write_se(out, &bits, 0); /* pic_init_qs_minus26 */ | ||
613 | write_se(out, &bits, 2); /* chroma_qp_index_offset */ | ||
614 | write_bits(out, &bits, 0, 1); /* deblocking_filter_control_present_flag */ | ||
615 | write_bits(out, &bits, 1, 1); /* constrained_intra_pred_flag */ | ||
616 | write_bits(out, &bits, 0, 1); /* redundant_pic_cnt_present_flag */ | ||
617 | write_h264_end(out, &bits, 1); | ||
618 | } | 578 | } |
619 | 579 | ||
620 | static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, | 580 | static int solo_fill_mpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, |
621 | struct videobuf_buffer *vb, | 581 | struct videobuf_dmabuf *vbuf, struct vop_header *vh) |
622 | struct videobuf_dmabuf *vbuf) | ||
623 | { | 582 | { |
624 | struct solo_enc_dev *solo_enc = fh->enc; | 583 | struct solo_enc_dev *solo_enc = fh->enc; |
625 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 584 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
626 | 585 | struct solo_videobuf *svb = (struct solo_videobuf *)vb; | |
627 | #define VH_WORDS 16 | 586 | int frame_off, frame_size; |
628 | #define MAX_VOL_HEADER_LENGTH 64 | ||
629 | |||
630 | __le32 vh[VH_WORDS]; | ||
631 | int ret; | ||
632 | int frame_size, frame_off; | ||
633 | int skip = 0; | 587 | int skip = 0; |
634 | 588 | ||
635 | if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh))) | 589 | if (vb->bsize < vh->mpeg_size) |
636 | return -EINVAL; | 590 | return -EIO; |
637 | |||
638 | /* First get the hardware vop header (not real mpeg) */ | ||
639 | ret = enc_get_mpeg_dma(solo_dev, vh, enc_buf->off, sizeof(vh)); | ||
640 | if (WARN_ON_ONCE(ret)) | ||
641 | return ret; | ||
642 | 591 | ||
643 | if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size)) | 592 | vb->width = vh->hsize << 4; |
644 | return -EINVAL; | 593 | vb->height = vh->vsize << 4; |
594 | vb->size = vh->mpeg_size; | ||
645 | 595 | ||
646 | vb->width = vop_hsize(vh) << 4; | 596 | /* If this is a key frame, add extra header */ |
647 | vb->height = vop_vsize(vh) << 4; | 597 | if (!vh->vop_type) { |
648 | vb->size = vop_size(vh); | 598 | sg_copy_from_buffer(vbuf->sglist, vbuf->sglen, |
599 | solo_enc->vop, | ||
600 | solo_enc->vop_len); | ||
649 | 601 | ||
650 | /* If this is a key frame, add extra m4v header */ | 602 | skip = solo_enc->vop_len; |
651 | if (!enc_buf->vop) { | 603 | vb->size += solo_enc->vop_len; |
652 | u8 header[MAX_VOL_HEADER_LENGTH], *out = header; | ||
653 | 604 | ||
654 | if (solo_dev->flags & FLAGS_6110) | 605 | svb->flags |= V4L2_BUF_FLAG_KEYFRAME; |
655 | h264_write_vol(&out, solo_dev, vh); | 606 | } else { |
656 | else | 607 | svb->flags |= V4L2_BUF_FLAG_PFRAME; |
657 | mpeg4_write_vol(&out, solo_dev, vh, | ||
658 | solo_dev->fps * 1000, | ||
659 | solo_enc->interval * 1000); | ||
660 | skip = out - header; | ||
661 | enc_write_sg(vbuf->sglist, header, skip); | ||
662 | /* Adjust the dma buffer past this header */ | ||
663 | vb->size += skip; | ||
664 | } | 608 | } |
665 | 609 | ||
666 | /* Now get the actual mpeg payload */ | 610 | /* Now get the actual mpeg payload */ |
667 | frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev); | 611 | frame_off = (vh->mpeg_off + sizeof(*vh)) |
668 | frame_size = enc_buf->size - sizeof(vh); | 612 | % SOLO_MP4E_EXT_SIZE(solo_dev); |
669 | 613 | frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1)) | |
670 | ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, | 614 | & ~(DMA_ALIGN - 1); |
671 | skip, frame_off, frame_size); | ||
672 | WARN_ON_ONCE(ret); | ||
673 | 615 | ||
674 | return ret; | 616 | return solo_send_desc(fh, skip, vbuf, frame_off, frame_size, |
617 | SOLO_MP4E_EXT_ADDR(solo_dev), | ||
618 | SOLO_MP4E_EXT_SIZE(solo_dev)); | ||
675 | } | 619 | } |
676 | 620 | ||
677 | static void solo_enc_fillbuf(struct solo_enc_fh *fh, | 621 | static int solo_enc_fillbuf(struct solo_enc_fh *fh, |
678 | struct videobuf_buffer *vb) | 622 | struct videobuf_buffer *vb, |
623 | struct solo_enc_buf *enc_buf) | ||
679 | { | 624 | { |
680 | struct solo_enc_dev *solo_enc = fh->enc; | 625 | struct solo_enc_dev *solo_enc = fh->enc; |
681 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 626 | struct solo_videobuf *svb = (struct solo_videobuf *)vb; |
682 | struct solo_enc_buf *enc_buf = NULL; | 627 | struct videobuf_dmabuf *vbuf = NULL; |
683 | struct videobuf_dmabuf *vbuf; | 628 | struct vop_header *vh = enc_buf->vh; |
684 | int ret; | 629 | int ret; |
685 | int error = 1; | ||
686 | u16 idx = fh->rd_idx; | ||
687 | |||
688 | while (idx != solo_dev->enc_wr_idx) { | ||
689 | struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx]; | ||
690 | 630 | ||
691 | idx = (idx + 1) % SOLO_NR_RING_BUFS; | 631 | vbuf = videobuf_to_dma(vb); |
692 | 632 | if (WARN_ON_ONCE(!vbuf)) { | |
693 | if (ebuf->ch != solo_enc->ch) | 633 | ret = -EIO; |
694 | continue; | 634 | goto vbuf_error; |
695 | |||
696 | if (fh->fmt == V4L2_PIX_FMT_MPEG) { | ||
697 | if (fh->type == ebuf->type) { | ||
698 | enc_buf = ebuf; | ||
699 | break; | ||
700 | } | ||
701 | } else { | ||
702 | /* For mjpeg, keep reading to the newest frame */ | ||
703 | enc_buf = ebuf; | ||
704 | } | ||
705 | } | 635 | } |
706 | 636 | ||
707 | fh->rd_idx = idx; | 637 | /* Setup some common flags for both types */ |
708 | 638 | svb->flags = V4L2_BUF_FLAG_TIMECODE; | |
709 | if (WARN_ON_ONCE(!enc_buf)) | 639 | vb->ts.tv_sec = vh->sec; |
710 | goto buf_err; | 640 | vb->ts.tv_usec = vh->usec; |
711 | 641 | ||
712 | if ((fh->fmt == V4L2_PIX_FMT_MPEG && | 642 | /* Check for motion flags */ |
713 | vb->bsize < enc_buf->size) || | 643 | if (solo_is_motion_on(solo_enc)) { |
714 | (fh->fmt == V4L2_PIX_FMT_MJPEG && | 644 | svb->flags |= V4L2_BUF_FLAG_MOTION_ON; |
715 | vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) { | 645 | if (enc_buf->motion) |
716 | WARN_ON_ONCE(1); | 646 | svb->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; |
717 | goto buf_err; | ||
718 | } | 647 | } |
719 | 648 | ||
720 | vbuf = videobuf_to_dma(vb); | ||
721 | if (WARN_ON_ONCE(!vbuf)) | ||
722 | goto buf_err; | ||
723 | |||
724 | if (fh->fmt == V4L2_PIX_FMT_MPEG) | 649 | if (fh->fmt == V4L2_PIX_FMT_MPEG) |
725 | ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf); | 650 | ret = solo_fill_mpeg(fh, vb, vbuf, vh); |
726 | else | 651 | else |
727 | ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf); | 652 | ret = solo_fill_jpeg(fh, vb, vbuf, vh); |
728 | 653 | ||
729 | if (!ret) | 654 | vbuf_error: |
730 | error = 0; | 655 | /* On error, we push this buffer back into the queue. The |
656 | * videobuf-core doesn't handle error packets very well. Plus | ||
657 | * we recover nicely internally anyway. */ | ||
658 | if (ret) { | ||
659 | unsigned long flags; | ||
731 | 660 | ||
732 | buf_err: | 661 | spin_lock_irqsave(&fh->av_lock, flags); |
733 | if (error) { | 662 | list_add(&vb->queue, &fh->vidq_active); |
734 | vb->state = VIDEOBUF_ERROR; | 663 | vb->state = VIDEOBUF_QUEUED; |
664 | spin_unlock_irqrestore(&fh->av_lock, flags); | ||
735 | } else { | 665 | } else { |
736 | vb->field_count++; | ||
737 | vb->ts = enc_buf->ts; | ||
738 | vb->state = VIDEOBUF_DONE; | 666 | vb->state = VIDEOBUF_DONE; |
739 | } | 667 | vb->field_count++; |
668 | vb->width = solo_enc->width; | ||
669 | vb->height = solo_enc->height; | ||
740 | 670 | ||
741 | wake_up(&vb->done); | 671 | wake_up(&vb->done); |
672 | } | ||
742 | 673 | ||
743 | return; | 674 | return ret; |
744 | } | 675 | } |
745 | 676 | ||
746 | static void solo_enc_thread_try(struct solo_enc_fh *fh) | 677 | static void solo_enc_handle_one(struct solo_enc_dev *solo_enc, |
678 | struct solo_enc_buf *enc_buf) | ||
747 | { | 679 | { |
748 | struct solo_enc_dev *solo_enc = fh->enc; | 680 | struct solo_enc_fh *fh; |
749 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
750 | struct videobuf_buffer *vb; | ||
751 | 681 | ||
752 | for (;;) { | 682 | mutex_lock(&solo_enc->enable_lock); |
753 | spin_lock(&solo_enc->lock); | 683 | |
684 | list_for_each_entry(fh, &solo_enc->listeners, list) { | ||
685 | struct videobuf_buffer *vb; | ||
686 | unsigned long flags; | ||
687 | |||
688 | if (fh->type != enc_buf->type) | ||
689 | continue; | ||
754 | 690 | ||
755 | if (fh->rd_idx == solo_dev->enc_wr_idx) | ||
756 | break; | ||
757 | 691 | ||
758 | if (list_empty(&fh->vidq_active)) | 692 | if (list_empty(&fh->vidq_active)) |
759 | break; | 693 | continue; |
694 | |||
695 | spin_lock_irqsave(&fh->av_lock, flags); | ||
760 | 696 | ||
761 | vb = list_first_entry(&fh->vidq_active, | 697 | vb = list_first_entry(&fh->vidq_active, |
762 | struct videobuf_buffer, queue); | 698 | struct videobuf_buffer, queue); |
763 | 699 | ||
764 | if (!waitqueue_active(&vb->done)) | ||
765 | break; | ||
766 | |||
767 | list_del(&vb->queue); | 700 | list_del(&vb->queue); |
701 | vb->state = VIDEOBUF_ACTIVE; | ||
768 | 702 | ||
769 | spin_unlock(&solo_enc->lock); | 703 | spin_unlock_irqrestore(&fh->av_lock, flags); |
770 | |||
771 | solo_enc_fillbuf(fh, vb); | ||
772 | } | ||
773 | |||
774 | assert_spin_locked(&solo_enc->lock); | ||
775 | spin_unlock(&solo_enc->lock); | ||
776 | } | ||
777 | |||
778 | static int solo_enc_thread(void *data) | ||
779 | { | ||
780 | struct solo_enc_fh *fh = data; | ||
781 | struct solo_enc_dev *solo_enc = fh->enc; | ||
782 | DECLARE_WAITQUEUE(wait, current); | ||
783 | 704 | ||
784 | set_freezable(); | 705 | solo_enc_fillbuf(fh, vb, enc_buf); |
785 | add_wait_queue(&solo_enc->thread_wait, &wait); | ||
786 | |||
787 | for (;;) { | ||
788 | long timeout = schedule_timeout_interruptible(HZ); | ||
789 | if (timeout == -ERESTARTSYS || kthread_should_stop()) | ||
790 | break; | ||
791 | solo_enc_thread_try(fh); | ||
792 | try_to_freeze(); | ||
793 | } | 706 | } |
794 | 707 | ||
795 | remove_wait_queue(&solo_enc->thread_wait, &wait); | 708 | mutex_unlock(&solo_enc->enable_lock); |
796 | |||
797 | return 0; | ||
798 | } | 709 | } |
799 | 710 | ||
800 | void solo_motion_isr(struct solo_dev *solo_dev) | 711 | void solo_enc_v4l2_isr(struct solo_dev *solo_dev) |
801 | { | 712 | { |
802 | u32 status; | 713 | wake_up_interruptible_all(&solo_dev->ring_thread_wait); |
803 | int i; | ||
804 | |||
805 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION); | ||
806 | |||
807 | status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS); | ||
808 | |||
809 | for (i = 0; i < solo_dev->nr_chans; i++) { | ||
810 | struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i]; | ||
811 | |||
812 | BUG_ON(solo_enc == NULL); | ||
813 | |||
814 | if (solo_enc->motion_detected) | ||
815 | continue; | ||
816 | if (!(status & (1 << i))) | ||
817 | continue; | ||
818 | |||
819 | solo_enc->motion_detected = 1; | ||
820 | } | ||
821 | } | 714 | } |
822 | 715 | ||
823 | void solo_enc_v4l2_isr(struct solo_dev *solo_dev) | 716 | static void solo_handle_ring(struct solo_dev *solo_dev) |
824 | { | 717 | { |
825 | struct solo_enc_buf *enc_buf; | 718 | for (;;) { |
826 | u32 mpeg_current, mpeg_next, mpeg_size; | 719 | struct solo_enc_dev *solo_enc; |
827 | u32 jpeg_current, jpeg_next, jpeg_size; | 720 | struct solo_enc_buf enc_buf; |
828 | u32 reg_mpeg_size; | 721 | u32 mpeg_current, off; |
829 | u8 cur_q, vop_type; | 722 | u8 ch; |
830 | u8 ch; | 723 | u8 cur_q; |
831 | enum solo_enc_types enc_type; | 724 | |
832 | 725 | /* Check if the hardware has any new ones in the queue */ | |
833 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER); | 726 | cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff; |
834 | 727 | if (cur_q == solo_dev->enc_idx) | |
835 | cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS; | 728 | break; |
836 | |||
837 | reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7; | ||
838 | 729 | ||
839 | while (solo_dev->enc_idx != cur_q) { | ||
840 | mpeg_current = solo_reg_read(solo_dev, | 730 | mpeg_current = solo_reg_read(solo_dev, |
841 | SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); | 731 | SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); |
842 | jpeg_current = solo_reg_read(solo_dev, | ||
843 | SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); | ||
844 | solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS; | 732 | solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS; |
845 | mpeg_next = solo_reg_read(solo_dev, | ||
846 | SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); | ||
847 | jpeg_next = solo_reg_read(solo_dev, | ||
848 | SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); | ||
849 | 733 | ||
850 | ch = (mpeg_current >> 24) & 0x1f; | 734 | ch = (mpeg_current >> 24) & 0x1f; |
735 | off = mpeg_current & 0x00ffffff; | ||
736 | |||
851 | if (ch >= SOLO_MAX_CHANNELS) { | 737 | if (ch >= SOLO_MAX_CHANNELS) { |
852 | ch -= SOLO_MAX_CHANNELS; | 738 | ch -= SOLO_MAX_CHANNELS; |
853 | enc_type = SOLO_ENC_TYPE_EXT; | 739 | enc_buf.type = SOLO_ENC_TYPE_EXT; |
854 | } else | 740 | } else |
855 | enc_type = SOLO_ENC_TYPE_STD; | 741 | enc_buf.type = SOLO_ENC_TYPE_STD; |
856 | |||
857 | vop_type = (mpeg_current >> 29) & 3; | ||
858 | |||
859 | mpeg_current &= 0x00ffffff; | ||
860 | mpeg_next &= 0x00ffffff; | ||
861 | jpeg_current &= 0x00ffffff; | ||
862 | jpeg_next &= 0x00ffffff; | ||
863 | |||
864 | mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) + | ||
865 | mpeg_next - mpeg_current) % | ||
866 | SOLO_MP4E_EXT_SIZE(solo_dev); | ||
867 | |||
868 | jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) + | ||
869 | jpeg_next - jpeg_current) % | ||
870 | SOLO_JPEG_EXT_SIZE(solo_dev); | ||
871 | 742 | ||
872 | /* XXX I think this means we had a ring overflow? */ | 743 | solo_enc = solo_dev->v4l2_enc[ch]; |
873 | if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) { | 744 | if (solo_enc == NULL) { |
874 | enc_reset_gop(solo_dev, ch); | 745 | dev_err(&solo_dev->pdev->dev, |
746 | "Got spurious packet for channel %d\n", ch); | ||
875 | continue; | 747 | continue; |
876 | } | 748 | } |
877 | 749 | ||
878 | /* When resetting the GOP, skip frames until I-frame */ | 750 | /* FAIL... */ |
879 | if (enc_gop_reset(solo_dev, ch, vop_type)) | 751 | if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off, |
752 | sizeof(struct vop_header))) | ||
880 | continue; | 753 | continue; |
881 | 754 | ||
882 | enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx]; | 755 | enc_buf.vh = (struct vop_header *)solo_dev->vh_buf; |
756 | enc_buf.vh->mpeg_off -= SOLO_MP4E_EXT_ADDR(solo_dev); | ||
757 | enc_buf.vh->jpeg_off -= SOLO_JPEG_EXT_ADDR(solo_dev); | ||
883 | 758 | ||
884 | enc_buf->vop = vop_type; | 759 | /* Sanity check */ |
885 | enc_buf->ch = ch; | 760 | if (enc_buf.vh->mpeg_off != off) |
886 | enc_buf->off = mpeg_current; | 761 | continue; |
887 | enc_buf->size = mpeg_size; | 762 | |
888 | enc_buf->jpeg_off = jpeg_current; | 763 | if (solo_motion_detected(solo_enc)) |
889 | enc_buf->jpeg_size = jpeg_size; | 764 | enc_buf.motion = 1; |
890 | enc_buf->type = enc_type; | 765 | else |
766 | enc_buf.motion = 0; | ||
767 | |||
768 | solo_enc_handle_one(solo_enc, &enc_buf); | ||
769 | } | ||
770 | } | ||
891 | 771 | ||
892 | do_gettimeofday(&enc_buf->ts); | 772 | static int solo_ring_thread(void *data) |
773 | { | ||
774 | struct solo_dev *solo_dev = data; | ||
775 | DECLARE_WAITQUEUE(wait, current); | ||
893 | 776 | ||
894 | solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) % | 777 | set_freezable(); |
895 | SOLO_NR_RING_BUFS; | 778 | add_wait_queue(&solo_dev->ring_thread_wait, &wait); |
896 | 779 | ||
897 | wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait); | 780 | for (;;) { |
781 | long timeout = schedule_timeout_interruptible(HZ); | ||
782 | if (timeout == -ERESTARTSYS || kthread_should_stop()) | ||
783 | break; | ||
784 | solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); | ||
785 | solo_handle_ring(solo_dev); | ||
786 | solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); | ||
787 | try_to_freeze(); | ||
898 | } | 788 | } |
899 | 789 | ||
900 | return; | 790 | remove_wait_queue(&solo_dev->ring_thread_wait, &wait); |
791 | |||
792 | return 0; | ||
901 | } | 793 | } |
902 | 794 | ||
903 | static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count, | 795 | static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count, |
@@ -915,17 +807,12 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, | |||
915 | struct videobuf_buffer *vb, | 807 | struct videobuf_buffer *vb, |
916 | enum v4l2_field field) | 808 | enum v4l2_field field) |
917 | { | 809 | { |
918 | struct solo_enc_fh *fh = vq->priv_data; | ||
919 | struct solo_enc_dev *solo_enc = fh->enc; | ||
920 | |||
921 | vb->size = FRAME_BUF_SIZE; | 810 | vb->size = FRAME_BUF_SIZE; |
922 | if (vb->baddr != 0 && vb->bsize < vb->size) | 811 | if (vb->baddr != 0 && vb->bsize < vb->size) |
923 | return -EINVAL; | 812 | return -EINVAL; |
924 | 813 | ||
925 | /* These properties only change when queue is idle */ | 814 | /* This property only change when queue is idle */ |
926 | vb->width = solo_enc->width; | 815 | vb->field = field; |
927 | vb->height = solo_enc->height; | ||
928 | vb->field = field; | ||
929 | 816 | ||
930 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | 817 | if (vb->state == VIDEOBUF_NEEDS_INIT) { |
931 | int rc = videobuf_iolock(vq, vb, NULL); | 818 | int rc = videobuf_iolock(vq, vb, NULL); |
@@ -933,7 +820,7 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, | |||
933 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | 820 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); |
934 | videobuf_dma_unmap(vq->dev, dma); | 821 | videobuf_dma_unmap(vq->dev, dma); |
935 | videobuf_dma_free(dma); | 822 | videobuf_dma_free(dma); |
936 | vb->state = VIDEOBUF_NEEDS_INIT; | 823 | |
937 | return rc; | 824 | return rc; |
938 | } | 825 | } |
939 | } | 826 | } |
@@ -949,20 +836,18 @@ static void solo_enc_buf_queue(struct videobuf_queue *vq, | |||
949 | 836 | ||
950 | vb->state = VIDEOBUF_QUEUED; | 837 | vb->state = VIDEOBUF_QUEUED; |
951 | list_add_tail(&vb->queue, &fh->vidq_active); | 838 | list_add_tail(&vb->queue, &fh->vidq_active); |
952 | wake_up_interruptible(&fh->enc->thread_wait); | ||
953 | } | 839 | } |
954 | 840 | ||
955 | static void solo_enc_buf_release(struct videobuf_queue *vq, | 841 | static void solo_enc_buf_release(struct videobuf_queue *vq, |
956 | struct videobuf_buffer *vb) | 842 | struct videobuf_buffer *vb) |
957 | { | 843 | { |
958 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | 844 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); |
959 | |||
960 | videobuf_dma_unmap(vq->dev, dma); | 845 | videobuf_dma_unmap(vq->dev, dma); |
961 | videobuf_dma_free(dma); | 846 | videobuf_dma_free(dma); |
962 | vb->state = VIDEOBUF_NEEDS_INIT; | 847 | vb->state = VIDEOBUF_NEEDS_INIT; |
963 | } | 848 | } |
964 | 849 | ||
965 | static struct videobuf_queue_ops solo_enc_video_qops = { | 850 | static const struct videobuf_queue_ops solo_enc_video_qops = { |
966 | .buf_setup = solo_enc_buf_setup, | 851 | .buf_setup = solo_enc_buf_setup, |
967 | .buf_prepare = solo_enc_buf_prepare, | 852 | .buf_prepare = solo_enc_buf_prepare, |
968 | .buf_queue = solo_enc_buf_queue, | 853 | .buf_queue = solo_enc_buf_queue, |
@@ -984,27 +869,78 @@ static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma) | |||
984 | return videobuf_mmap_mapper(&fh->vidq, vma); | 869 | return videobuf_mmap_mapper(&fh->vidq, vma); |
985 | } | 870 | } |
986 | 871 | ||
872 | static int solo_ring_start(struct solo_dev *solo_dev) | ||
873 | { | ||
874 | if (atomic_inc_return(&solo_dev->enc_users) > 1) | ||
875 | return 0; | ||
876 | |||
877 | solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev, | ||
878 | SOLO6X10_NAME "_ring"); | ||
879 | if (IS_ERR(solo_dev->ring_thread)) { | ||
880 | int err = PTR_ERR(solo_dev->ring_thread); | ||
881 | solo_dev->ring_thread = NULL; | ||
882 | return err; | ||
883 | } | ||
884 | |||
885 | solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static void solo_ring_stop(struct solo_dev *solo_dev) | ||
891 | { | ||
892 | if (atomic_dec_return(&solo_dev->enc_users) > 0) | ||
893 | return; | ||
894 | |||
895 | if (solo_dev->ring_thread) { | ||
896 | kthread_stop(solo_dev->ring_thread); | ||
897 | solo_dev->ring_thread = NULL; | ||
898 | } | ||
899 | |||
900 | solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); | ||
901 | } | ||
902 | |||
987 | static int solo_enc_open(struct file *file) | 903 | static int solo_enc_open(struct file *file) |
988 | { | 904 | { |
989 | struct solo_enc_dev *solo_enc = video_drvdata(file); | 905 | struct solo_enc_dev *solo_enc = video_drvdata(file); |
906 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
990 | struct solo_enc_fh *fh; | 907 | struct solo_enc_fh *fh; |
908 | int ret; | ||
909 | |||
910 | ret = solo_ring_start(solo_dev); | ||
911 | if (ret) | ||
912 | return ret; | ||
991 | 913 | ||
992 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 914 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
993 | if (fh == NULL) | 915 | if (fh == NULL) { |
916 | solo_ring_stop(solo_dev); | ||
917 | return -ENOMEM; | ||
918 | } | ||
919 | |||
920 | fh->desc_nelts = 32; | ||
921 | fh->desc_items = pci_alloc_consistent(solo_dev->pdev, | ||
922 | sizeof(struct solo_p2m_desc) * | ||
923 | fh->desc_nelts, &fh->desc_dma); | ||
924 | if (fh->desc_items == NULL) { | ||
925 | kfree(fh); | ||
926 | solo_ring_stop(solo_dev); | ||
994 | return -ENOMEM; | 927 | return -ENOMEM; |
928 | } | ||
995 | 929 | ||
996 | fh->enc = solo_enc; | 930 | fh->enc = solo_enc; |
931 | spin_lock_init(&fh->av_lock); | ||
997 | file->private_data = fh; | 932 | file->private_data = fh; |
998 | INIT_LIST_HEAD(&fh->vidq_active); | 933 | INIT_LIST_HEAD(&fh->vidq_active); |
999 | fh->fmt = V4L2_PIX_FMT_MPEG; | 934 | fh->fmt = V4L2_PIX_FMT_MPEG; |
1000 | fh->type = SOLO_ENC_TYPE_STD; | 935 | fh->type = SOLO_ENC_TYPE_STD; |
1001 | 936 | ||
1002 | videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops, | 937 | videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops, |
1003 | &solo_enc->solo_dev->pdev->dev, | 938 | &solo_dev->pdev->dev, |
1004 | &solo_enc->lock, | 939 | &fh->av_lock, |
1005 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 940 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
1006 | V4L2_FIELD_INTERLACED, | 941 | V4L2_FIELD_INTERLACED, |
1007 | sizeof(struct videobuf_buffer), fh, NULL); | 942 | sizeof(struct solo_videobuf), |
943 | fh, NULL); | ||
1008 | 944 | ||
1009 | return 0; | 945 | return 0; |
1010 | } | 946 | } |
@@ -1013,22 +949,12 @@ static ssize_t solo_enc_read(struct file *file, char __user *data, | |||
1013 | size_t count, loff_t *ppos) | 949 | size_t count, loff_t *ppos) |
1014 | { | 950 | { |
1015 | struct solo_enc_fh *fh = file->private_data; | 951 | struct solo_enc_fh *fh = file->private_data; |
1016 | struct solo_enc_dev *solo_enc = fh->enc; | 952 | int ret; |
1017 | 953 | ||
1018 | /* Make sure the encoder is on */ | 954 | /* Make sure the encoder is on */ |
1019 | if (!fh->enc_on) { | 955 | ret = solo_enc_on(fh); |
1020 | int ret; | 956 | if (ret) |
1021 | 957 | return ret; | |
1022 | spin_lock(&solo_enc->lock); | ||
1023 | ret = solo_enc_on(fh); | ||
1024 | spin_unlock(&solo_enc->lock); | ||
1025 | if (ret) | ||
1026 | return ret; | ||
1027 | |||
1028 | ret = solo_start_fh_thread(fh); | ||
1029 | if (ret) | ||
1030 | return ret; | ||
1031 | } | ||
1032 | 958 | ||
1033 | return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, | 959 | return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, |
1034 | file->f_flags & O_NONBLOCK); | 960 | file->f_flags & O_NONBLOCK); |
@@ -1037,17 +963,21 @@ static ssize_t solo_enc_read(struct file *file, char __user *data, | |||
1037 | static int solo_enc_release(struct file *file) | 963 | static int solo_enc_release(struct file *file) |
1038 | { | 964 | { |
1039 | struct solo_enc_fh *fh = file->private_data; | 965 | struct solo_enc_fh *fh = file->private_data; |
1040 | struct solo_enc_dev *solo_enc = fh->enc; | 966 | struct solo_dev *solo_dev = fh->enc->solo_dev; |
967 | |||
968 | solo_enc_off(fh); | ||
1041 | 969 | ||
1042 | videobuf_stop(&fh->vidq); | 970 | videobuf_stop(&fh->vidq); |
1043 | videobuf_mmap_free(&fh->vidq); | 971 | videobuf_mmap_free(&fh->vidq); |
1044 | 972 | ||
1045 | spin_lock(&solo_enc->lock); | 973 | pci_free_consistent(fh->enc->solo_dev->pdev, |
1046 | solo_enc_off(fh); | 974 | sizeof(struct solo_p2m_desc) * |
1047 | spin_unlock(&solo_enc->lock); | 975 | fh->desc_nelts, fh->desc_items, fh->desc_dma); |
1048 | 976 | ||
1049 | kfree(fh); | 977 | kfree(fh); |
1050 | 978 | ||
979 | solo_ring_stop(solo_dev); | ||
980 | |||
1051 | return 0; | 981 | return 0; |
1052 | } | 982 | } |
1053 | 983 | ||
@@ -1095,7 +1025,8 @@ static int solo_enc_enum_input(struct file *file, void *priv, | |||
1095 | return 0; | 1025 | return 0; |
1096 | } | 1026 | } |
1097 | 1027 | ||
1098 | static int solo_enc_set_input(struct file *file, void *priv, unsigned int index) | 1028 | static int solo_enc_set_input(struct file *file, void *priv, |
1029 | unsigned int index) | ||
1099 | { | 1030 | { |
1100 | if (index) | 1031 | if (index) |
1101 | return -EINVAL; | 1032 | return -EINVAL; |
@@ -1144,8 +1075,8 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, | |||
1144 | pix->pixelformat != V4L2_PIX_FMT_MJPEG) | 1075 | pix->pixelformat != V4L2_PIX_FMT_MJPEG) |
1145 | return -EINVAL; | 1076 | return -EINVAL; |
1146 | 1077 | ||
1147 | /* We cannot change width/height in mid read */ | 1078 | /* We cannot change width/height in mid mpeg */ |
1148 | if (atomic_read(&solo_enc->readers) > 0) { | 1079 | if (atomic_read(&solo_enc->mpeg_readers) > 0) { |
1149 | if (pix->width != solo_enc->width || | 1080 | if (pix->width != solo_enc->width || |
1150 | pix->height != solo_enc->height) | 1081 | pix->height != solo_enc->height) |
1151 | return -EBUSY; | 1082 | return -EBUSY; |
@@ -1183,11 +1114,11 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, | |||
1183 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1114 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1184 | int ret; | 1115 | int ret; |
1185 | 1116 | ||
1186 | spin_lock(&solo_enc->lock); | 1117 | mutex_lock(&solo_enc->enable_lock); |
1187 | 1118 | ||
1188 | ret = solo_enc_try_fmt_cap(file, priv, f); | 1119 | ret = solo_enc_try_fmt_cap(file, priv, f); |
1189 | if (ret) { | 1120 | if (ret) { |
1190 | spin_unlock(&solo_enc->lock); | 1121 | mutex_unlock(&solo_enc->enable_lock); |
1191 | return ret; | 1122 | return ret; |
1192 | } | 1123 | } |
1193 | 1124 | ||
@@ -1201,14 +1132,10 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, | |||
1201 | 1132 | ||
1202 | if (pix->priv) | 1133 | if (pix->priv) |
1203 | fh->type = SOLO_ENC_TYPE_EXT; | 1134 | fh->type = SOLO_ENC_TYPE_EXT; |
1204 | ret = solo_enc_on(fh); | ||
1205 | |||
1206 | spin_unlock(&solo_enc->lock); | ||
1207 | 1135 | ||
1208 | if (ret) | 1136 | mutex_unlock(&solo_enc->enable_lock); |
1209 | return ret; | ||
1210 | 1137 | ||
1211 | return solo_start_fh_thread(fh); | 1138 | return 0; |
1212 | } | 1139 | } |
1213 | 1140 | ||
1214 | static int solo_enc_get_fmt_cap(struct file *file, void *priv, | 1141 | static int solo_enc_get_fmt_cap(struct file *file, void *priv, |
@@ -1245,7 +1172,8 @@ static int solo_enc_querybuf(struct file *file, void *priv, | |||
1245 | return videobuf_querybuf(&fh->vidq, buf); | 1172 | return videobuf_querybuf(&fh->vidq, buf); |
1246 | } | 1173 | } |
1247 | 1174 | ||
1248 | static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | 1175 | static int solo_enc_qbuf(struct file *file, void *priv, |
1176 | struct v4l2_buffer *buf) | ||
1249 | { | 1177 | { |
1250 | struct solo_enc_fh *fh = priv; | 1178 | struct solo_enc_fh *fh = priv; |
1251 | 1179 | ||
@@ -1256,50 +1184,21 @@ static int solo_enc_dqbuf(struct file *file, void *priv, | |||
1256 | struct v4l2_buffer *buf) | 1184 | struct v4l2_buffer *buf) |
1257 | { | 1185 | { |
1258 | struct solo_enc_fh *fh = priv; | 1186 | struct solo_enc_fh *fh = priv; |
1259 | struct solo_enc_dev *solo_enc = fh->enc; | 1187 | struct solo_videobuf *svb; |
1260 | int ret; | 1188 | int ret; |
1261 | 1189 | ||
1262 | /* Make sure the encoder is on */ | 1190 | /* Make sure the encoder is on */ |
1263 | if (!fh->enc_on) { | 1191 | ret = solo_enc_on(fh); |
1264 | spin_lock(&solo_enc->lock); | 1192 | if (ret) |
1265 | ret = solo_enc_on(fh); | 1193 | return ret; |
1266 | spin_unlock(&solo_enc->lock); | ||
1267 | if (ret) | ||
1268 | return ret; | ||
1269 | |||
1270 | ret = solo_start_fh_thread(fh); | ||
1271 | if (ret) | ||
1272 | return ret; | ||
1273 | } | ||
1274 | 1194 | ||
1275 | ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); | 1195 | ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); |
1276 | if (ret) | 1196 | if (ret) |
1277 | return ret; | 1197 | return ret; |
1278 | 1198 | ||
1279 | /* Signal motion detection */ | 1199 | /* Copy over the flags */ |
1280 | if (solo_is_motion_on(solo_enc)) { | 1200 | svb = (struct solo_videobuf *)fh->vidq.bufs[buf->index]; |
1281 | buf->flags |= V4L2_BUF_FLAG_MOTION_ON; | 1201 | buf->flags |= svb->flags; |
1282 | if (solo_enc->motion_detected) { | ||
1283 | buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; | ||
1284 | solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, | ||
1285 | 1 << solo_enc->ch); | ||
1286 | solo_enc->motion_detected = 0; | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | /* Check for key frame on mpeg data */ | ||
1291 | if (fh->fmt == V4L2_PIX_FMT_MPEG) { | ||
1292 | struct videobuf_dmabuf *vbuf = | ||
1293 | videobuf_to_dma(fh->vidq.bufs[buf->index]); | ||
1294 | |||
1295 | if (vbuf) { | ||
1296 | u8 *p = sg_virt(vbuf->sglist); | ||
1297 | if (p[3] == 0x00) | ||
1298 | buf->flags |= V4L2_BUF_FLAG_KEYFRAME; | ||
1299 | else | ||
1300 | buf->flags |= V4L2_BUF_FLAG_PFRAME; | ||
1301 | } | ||
1302 | } | ||
1303 | 1202 | ||
1304 | return 0; | 1203 | return 0; |
1305 | } | 1204 | } |
@@ -1319,11 +1218,16 @@ static int solo_enc_streamoff(struct file *file, void *priv, | |||
1319 | enum v4l2_buf_type i) | 1218 | enum v4l2_buf_type i) |
1320 | { | 1219 | { |
1321 | struct solo_enc_fh *fh = priv; | 1220 | struct solo_enc_fh *fh = priv; |
1221 | int ret; | ||
1322 | 1222 | ||
1323 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1223 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1324 | return -EINVAL; | 1224 | return -EINVAL; |
1325 | 1225 | ||
1326 | return videobuf_streamoff(&fh->vidq); | 1226 | ret = videobuf_streamoff(&fh->vidq); |
1227 | if (!ret) | ||
1228 | solo_enc_off(fh); | ||
1229 | |||
1230 | return ret; | ||
1327 | } | 1231 | } |
1328 | 1232 | ||
1329 | static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) | 1233 | static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) |
@@ -1407,10 +1311,10 @@ static int solo_s_parm(struct file *file, void *priv, | |||
1407 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 1311 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
1408 | struct v4l2_captureparm *cp = &sp->parm.capture; | 1312 | struct v4l2_captureparm *cp = &sp->parm.capture; |
1409 | 1313 | ||
1410 | spin_lock(&solo_enc->lock); | 1314 | mutex_lock(&solo_enc->enable_lock); |
1411 | 1315 | ||
1412 | if (atomic_read(&solo_enc->readers) > 0) { | 1316 | if (atomic_read(&solo_enc->mpeg_readers) > 0) { |
1413 | spin_unlock(&solo_enc->lock); | 1317 | mutex_unlock(&solo_enc->enable_lock); |
1414 | return -EBUSY; | 1318 | return -EBUSY; |
1415 | } | 1319 | } |
1416 | 1320 | ||
@@ -1431,10 +1335,9 @@ static int solo_s_parm(struct file *file, void *priv, | |||
1431 | 1335 | ||
1432 | cp->capability = V4L2_CAP_TIMEPERFRAME; | 1336 | cp->capability = V4L2_CAP_TIMEPERFRAME; |
1433 | 1337 | ||
1434 | solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1); | ||
1435 | solo_update_mode(solo_enc); | 1338 | solo_update_mode(solo_enc); |
1436 | 1339 | ||
1437 | spin_unlock(&solo_enc->lock); | 1340 | mutex_unlock(&solo_enc->enable_lock); |
1438 | 1341 | ||
1439 | return 0; | 1342 | return 0; |
1440 | } | 1343 | } |
@@ -1510,6 +1413,7 @@ static int solo_querymenu(struct file *file, void *priv, | |||
1510 | int err; | 1413 | int err; |
1511 | 1414 | ||
1512 | qctrl.id = qmenu->id; | 1415 | qctrl.id = qmenu->id; |
1416 | |||
1513 | err = solo_queryctrl(file, priv, &qctrl); | 1417 | err = solo_queryctrl(file, priv, &qctrl); |
1514 | if (err) | 1418 | if (err) |
1515 | return err; | 1419 | return err; |
@@ -1536,6 +1440,8 @@ static int solo_g_ctrl(struct file *file, void *priv, | |||
1536 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; | 1440 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; |
1537 | break; | 1441 | break; |
1538 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | 1442 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: |
1443 | if (atomic_read(&solo_enc->readers) > 0) | ||
1444 | return -EBUSY; | ||
1539 | ctrl->value = solo_enc->gop; | 1445 | ctrl->value = solo_enc->gop; |
1540 | break; | 1446 | break; |
1541 | case V4L2_CID_MOTION_THRESHOLD: | 1447 | case V4L2_CID_MOTION_THRESHOLD: |
@@ -1574,19 +1480,32 @@ static int solo_s_ctrl(struct file *file, void *priv, | |||
1574 | if (ctrl->value < 1 || ctrl->value > 255) | 1480 | if (ctrl->value < 1 || ctrl->value > 255) |
1575 | return -ERANGE; | 1481 | return -ERANGE; |
1576 | solo_enc->gop = ctrl->value; | 1482 | solo_enc->gop = ctrl->value; |
1577 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), | ||
1578 | solo_enc->gop); | ||
1579 | solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), | ||
1580 | solo_enc->gop); | ||
1581 | break; | 1483 | break; |
1582 | case V4L2_CID_MOTION_THRESHOLD: | 1484 | case V4L2_CID_MOTION_THRESHOLD: |
1583 | /* TODO accept value on lower 16-bits and use high | 1485 | { |
1584 | * 16-bits to assign the value to a specific block */ | 1486 | u16 block = (ctrl->value >> 16) & 0xffff; |
1585 | if (ctrl->value < 0 || ctrl->value > 0xffff) | 1487 | u16 value = ctrl->value & 0xffff; |
1488 | |||
1489 | /* Motion thresholds are in a table of 64x64 samples, with | ||
1490 | * each sample representing 16x16 pixels of the source. In | ||
1491 | * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. | ||
1492 | * The 5th sample on the 10th row is (10*64)+5 = 645. | ||
1493 | * | ||
1494 | * Block is 0 to set the threshold globally, or any positive | ||
1495 | * number under 2049 to set block-1 individually. */ | ||
1496 | if (block > 2049) | ||
1586 | return -ERANGE; | 1497 | return -ERANGE; |
1587 | solo_enc->motion_thresh = ctrl->value; | 1498 | |
1588 | solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value); | 1499 | if (block == 0) { |
1500 | solo_enc->motion_thresh = value; | ||
1501 | return solo_set_motion_threshold(solo_dev, | ||
1502 | solo_enc->ch, value); | ||
1503 | } else { | ||
1504 | return solo_set_motion_block(solo_dev, solo_enc->ch, | ||
1505 | value, block - 1); | ||
1506 | } | ||
1589 | break; | 1507 | break; |
1508 | } | ||
1590 | case V4L2_CID_MOTION_ENABLE: | 1509 | case V4L2_CID_MOTION_ENABLE: |
1591 | solo_motion_toggle(solo_enc, ctrl->value); | 1510 | solo_motion_toggle(solo_enc, ctrl->value); |
1592 | break; | 1511 | break; |
@@ -1613,6 +1532,7 @@ static int solo_s_ext_ctrls(struct file *file, void *priv, | |||
1613 | if (ctrl->size - 1 > OSD_TEXT_MAX) | 1532 | if (ctrl->size - 1 > OSD_TEXT_MAX) |
1614 | err = -ERANGE; | 1533 | err = -ERANGE; |
1615 | else { | 1534 | else { |
1535 | mutex_lock(&solo_enc->enable_lock); | ||
1616 | err = copy_from_user(solo_enc->osd_text, | 1536 | err = copy_from_user(solo_enc->osd_text, |
1617 | ctrl->string, | 1537 | ctrl->string, |
1618 | OSD_TEXT_MAX); | 1538 | OSD_TEXT_MAX); |
@@ -1621,6 +1541,7 @@ static int solo_s_ext_ctrls(struct file *file, void *priv, | |||
1621 | err = solo_osd_print(solo_enc); | 1541 | err = solo_osd_print(solo_enc); |
1622 | else | 1542 | else |
1623 | err = -EFAULT; | 1543 | err = -EFAULT; |
1544 | mutex_unlock(&solo_enc->enable_lock); | ||
1624 | } | 1545 | } |
1625 | break; | 1546 | break; |
1626 | default: | 1547 | default: |
@@ -1653,11 +1574,13 @@ static int solo_g_ext_ctrls(struct file *file, void *priv, | |||
1653 | ctrl->size = OSD_TEXT_MAX; | 1574 | ctrl->size = OSD_TEXT_MAX; |
1654 | err = -ENOSPC; | 1575 | err = -ENOSPC; |
1655 | } else { | 1576 | } else { |
1577 | mutex_lock(&solo_enc->enable_lock); | ||
1656 | err = copy_to_user(ctrl->string, | 1578 | err = copy_to_user(ctrl->string, |
1657 | solo_enc->osd_text, | 1579 | solo_enc->osd_text, |
1658 | OSD_TEXT_MAX); | 1580 | OSD_TEXT_MAX); |
1659 | if (err) | 1581 | if (err) |
1660 | err = -EFAULT; | 1582 | err = -EFAULT; |
1583 | mutex_unlock(&solo_enc->enable_lock); | ||
1661 | } | 1584 | } |
1662 | break; | 1585 | break; |
1663 | default: | 1586 | default: |
@@ -1717,7 +1640,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { | |||
1717 | .vidioc_s_ext_ctrls = solo_s_ext_ctrls, | 1640 | .vidioc_s_ext_ctrls = solo_s_ext_ctrls, |
1718 | }; | 1641 | }; |
1719 | 1642 | ||
1720 | static struct video_device solo_enc_template = { | 1643 | static const struct video_device solo_enc_template = { |
1721 | .name = SOLO6X10_NAME, | 1644 | .name = SOLO6X10_NAME, |
1722 | .fops = &solo_enc_fops, | 1645 | .fops = &solo_enc_fops, |
1723 | .ioctl_ops = &solo_enc_ioctl_ops, | 1646 | .ioctl_ops = &solo_enc_ioctl_ops, |
@@ -1728,7 +1651,8 @@ static struct video_device solo_enc_template = { | |||
1728 | .current_norm = V4L2_STD_NTSC_M, | 1651 | .current_norm = V4L2_STD_NTSC_M, |
1729 | }; | 1652 | }; |
1730 | 1653 | ||
1731 | static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) | 1654 | static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, |
1655 | u8 ch, unsigned nr) | ||
1732 | { | 1656 | { |
1733 | struct solo_enc_dev *solo_enc; | 1657 | struct solo_enc_dev *solo_enc; |
1734 | int ret; | 1658 | int ret; |
@@ -1748,8 +1672,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) | |||
1748 | 1672 | ||
1749 | *solo_enc->vfd = solo_enc_template; | 1673 | *solo_enc->vfd = solo_enc_template; |
1750 | solo_enc->vfd->parent = &solo_dev->pdev->dev; | 1674 | solo_enc->vfd->parent = &solo_dev->pdev->dev; |
1751 | ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, | 1675 | ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); |
1752 | video_nr); | ||
1753 | if (ret < 0) { | 1676 | if (ret < 0) { |
1754 | video_device_release(solo_enc->vfd); | 1677 | video_device_release(solo_enc->vfd); |
1755 | kfree(solo_enc); | 1678 | kfree(solo_enc); |
@@ -1762,12 +1685,12 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) | |||
1762 | "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, | 1685 | "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, |
1763 | solo_enc->vfd->num); | 1686 | solo_enc->vfd->num); |
1764 | 1687 | ||
1765 | if (video_nr != -1) | 1688 | INIT_LIST_HEAD(&solo_enc->listeners); |
1766 | video_nr++; | 1689 | mutex_init(&solo_enc->enable_lock); |
1690 | spin_lock_init(&solo_enc->motion_lock); | ||
1767 | 1691 | ||
1768 | spin_lock_init(&solo_enc->lock); | ||
1769 | init_waitqueue_head(&solo_enc->thread_wait); | ||
1770 | atomic_set(&solo_enc->readers, 0); | 1692 | atomic_set(&solo_enc->readers, 0); |
1693 | atomic_set(&solo_enc->mpeg_readers, 0); | ||
1771 | 1694 | ||
1772 | solo_enc->qp = SOLO_DEFAULT_QP; | 1695 | solo_enc->qp = SOLO_DEFAULT_QP; |
1773 | solo_enc->gop = solo_dev->fps; | 1696 | solo_enc->gop = solo_dev->fps; |
@@ -1775,9 +1698,13 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) | |||
1775 | solo_enc->mode = SOLO_ENC_MODE_CIF; | 1698 | solo_enc->mode = SOLO_ENC_MODE_CIF; |
1776 | solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; | 1699 | solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; |
1777 | 1700 | ||
1778 | spin_lock(&solo_enc->lock); | 1701 | mutex_lock(&solo_enc->enable_lock); |
1779 | solo_update_mode(solo_enc); | 1702 | solo_update_mode(solo_enc); |
1780 | spin_unlock(&solo_enc->lock); | 1703 | mutex_unlock(&solo_enc->enable_lock); |
1704 | |||
1705 | /* Initialize this per encoder */ | ||
1706 | solo_enc->jpeg_len = sizeof(jpeg_header); | ||
1707 | memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); | ||
1781 | 1708 | ||
1782 | return solo_enc; | 1709 | return solo_enc; |
1783 | } | 1710 | } |
@@ -1791,12 +1718,22 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc) | |||
1791 | kfree(solo_enc); | 1718 | kfree(solo_enc); |
1792 | } | 1719 | } |
1793 | 1720 | ||
1794 | int solo_enc_v4l2_init(struct solo_dev *solo_dev) | 1721 | int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) |
1795 | { | 1722 | { |
1796 | int i; | 1723 | int i; |
1797 | 1724 | ||
1725 | atomic_set(&solo_dev->enc_users, 0); | ||
1726 | init_waitqueue_head(&solo_dev->ring_thread_wait); | ||
1727 | |||
1728 | solo_dev->vh_size = sizeof(struct vop_header); | ||
1729 | solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev, | ||
1730 | solo_dev->vh_size, | ||
1731 | &solo_dev->vh_dma); | ||
1732 | if (solo_dev->vh_buf == NULL) | ||
1733 | return -ENOMEM; | ||
1734 | |||
1798 | for (i = 0; i < solo_dev->nr_chans; i++) { | 1735 | for (i = 0; i < solo_dev->nr_chans; i++) { |
1799 | solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i); | 1736 | solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr); |
1800 | if (IS_ERR(solo_dev->v4l2_enc[i])) | 1737 | if (IS_ERR(solo_dev->v4l2_enc[i])) |
1801 | break; | 1738 | break; |
1802 | } | 1739 | } |
@@ -1805,11 +1742,15 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev) | |||
1805 | int ret = PTR_ERR(solo_dev->v4l2_enc[i]); | 1742 | int ret = PTR_ERR(solo_dev->v4l2_enc[i]); |
1806 | while (i--) | 1743 | while (i--) |
1807 | solo_enc_free(solo_dev->v4l2_enc[i]); | 1744 | solo_enc_free(solo_dev->v4l2_enc[i]); |
1745 | pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, | ||
1746 | solo_dev->vh_buf, solo_dev->vh_dma); | ||
1808 | return ret; | 1747 | return ret; |
1809 | } | 1748 | } |
1810 | 1749 | ||
1811 | /* D1@MAX-FPS * 4 */ | 1750 | if (solo_dev->type == SOLO_DEV_6010) |
1812 | solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; | 1751 | solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; |
1752 | else | ||
1753 | solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5; | ||
1813 | 1754 | ||
1814 | dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n", | 1755 | dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n", |
1815 | solo_dev->v4l2_enc[0]->vfd->num, | 1756 | solo_dev->v4l2_enc[0]->vfd->num, |
@@ -1822,8 +1763,9 @@ void solo_enc_v4l2_exit(struct solo_dev *solo_dev) | |||
1822 | { | 1763 | { |
1823 | int i; | 1764 | int i; |
1824 | 1765 | ||
1825 | solo_irq_off(solo_dev, SOLO_IRQ_MOTION); | ||
1826 | |||
1827 | for (i = 0; i < solo_dev->nr_chans; i++) | 1766 | for (i = 0; i < solo_dev->nr_chans; i++) |
1828 | solo_enc_free(solo_dev->v4l2_enc[i]); | 1767 | solo_enc_free(solo_dev->v4l2_enc[i]); |
1768 | |||
1769 | pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, | ||
1770 | solo_dev->vh_buf, solo_dev->vh_dma); | ||
1829 | } | 1771 | } |
diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 87f3c0452ca4..ba603ce1f746 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c | |||
@@ -1,6 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com | 2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> | 3 | * |
4 | * Original author: | ||
5 | * Ben Collins <bcollins@ubuntu.com> | ||
6 | * | ||
7 | * Additional work by: | ||
8 | * John Brooks <john.brooks@bluecherry.net> | ||
4 | * | 9 | * |
5 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -21,47 +26,43 @@ | |||
21 | #include <linux/module.h> | 26 | #include <linux/module.h> |
22 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
23 | #include <linux/freezer.h> | 28 | #include <linux/freezer.h> |
29 | |||
24 | #include <media/v4l2-ioctl.h> | 30 | #include <media/v4l2-ioctl.h> |
25 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
26 | #include <media/videobuf-dma-sg.h> | 32 | #include <media/videobuf-dma-contig.h> |
33 | |||
27 | #include "solo6x10.h" | 34 | #include "solo6x10.h" |
28 | #include "tw28.h" | 35 | #include "tw28.h" |
29 | 36 | ||
30 | #define SOLO_HW_BPL 2048 | ||
31 | #define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED | 37 | #define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED |
32 | 38 | ||
33 | /* Image size is two fields, SOLO_HW_BPL is one horizontal line */ | 39 | /* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */ |
40 | #define SOLO_HW_BPL 2048 | ||
34 | #define solo_vlines(__solo) (__solo->video_vsize * 2) | 41 | #define solo_vlines(__solo) (__solo->video_vsize * 2) |
35 | #define solo_image_size(__solo) (solo_bytesperline(__solo) * \ | 42 | #define solo_image_size(__solo) (solo_bytesperline(__solo) * \ |
36 | solo_vlines(__solo)) | 43 | solo_vlines(__solo)) |
37 | #define solo_bytesperline(__solo) (__solo->video_hsize * 2) | 44 | #define solo_bytesperline(__solo) (__solo->video_hsize * 2) |
38 | 45 | ||
39 | #define MIN_VID_BUFFERS 4 | 46 | #define MIN_VID_BUFFERS 2 |
40 | 47 | ||
41 | /* Simple file handle */ | 48 | /* Simple file handle */ |
42 | struct solo_filehandle { | 49 | struct solo_filehandle { |
43 | struct solo_dev *solo_dev; | 50 | struct solo_dev *solo_dev; |
44 | struct videobuf_queue vidq; | 51 | struct videobuf_queue vidq; |
45 | struct task_struct *kthread; | 52 | struct task_struct *kthread; |
46 | spinlock_t slock; | 53 | spinlock_t slock; |
47 | int old_write; | 54 | int old_write; |
48 | struct list_head vidq_active; | 55 | struct list_head vidq_active; |
49 | struct p2m_desc desc[SOLO_NR_P2M_DESC]; | ||
50 | int desc_idx; | ||
51 | }; | 56 | }; |
52 | 57 | ||
53 | unsigned video_nr = -1; | 58 | static inline void erase_on(struct solo_dev *solo_dev) |
54 | module_param(video_nr, uint, 0644); | ||
55 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); | ||
56 | |||
57 | static void erase_on(struct solo_dev *solo_dev) | ||
58 | { | 59 | { |
59 | solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); | 60 | solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); |
60 | solo_dev->erasing = 1; | 61 | solo_dev->erasing = 1; |
61 | solo_dev->frame_blank = 0; | 62 | solo_dev->frame_blank = 0; |
62 | } | 63 | } |
63 | 64 | ||
64 | static int erase_off(struct solo_dev *solo_dev) | 65 | static inline int erase_off(struct solo_dev *solo_dev) |
65 | { | 66 | { |
66 | if (!solo_dev->erasing) | 67 | if (!solo_dev->erasing) |
67 | return 0; | 68 | return 0; |
@@ -78,8 +79,7 @@ static int erase_off(struct solo_dev *solo_dev) | |||
78 | 79 | ||
79 | void solo_video_in_isr(struct solo_dev *solo_dev) | 80 | void solo_video_in_isr(struct solo_dev *solo_dev) |
80 | { | 81 | { |
81 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN); | 82 | wake_up_interruptible_all(&solo_dev->disp_thread_wait); |
82 | wake_up_interruptible(&solo_dev->disp_thread_wait); | ||
83 | } | 83 | } |
84 | 84 | ||
85 | static void solo_win_setup(struct solo_dev *solo_dev, u8 ch, | 85 | static void solo_win_setup(struct solo_dev *solo_dev, u8 ch, |
@@ -202,165 +202,61 @@ static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch) | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | static void disp_reset_desc(struct solo_filehandle *fh) | ||
206 | { | ||
207 | /* We use desc mode, which ignores desc 0 */ | ||
208 | memset(fh->desc, 0, sizeof(*fh->desc)); | ||
209 | fh->desc_idx = 1; | ||
210 | } | ||
211 | |||
212 | static int disp_flush_descs(struct solo_filehandle *fh) | ||
213 | { | ||
214 | int ret; | ||
215 | |||
216 | if (!fh->desc_idx) | ||
217 | return 0; | ||
218 | |||
219 | ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP, | ||
220 | fh->desc, fh->desc_idx); | ||
221 | disp_reset_desc(fh); | ||
222 | |||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr, | ||
227 | u32 ext_addr, int size, int repeat, int ext_size) | ||
228 | { | ||
229 | if (fh->desc_idx >= SOLO_NR_P2M_DESC) { | ||
230 | int ret = disp_flush_descs(fh); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr, | ||
236 | size, repeat, ext_size); | ||
237 | fh->desc_idx++; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void solo_fillbuf(struct solo_filehandle *fh, | 205 | static void solo_fillbuf(struct solo_filehandle *fh, |
243 | struct videobuf_buffer *vb) | 206 | struct videobuf_buffer *vb) |
244 | { | 207 | { |
245 | struct solo_dev *solo_dev = fh->solo_dev; | 208 | struct solo_dev *solo_dev = fh->solo_dev; |
246 | struct videobuf_dmabuf *vbuf; | 209 | dma_addr_t vbuf; |
247 | unsigned int fdma_addr; | 210 | unsigned int fdma_addr; |
248 | int error = 1; | 211 | int error = -1; |
249 | int i; | 212 | int i; |
250 | struct scatterlist *sg; | ||
251 | dma_addr_t sg_dma; | ||
252 | int sg_size_left; | ||
253 | 213 | ||
254 | vbuf = videobuf_to_dma(vb); | 214 | vbuf = videobuf_to_dma_contig(vb); |
255 | if (!vbuf) | 215 | if (!vbuf) |
256 | goto finish_buf; | 216 | goto finish_buf; |
257 | 217 | ||
258 | if (erase_off(solo_dev)) { | 218 | if (erase_off(solo_dev)) { |
259 | int i; | 219 | void *p = videobuf_queue_to_vaddr(&fh->vidq, vb); |
260 | 220 | int image_size = solo_image_size(solo_dev); | |
261 | /* Just blit to the entire sg list, ignoring size */ | 221 | for (i = 0; i < image_size; i += 2) { |
262 | for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { | 222 | ((u8 *)p)[i] = 0x80; |
263 | void *p = sg_virt(sg); | 223 | ((u8 *)p)[i + 1] = 0x00; |
264 | size_t len = sg_dma_len(sg); | ||
265 | |||
266 | for (i = 0; i < len; i += 2) { | ||
267 | ((u8 *)p)[i] = 0x80; | ||
268 | ((u8 *)p)[i + 1] = 0x00; | ||
269 | } | ||
270 | } | 224 | } |
271 | |||
272 | error = 0; | 225 | error = 0; |
273 | goto finish_buf; | 226 | } else { |
274 | } | 227 | fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write * |
275 | 228 | (SOLO_HW_BPL * solo_vlines(solo_dev))); | |
276 | disp_reset_desc(fh); | ||
277 | sg = vbuf->sglist; | ||
278 | sg_dma = sg_dma_address(sg); | ||
279 | sg_size_left = sg_dma_len(sg); | ||
280 | |||
281 | fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write * | ||
282 | (SOLO_HW_BPL * solo_vlines(solo_dev))); | ||
283 | |||
284 | for (i = 0; i < solo_vlines(solo_dev); i++) { | ||
285 | int line_len = solo_bytesperline(solo_dev); | ||
286 | int lines; | ||
287 | |||
288 | if (!sg_size_left) { | ||
289 | sg = sg_next(sg); | ||
290 | if (sg == NULL) | ||
291 | goto finish_buf; | ||
292 | sg_dma = sg_dma_address(sg); | ||
293 | sg_size_left = sg_dma_len(sg); | ||
294 | } | ||
295 | |||
296 | /* No room for an entire line, so chunk it up */ | ||
297 | if (sg_size_left < line_len) { | ||
298 | int this_addr = fdma_addr; | ||
299 | |||
300 | while (line_len > 0) { | ||
301 | int this_write; | ||
302 | |||
303 | if (!sg_size_left) { | ||
304 | sg = sg_next(sg); | ||
305 | if (sg == NULL) | ||
306 | goto finish_buf; | ||
307 | sg_dma = sg_dma_address(sg); | ||
308 | sg_size_left = sg_dma_len(sg); | ||
309 | } | ||
310 | |||
311 | this_write = min(sg_size_left, line_len); | ||
312 | |||
313 | if (disp_push_desc(fh, sg_dma, this_addr, | ||
314 | this_write, 0, 0)) | ||
315 | goto finish_buf; | ||
316 | |||
317 | line_len -= this_write; | ||
318 | sg_size_left -= this_write; | ||
319 | sg_dma += this_write; | ||
320 | this_addr += this_write; | ||
321 | } | ||
322 | |||
323 | fdma_addr += SOLO_HW_BPL; | ||
324 | continue; | ||
325 | } | ||
326 | |||
327 | /* Shove as many lines into a repeating descriptor as possible */ | ||
328 | lines = min(sg_size_left / line_len, | ||
329 | solo_vlines(solo_dev) - i); | ||
330 | |||
331 | if (disp_push_desc(fh, sg_dma, fdma_addr, line_len, | ||
332 | lines - 1, SOLO_HW_BPL)) | ||
333 | goto finish_buf; | ||
334 | 229 | ||
335 | i += lines - 1; | 230 | error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr, |
336 | fdma_addr += SOLO_HW_BPL * lines; | 231 | solo_bytesperline(solo_dev), |
337 | sg_dma += lines * line_len; | 232 | solo_vlines(solo_dev), SOLO_HW_BPL); |
338 | sg_size_left -= lines * line_len; | ||
339 | } | 233 | } |
340 | 234 | ||
341 | error = disp_flush_descs(fh); | ||
342 | |||
343 | finish_buf: | 235 | finish_buf: |
344 | if (error) { | 236 | if (error) { |
345 | vb->state = VIDEOBUF_ERROR; | 237 | vb->state = VIDEOBUF_ERROR; |
346 | } else { | 238 | } else { |
347 | vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev); | ||
348 | vb->state = VIDEOBUF_DONE; | 239 | vb->state = VIDEOBUF_DONE; |
349 | vb->field_count++; | 240 | vb->field_count++; |
350 | do_gettimeofday(&vb->ts); | ||
351 | } | 241 | } |
352 | 242 | ||
353 | wake_up(&vb->done); | 243 | wake_up(&vb->done); |
354 | |||
355 | return; | ||
356 | } | 244 | } |
357 | 245 | ||
358 | static void solo_thread_try(struct solo_filehandle *fh) | 246 | static void solo_thread_try(struct solo_filehandle *fh) |
359 | { | 247 | { |
360 | struct videobuf_buffer *vb; | 248 | struct videobuf_buffer *vb; |
361 | unsigned int cur_write; | ||
362 | 249 | ||
250 | /* Only "break" from this loop if slock is held, otherwise | ||
251 | * just return. */ | ||
363 | for (;;) { | 252 | for (;;) { |
253 | unsigned int cur_write; | ||
254 | |||
255 | cur_write = SOLO_VI_STATUS0_PAGE( | ||
256 | solo_reg_read(fh->solo_dev, SOLO_VI_STATUS0)); | ||
257 | if (cur_write == fh->old_write) | ||
258 | return; | ||
259 | |||
364 | spin_lock(&fh->slock); | 260 | spin_lock(&fh->slock); |
365 | 261 | ||
366 | if (list_empty(&fh->vidq_active)) | 262 | if (list_empty(&fh->vidq_active)) |
@@ -372,13 +268,9 @@ static void solo_thread_try(struct solo_filehandle *fh) | |||
372 | if (!waitqueue_active(&vb->done)) | 268 | if (!waitqueue_active(&vb->done)) |
373 | break; | 269 | break; |
374 | 270 | ||
375 | cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev, | ||
376 | SOLO_VI_STATUS0)); | ||
377 | if (cur_write == fh->old_write) | ||
378 | break; | ||
379 | |||
380 | fh->old_write = cur_write; | 271 | fh->old_write = cur_write; |
381 | list_del(&vb->queue); | 272 | list_del(&vb->queue); |
273 | vb->state = VIDEOBUF_ACTIVE; | ||
382 | 274 | ||
383 | spin_unlock(&fh->slock); | 275 | spin_unlock(&fh->slock); |
384 | 276 | ||
@@ -413,17 +305,31 @@ static int solo_thread(void *data) | |||
413 | 305 | ||
414 | static int solo_start_thread(struct solo_filehandle *fh) | 306 | static int solo_start_thread(struct solo_filehandle *fh) |
415 | { | 307 | { |
308 | int ret = 0; | ||
309 | |||
310 | if (atomic_inc_return(&fh->solo_dev->disp_users) == 1) | ||
311 | solo_irq_on(fh->solo_dev, SOLO_IRQ_VIDEO_IN); | ||
312 | |||
416 | fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp"); | 313 | fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp"); |
417 | 314 | ||
418 | return PTR_RET(fh->kthread); | 315 | if (IS_ERR(fh->kthread)) { |
316 | ret = PTR_ERR(fh->kthread); | ||
317 | fh->kthread = NULL; | ||
318 | } | ||
319 | |||
320 | return ret; | ||
419 | } | 321 | } |
420 | 322 | ||
421 | static void solo_stop_thread(struct solo_filehandle *fh) | 323 | static void solo_stop_thread(struct solo_filehandle *fh) |
422 | { | 324 | { |
423 | if (fh->kthread) { | 325 | if (!fh->kthread) |
424 | kthread_stop(fh->kthread); | 326 | return; |
425 | fh->kthread = NULL; | 327 | |
426 | } | 328 | kthread_stop(fh->kthread); |
329 | fh->kthread = NULL; | ||
330 | |||
331 | if (atomic_dec_return(&fh->solo_dev->disp_users) == 0) | ||
332 | solo_irq_off(fh->solo_dev, SOLO_IRQ_VIDEO_IN); | ||
427 | } | 333 | } |
428 | 334 | ||
429 | static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, | 335 | static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, |
@@ -459,9 +365,7 @@ static int solo_buf_prepare(struct videobuf_queue *vq, | |||
459 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | 365 | if (vb->state == VIDEOBUF_NEEDS_INIT) { |
460 | int rc = videobuf_iolock(vq, vb, NULL); | 366 | int rc = videobuf_iolock(vq, vb, NULL); |
461 | if (rc < 0) { | 367 | if (rc < 0) { |
462 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | 368 | videobuf_dma_contig_free(vq, vb); |
463 | videobuf_dma_unmap(vq->dev, dma); | ||
464 | videobuf_dma_free(dma); | ||
465 | vb->state = VIDEOBUF_NEEDS_INIT; | 369 | vb->state = VIDEOBUF_NEEDS_INIT; |
466 | return rc; | 370 | return rc; |
467 | } | 371 | } |
@@ -485,14 +389,11 @@ static void solo_buf_queue(struct videobuf_queue *vq, | |||
485 | static void solo_buf_release(struct videobuf_queue *vq, | 389 | static void solo_buf_release(struct videobuf_queue *vq, |
486 | struct videobuf_buffer *vb) | 390 | struct videobuf_buffer *vb) |
487 | { | 391 | { |
488 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | 392 | videobuf_dma_contig_free(vq, vb); |
489 | |||
490 | videobuf_dma_unmap(vq->dev, dma); | ||
491 | videobuf_dma_free(dma); | ||
492 | vb->state = VIDEOBUF_NEEDS_INIT; | 393 | vb->state = VIDEOBUF_NEEDS_INIT; |
493 | } | 394 | } |
494 | 395 | ||
495 | static struct videobuf_queue_ops solo_video_qops = { | 396 | static const struct videobuf_queue_ops solo_video_qops = { |
496 | .buf_setup = solo_buf_setup, | 397 | .buf_setup = solo_buf_setup, |
497 | .buf_prepare = solo_buf_prepare, | 398 | .buf_prepare = solo_buf_prepare, |
498 | .buf_queue = solo_buf_queue, | 399 | .buf_queue = solo_buf_queue, |
@@ -535,12 +436,12 @@ static int solo_v4l2_open(struct file *file) | |||
535 | return ret; | 436 | return ret; |
536 | } | 437 | } |
537 | 438 | ||
538 | videobuf_queue_sg_init(&fh->vidq, &solo_video_qops, | 439 | videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops, |
539 | &solo_dev->pdev->dev, &fh->slock, | 440 | &solo_dev->pdev->dev, &fh->slock, |
540 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 441 | V4L2_BUF_TYPE_VIDEO_CAPTURE, |
541 | SOLO_DISP_PIX_FIELD, | 442 | SOLO_DISP_PIX_FIELD, |
542 | sizeof(struct videobuf_buffer), fh, NULL); | 443 | sizeof(struct videobuf_buffer), |
543 | 444 | fh, NULL); | |
544 | return 0; | 445 | return 0; |
545 | } | 446 | } |
546 | 447 | ||
@@ -557,9 +458,11 @@ static int solo_v4l2_release(struct file *file) | |||
557 | { | 458 | { |
558 | struct solo_filehandle *fh = file->private_data; | 459 | struct solo_filehandle *fh = file->private_data; |
559 | 460 | ||
461 | solo_stop_thread(fh); | ||
462 | |||
560 | videobuf_stop(&fh->vidq); | 463 | videobuf_stop(&fh->vidq); |
561 | videobuf_mmap_free(&fh->vidq); | 464 | videobuf_mmap_free(&fh->vidq); |
562 | solo_stop_thread(fh); | 465 | |
563 | kfree(fh); | 466 | kfree(fh); |
564 | 467 | ||
565 | return 0; | 468 | return 0; |
@@ -585,12 +488,12 @@ static int solo_querycap(struct file *file, void *priv, | |||
585 | static int solo_enum_ext_input(struct solo_dev *solo_dev, | 488 | static int solo_enum_ext_input(struct solo_dev *solo_dev, |
586 | struct v4l2_input *input) | 489 | struct v4l2_input *input) |
587 | { | 490 | { |
588 | static const char *dispnames_1[] = { "4UP" }; | 491 | static const char * const dispnames_1[] = { "4UP" }; |
589 | static const char *dispnames_2[] = { "4UP-1", "4UP-2" }; | 492 | static const char * const dispnames_2[] = { "4UP-1", "4UP-2" }; |
590 | static const char *dispnames_5[] = { | 493 | static const char * const dispnames_5[] = { |
591 | "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" | 494 | "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" |
592 | }; | 495 | }; |
593 | const char **dispnames; | 496 | const char * const *dispnames; |
594 | 497 | ||
595 | if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) | 498 | if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) |
596 | return -EINVAL; | 499 | return -EINVAL; |
@@ -640,8 +543,14 @@ static int solo_enum_input(struct file *file, void *priv, | |||
640 | static int solo_set_input(struct file *file, void *priv, unsigned int index) | 543 | static int solo_set_input(struct file *file, void *priv, unsigned int index) |
641 | { | 544 | { |
642 | struct solo_filehandle *fh = priv; | 545 | struct solo_filehandle *fh = priv; |
546 | int ret = solo_v4l2_set_ch(fh->solo_dev, index); | ||
547 | |||
548 | if (!ret) { | ||
549 | while (erase_off(fh->solo_dev)) | ||
550 | /* Do nothing */; | ||
551 | } | ||
643 | 552 | ||
644 | return solo_v4l2_set_ch(fh->solo_dev, index); | 553 | return ret; |
645 | } | 554 | } |
646 | 555 | ||
647 | static int solo_get_input(struct file *file, void *priv, unsigned int *index) | 556 | static int solo_get_input(struct file *file, void *priv, unsigned int *index) |
@@ -732,7 +641,8 @@ static int solo_reqbufs(struct file *file, void *priv, | |||
732 | return videobuf_reqbufs(&fh->vidq, req); | 641 | return videobuf_reqbufs(&fh->vidq, req); |
733 | } | 642 | } |
734 | 643 | ||
735 | static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) | 644 | static int solo_querybuf(struct file *file, void *priv, |
645 | struct v4l2_buffer *buf) | ||
736 | { | 646 | { |
737 | struct solo_filehandle *fh = priv; | 647 | struct solo_filehandle *fh = priv; |
738 | 648 | ||
@@ -901,11 +811,12 @@ static struct video_device solo_v4l2_template = { | |||
901 | .current_norm = V4L2_STD_NTSC_M, | 811 | .current_norm = V4L2_STD_NTSC_M, |
902 | }; | 812 | }; |
903 | 813 | ||
904 | int solo_v4l2_init(struct solo_dev *solo_dev) | 814 | int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) |
905 | { | 815 | { |
906 | int ret; | 816 | int ret; |
907 | int i; | 817 | int i; |
908 | 818 | ||
819 | atomic_set(&solo_dev->disp_users, 0); | ||
909 | init_waitqueue_head(&solo_dev->disp_thread_wait); | 820 | init_waitqueue_head(&solo_dev->disp_thread_wait); |
910 | 821 | ||
911 | solo_dev->vfd = video_device_alloc(); | 822 | solo_dev->vfd = video_device_alloc(); |
@@ -915,7 +826,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev) | |||
915 | *solo_dev->vfd = solo_v4l2_template; | 826 | *solo_dev->vfd = solo_v4l2_template; |
916 | solo_dev->vfd->parent = &solo_dev->pdev->dev; | 827 | solo_dev->vfd->parent = &solo_dev->pdev->dev; |
917 | 828 | ||
918 | ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr); | 829 | ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); |
919 | if (ret < 0) { | 830 | if (ret < 0) { |
920 | video_device_release(solo_dev->vfd); | 831 | video_device_release(solo_dev->vfd); |
921 | solo_dev->vfd = NULL; | 832 | solo_dev->vfd = NULL; |
@@ -927,35 +838,30 @@ int solo_v4l2_init(struct solo_dev *solo_dev) | |||
927 | snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", | 838 | snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", |
928 | SOLO6X10_NAME, solo_dev->vfd->num); | 839 | SOLO6X10_NAME, solo_dev->vfd->num); |
929 | 840 | ||
930 | if (video_nr != -1) | 841 | dev_info(&solo_dev->pdev->dev, |
931 | video_nr++; | 842 | "Display as /dev/video%d with %d inputs (%d extended)\n", |
932 | 843 | solo_dev->vfd->num, solo_dev->nr_chans, solo_dev->nr_ext); | |
933 | dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with " | ||
934 | "%d inputs (%d extended)\n", solo_dev->vfd->num, | ||
935 | solo_dev->nr_chans, solo_dev->nr_ext); | ||
936 | 844 | ||
937 | /* Cycle all the channels and clear */ | 845 | /* Cycle all the channels and clear */ |
938 | for (i = 0; i < solo_dev->nr_chans; i++) { | 846 | for (i = 0; i < solo_dev->nr_chans; i++) { |
939 | solo_v4l2_set_ch(solo_dev, i); | 847 | solo_v4l2_set_ch(solo_dev, i); |
940 | while (erase_off(solo_dev)) | 848 | while (erase_off(solo_dev)) |
941 | ;/* Do nothing */ | 849 | /* Do nothing */; |
942 | } | 850 | } |
943 | 851 | ||
944 | /* Set the default display channel */ | 852 | /* Set the default display channel */ |
945 | solo_v4l2_set_ch(solo_dev, 0); | 853 | solo_v4l2_set_ch(solo_dev, 0); |
946 | while (erase_off(solo_dev)) | 854 | while (erase_off(solo_dev)) |
947 | ;/* Do nothing */ | 855 | /* Do nothing */; |
948 | |||
949 | solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); | ||
950 | 856 | ||
951 | return 0; | 857 | return 0; |
952 | } | 858 | } |
953 | 859 | ||
954 | void solo_v4l2_exit(struct solo_dev *solo_dev) | 860 | void solo_v4l2_exit(struct solo_dev *solo_dev) |
955 | { | 861 | { |
956 | solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); | 862 | if (solo_dev->vfd == NULL) |
957 | if (solo_dev->vfd) { | 863 | return; |
958 | video_unregister_device(solo_dev->vfd); | 864 | |
959 | solo_dev->vfd = NULL; | 865 | video_unregister_device(solo_dev->vfd); |
960 | } | 866 | solo_dev->vfd = NULL; |
961 | } | 867 | } |