aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/solo6x10
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/solo6x10')
-rw-r--r--drivers/staging/solo6x10/Kconfig8
-rw-r--r--drivers/staging/solo6x10/Makefile3
-rw-r--r--drivers/staging/solo6x10/TODO24
-rw-r--r--drivers/staging/solo6x10/core.c332
-rw-r--r--drivers/staging/solo6x10/disp.c270
-rw-r--r--drivers/staging/solo6x10/enc.c238
-rw-r--r--drivers/staging/solo6x10/g723.c399
-rw-r--r--drivers/staging/solo6x10/gpio.c102
-rw-r--r--drivers/staging/solo6x10/i2c.c330
-rw-r--r--drivers/staging/solo6x10/jpeg.h105
-rw-r--r--drivers/staging/solo6x10/osd-font.h154
-rw-r--r--drivers/staging/solo6x10/p2m.c306
-rw-r--r--drivers/staging/solo6x10/registers.h637
-rw-r--r--drivers/staging/solo6x10/solo6x10.h336
-rw-r--r--drivers/staging/solo6x10/tw28.c821
-rw-r--r--drivers/staging/solo6x10/tw28.h63
-rw-r--r--drivers/staging/solo6x10/v4l2-enc.c1825
-rw-r--r--drivers/staging/solo6x10/v4l2.c964
18 files changed, 6917 insertions, 0 deletions
diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig
new file mode 100644
index 00000000000..03dcac4ea4d
--- /dev/null
+++ b/drivers/staging/solo6x10/Kconfig
@@ -0,0 +1,8 @@
1config SOLO6X10
2 tristate "Softlogic 6x10 MPEG codec cards"
3 depends on PCI && VIDEO_DEV && SND && I2C
4 select VIDEOBUF_DMA_SG
5 select SND_PCM
6 ---help---
7 This driver supports the Softlogic based MPEG-4 and h.264 codec
8 codec cards.
diff --git a/drivers/staging/solo6x10/Makefile b/drivers/staging/solo6x10/Makefile
new file mode 100644
index 00000000000..72816cf1670
--- /dev/null
+++ b/drivers/staging/solo6x10/Makefile
@@ -0,0 +1,3 @@
1solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o
2
3obj-$(CONFIG_SOLO6X10) := solo6x10.o
diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/solo6x10/TODO
new file mode 100644
index 00000000000..7e6c4fa130d
--- /dev/null
+++ b/drivers/staging/solo6x10/TODO
@@ -0,0 +1,24 @@
1TODO (staging => main):
2
3 * Motion detection flags need to be moved to v4l2
4 * Some private CIDs need to be moved to v4l2
5
6TODO (general):
7
8 * encoder on/off controls
9 * mpeg cid bitrate mode (vbr/cbr)
10 * mpeg cid bitrate/bitrate-peak
11 * mpeg encode of user data
12 * mpeg decode of user data
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
23Plase send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc Ben Collins
24<bcollins@bluecherry.net>
diff --git a/drivers/staging/solo6x10/core.c b/drivers/staging/solo6x10/core.c
new file mode 100644
index 00000000000..f974f6412ad
--- /dev/null
+++ b/drivers/staging/solo6x10/core.c
@@ -0,0 +1,332 @@
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#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/pci.h>
23#include <linux/interrupt.h>
24#include <linux/slab.h>
25#include <linux/videodev2.h>
26#include "solo6x10.h"
27#include "tw28.h"
28
29MODULE_DESCRIPTION("Softlogic 6x10 MP4/H.264 Encoder/Decoder V4L2/ALSA Driver");
30MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
31MODULE_VERSION(SOLO6X10_VERSION);
32MODULE_LICENSE("GPL");
33
34void solo_irq_on(struct solo_dev *solo_dev, u32 mask)
35{
36 solo_dev->irq_mask |= mask;
37 solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
38}
39
40void solo_irq_off(struct solo_dev *solo_dev, u32 mask)
41{
42 solo_dev->irq_mask &= ~mask;
43 solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
44}
45
46/* XXX We should check the return value of the sub-device ISR's */
47static irqreturn_t solo_isr(int irq, void *data)
48{
49 struct solo_dev *solo_dev = data;
50 u32 status;
51 int i;
52
53 status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
54 if (!status)
55 return IRQ_NONE;
56
57 if (status & ~solo_dev->irq_mask) {
58 solo_reg_write(solo_dev, SOLO_IRQ_STAT,
59 status & ~solo_dev->irq_mask);
60 status &= solo_dev->irq_mask;
61 }
62
63 if (status & SOLO_IRQ_PCI_ERR) {
64 u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
65 solo_p2m_error_isr(solo_dev, err);
66 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR);
67 }
68
69 for (i = 0; i < SOLO_NR_P2M; i++)
70 if (status & SOLO_IRQ_P2M(i))
71 solo_p2m_isr(solo_dev, i);
72
73 if (status & SOLO_IRQ_IIC)
74 solo_i2c_isr(solo_dev);
75
76 if (status & SOLO_IRQ_VIDEO_IN)
77 solo_video_in_isr(solo_dev);
78
79 /* Call this first so enc gets detected flag set */
80 if (status & SOLO_IRQ_MOTION)
81 solo_motion_isr(solo_dev);
82
83 if (status & SOLO_IRQ_ENCODER)
84 solo_enc_v4l2_isr(solo_dev);
85
86 if (status & SOLO_IRQ_G723)
87 solo_g723_isr(solo_dev);
88
89 return IRQ_HANDLED;
90}
91
92static void free_solo_dev(struct solo_dev *solo_dev)
93{
94 struct pci_dev *pdev;
95
96 if (!solo_dev)
97 return;
98
99 pdev = solo_dev->pdev;
100
101 /* If we never initialized the PCI device, then nothing else
102 * below here needs cleanup */
103 if (!pdev) {
104 kfree(solo_dev);
105 return;
106 }
107
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) {
120 solo_irq_off(solo_dev, ~0);
121 pci_iounmap(pdev, solo_dev->reg_base);
122 free_irq(pdev->irq, solo_dev);
123 }
124
125 pci_release_regions(pdev);
126 pci_disable_device(pdev);
127 pci_set_drvdata(pdev, NULL);
128
129 kfree(solo_dev);
130}
131
132static int __devinit solo_pci_probe(struct pci_dev *pdev,
133 const struct pci_device_id *id)
134{
135 struct solo_dev *solo_dev;
136 int ret;
137 int sdram;
138 u8 chip_id;
139 u32 reg;
140
141 solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
142 if (solo_dev == NULL)
143 return -ENOMEM;
144
145 solo_dev->pdev = pdev;
146 spin_lock_init(&solo_dev->reg_io_lock);
147 pci_set_drvdata(pdev, solo_dev);
148
149 ret = pci_enable_device(pdev);
150 if (ret)
151 goto fail_probe;
152
153 pci_set_master(pdev);
154
155 ret = pci_request_regions(pdev, SOLO6X10_NAME);
156 if (ret)
157 goto fail_probe;
158
159 solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
160 if (solo_dev->reg_base == NULL) {
161 ret = -ENOMEM;
162 goto fail_probe;
163 }
164
165 chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
166 SOLO_CHIP_ID_MASK;
167 switch (chip_id) {
168 case 7:
169 solo_dev->nr_chans = 16;
170 solo_dev->nr_ext = 5;
171 break;
172 case 6:
173 solo_dev->nr_chans = 8;
174 solo_dev->nr_ext = 2;
175 break;
176 default:
177 dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
178 "defaulting to 4 channels\n",
179 chip_id);
180 case 5:
181 solo_dev->nr_chans = 4;
182 solo_dev->nr_ext = 1;
183 }
184
185 solo_dev->flags = id->driver_data;
186
187 /* Disable all interrupts to start */
188 solo_irq_off(solo_dev, ~0);
189
190 reg = SOLO_SYS_CFG_SDRAM64BIT;
191 /* Initial global settings */
192 if (!(solo_dev->flags & FLAGS_6110))
193 reg |= SOLO6010_SYS_CFG_INPUTDIV(25) |
194 SOLO6010_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
195 SOLO6010_SYS_CFG_OUTDIV(3);
196 solo_reg_write(solo_dev, SOLO_SYS_CFG, reg);
197
198 if (solo_dev->flags & FLAGS_6110) {
199 u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
200 u32 pll_DIVQ;
201 u32 pll_DIVF;
202
203 if (sys_clock_MHz < 125) {
204 pll_DIVQ = 3;
205 pll_DIVF = (sys_clock_MHz * 4) / 3;
206 } else {
207 pll_DIVQ = 2;
208 pll_DIVF = (sys_clock_MHz * 2) / 3;
209 }
210
211 solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
212 SOLO6110_PLL_RANGE_5_10MHZ |
213 SOLO6110_PLL_DIVR(9) |
214 SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) |
215 SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN);
216 mdelay(1); // PLL Locking time (1ms)
217
218 solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */
219 } else
220 solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */
221
222 solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
223
224 /* PLL locking time of 1ms */
225 mdelay(1);
226
227 ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
228 solo_dev);
229 if (ret)
230 goto fail_probe;
231
232 /* Handle this from the start */
233 solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
234
235 ret = solo_i2c_init(solo_dev);
236 if (ret)
237 goto fail_probe;
238
239 /* Setup the DMA engine */
240 sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
241 solo_reg_write(solo_dev, SOLO_DMA_CTRL,
242 SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
243 SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
244 SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
245 SOLO_DMA_CTRL_READ_CLK_SELECT |
246 SOLO_DMA_CTRL_LATENCY(1));
247
248 ret = solo_p2m_init(solo_dev);
249 if (ret)
250 goto fail_probe;
251
252 ret = solo_disp_init(solo_dev);
253 if (ret)
254 goto fail_probe;
255
256 ret = solo_gpio_init(solo_dev);
257 if (ret)
258 goto fail_probe;
259
260 ret = solo_tw28_init(solo_dev);
261 if (ret)
262 goto fail_probe;
263
264 ret = solo_v4l2_init(solo_dev);
265 if (ret)
266 goto fail_probe;
267
268 ret = solo_enc_init(solo_dev);
269 if (ret)
270 goto fail_probe;
271
272 ret = solo_enc_v4l2_init(solo_dev);
273 if (ret)
274 goto fail_probe;
275
276 ret = solo_g723_init(solo_dev);
277 if (ret)
278 goto fail_probe;
279
280 return 0;
281
282fail_probe:
283 free_solo_dev(solo_dev);
284 return ret;
285}
286
287static void __devexit solo_pci_remove(struct pci_dev *pdev)
288{
289 struct solo_dev *solo_dev = pci_get_drvdata(pdev);
290
291 free_solo_dev(solo_dev);
292}
293
294static struct pci_device_id solo_id_table[] = {
295 /* 6010 based cards */
296 {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
297 {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
298 .driver_data = FLAGS_6110},
299 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
300 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
301 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
302 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)},
303 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)},
304 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)},
305 /* 6110 based cards */
306 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)},
307 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)},
308 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)},
309 {0,}
310};
311
312MODULE_DEVICE_TABLE(pci, solo_id_table);
313
314static struct pci_driver solo_pci_driver = {
315 .name = SOLO6X10_NAME,
316 .id_table = solo_id_table,
317 .probe = solo_pci_probe,
318 .remove = solo_pci_remove,
319};
320
321static int __init solo_module_init(void)
322{
323 return pci_register_driver(&solo_pci_driver);
324}
325
326static void __exit solo_module_exit(void)
327{
328 pci_unregister_driver(&solo_pci_driver);
329}
330
331module_init(solo_module_init);
332module_exit(solo_module_exit);
diff --git a/drivers/staging/solo6x10/disp.c b/drivers/staging/solo6x10/disp.c
new file mode 100644
index 00000000000..884c0eb757c
--- /dev/null
+++ b/drivers/staging/solo6x10/disp.c
@@ -0,0 +1,270 @@
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#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/videodev2.h>
23#include <media/v4l2-ioctl.h>
24#include "solo6x10.h"
25
26#define SOLO_VCLK_DELAY 3
27#define SOLO_PROGRESSIVE_VSIZE 1024
28
29#define SOLO_MOT_THRESH_W 64
30#define SOLO_MOT_THRESH_H 64
31#define SOLO_MOT_THRESH_SIZE 8192
32#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
33#define SOLO_MOT_FLAG_SIZE 512
34#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32)
35
36static unsigned video_type;
37module_param(video_type, uint, 0644);
38MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
39
40static void solo_vin_config(struct solo_dev *solo_dev)
41{
42 solo_dev->vin_hstart = 8;
43 solo_dev->vin_vstart = 2;
44
45 solo_reg_write(solo_dev, SOLO_SYS_VCLK,
46 SOLO_VCLK_SELECT(2) |
47 SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
48 SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
49 SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
50 SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
51 SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
52 SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
53 SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
54 SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
55
56 solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
57 SOLO_VI_H_START(solo_dev->vin_hstart) |
58 SOLO_VI_V_START(solo_dev->vin_vstart) |
59 SOLO_VI_V_STOP(solo_dev->vin_vstart +
60 solo_dev->video_vsize));
61
62 solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
63 SOLO_VI_H_START(solo_dev->vout_hstart) |
64 SOLO_VI_V_START(solo_dev->vout_vstart) |
65 SOLO_VI_V_STOP(solo_dev->vout_vstart +
66 solo_dev->video_vsize));
67
68 solo_reg_write(solo_dev, SOLO_VI_ACT_P,
69 SOLO_VI_H_START(0) |
70 SOLO_VI_V_START(1) |
71 SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
72
73 solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
74 SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
75
76 solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
77 solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
78
79 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
80 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
81 SOLO_VI_PB_USER_MODE);
82 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
83 SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
84 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
85 SOLO_VI_PB_VSTART(4) |
86 SOLO_VI_PB_VSTOP(4 + 240));
87 } else {
88 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
89 SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
90 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
91 SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
92 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
93 SOLO_VI_PB_VSTART(4) |
94 SOLO_VI_PB_VSTOP(4 + 288));
95 }
96 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
97 SOLO_VI_PB_HSTOP(16 + 720));
98}
99
100static void solo_disp_config(struct solo_dev *solo_dev)
101{
102 solo_dev->vout_hstart = 6;
103 solo_dev->vout_vstart = 8;
104
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,
113 solo_dev->video_type |
114 SOLO_VO_USER_COLOR_SET_NAV |
115 SOLO_VO_NA_COLOR_Y(0) |
116 SOLO_VO_NA_COLOR_CB(0) |
117 SOLO_VO_NA_COLOR_CR(0));
118
119 solo_reg_write(solo_dev, SOLO_VO_ACT_H,
120 SOLO_VO_H_START(solo_dev->vout_hstart) |
121 SOLO_VO_H_STOP(solo_dev->vout_hstart +
122 solo_dev->video_hsize));
123
124 solo_reg_write(solo_dev, SOLO_VO_ACT_V,
125 SOLO_VO_V_START(solo_dev->vout_vstart) |
126 SOLO_VO_V_STOP(solo_dev->vout_vstart +
127 solo_dev->video_vsize));
128
129 solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
130 SOLO_VO_H_LEN(solo_dev->video_hsize) |
131 SOLO_VO_V_LEN(solo_dev->video_vsize));
132
133 solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
134
135 solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
136 SOLO_VO_DISP_ERASE_COUNT(8) |
137 SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
138
139 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
140
141 /* Enable channels we support */
142 solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
143
144 /* Disable the watchdog */
145 solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
146}
147
148static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
149 u16 val, int reg_size)
150{
151 u16 buf[64];
152 int i;
153 int ret = 0;
154
155 for (i = 0; i < sizeof(buf) >> 1; i++)
156 buf[i] = val;
157
158 for (i = 0; i < reg_size; i += sizeof(buf))
159 ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
160 SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
161 sizeof(buf));
162
163 return ret;
164}
165
166void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
167{
168 if (ch > solo_dev->nr_chans)
169 return;
170
171 solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
172 (ch * SOLO_MOT_THRESH_SIZE * 2),
173 val, SOLO_MOT_THRESH_REAL);
174}
175
176/* 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
178 * spec says. However, this code (take from rdk) has some mystery 8k
179 * block right after the flag area, before the first thresh table. */
180static void solo_motion_config(struct solo_dev *solo_dev)
181{
182 int i;
183
184 for (i = 0; i < solo_dev->nr_chans; i++) {
185 /* Clear motion flag area */
186 solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
187 SOLO_MOT_FLAG_SIZE);
188
189 /* Clear working cache table */
190 solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
191 SOLO_MOT_THRESH_SIZE +
192 (i * SOLO_MOT_THRESH_SIZE * 2),
193 0x0000, SOLO_MOT_THRESH_REAL);
194
195 /* Set default threshold table */
196 solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
197 }
198
199 /* Default motion settings */
200 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
201 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
202 solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
203 SOLO_VI_MOTION_FRAME_COUNT(3) |
204 SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
205 | /* SOLO_VI_MOTION_INTR_START_STOP | */
206 SOLO_VI_MOTION_SAMPLE_COUNT(10));
207
208 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
209 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
210}
211
212int solo_disp_init(struct solo_dev *solo_dev)
213{
214 int i;
215
216 solo_dev->video_hsize = 704;
217 if (video_type == 0) {
218 solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
219 solo_dev->video_vsize = 240;
220 solo_dev->fps = 30;
221 } else {
222 solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
223 solo_dev->video_vsize = 288;
224 solo_dev->fps = 25;
225 }
226
227 solo_vin_config(solo_dev);
228 solo_motion_config(solo_dev);
229 solo_disp_config(solo_dev);
230
231 for (i = 0; i < solo_dev->nr_chans; i++)
232 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
233
234 return 0;
235}
236
237void solo_disp_exit(struct solo_dev *solo_dev)
238{
239 int i;
240
241 solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
242
243 solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
244 solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
245 solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
246
247 for (i = 0; i < solo_dev->nr_chans; i++) {
248 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
249 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
250 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
251 }
252
253 /* Set default border */
254 for (i = 0; i < 5; i++)
255 solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
256
257 for (i = 0; i < 5; i++)
258 solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
259
260 solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
261 solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
262
263 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
264 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
265 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
266
267 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
268 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
269 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
270}
diff --git a/drivers/staging/solo6x10/enc.c b/drivers/staging/solo6x10/enc.c
new file mode 100644
index 00000000000..de502599bb1
--- /dev/null
+++ b/drivers/staging/solo6x10/enc.c
@@ -0,0 +1,238 @@
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#include <linux/kernel.h>
21#include <linux/slab.h>
22#include "solo6x10.h"
23#include "osd-font.h"
24
25#define CAPTURE_MAX_BANDWIDTH 32 /* D1 4channel (D1 == 4) */
26#define OSG_BUFFER_SIZE 1024
27
28#define VI_PROG_HSIZE (1280 - 16)
29#define VI_PROG_VSIZE (1024 - 16)
30
31static void solo_capture_config(struct solo_dev *solo_dev)
32{
33 int i, j;
34 unsigned long height;
35 unsigned long width;
36 unsigned char *buf;
37
38 solo_reg_write(solo_dev, SOLO_CAP_BASE,
39 SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE *
40 solo_dev->nr_chans) |
41 SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
42 solo_reg_write(solo_dev, SOLO_CAP_BTW,
43 (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
44 SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH));
45
46 /* Set scale 1, 9 dimension */
47 width = solo_dev->video_hsize;
48 height = solo_dev->video_vsize;
49 solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
50 SOLO_DIM_H_MB_NUM(width / 16) |
51 SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
52 SOLO_DIM_V_MB_NUM_FIELD(height / 16));
53
54 /* Set scale 2, 10 dimension */
55 width = solo_dev->video_hsize / 2;
56 height = solo_dev->video_vsize;
57 solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
58 SOLO_DIM_H_MB_NUM(width / 16) |
59 SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
60 SOLO_DIM_V_MB_NUM_FIELD(height / 16));
61
62 /* Set scale 3, 11 dimension */
63 width = solo_dev->video_hsize / 2;
64 height = solo_dev->video_vsize / 2;
65 solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
66 SOLO_DIM_H_MB_NUM(width / 16) |
67 SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
68 SOLO_DIM_V_MB_NUM_FIELD(height / 16));
69
70 /* Set scale 4, 12 dimension */
71 width = solo_dev->video_hsize / 3;
72 height = solo_dev->video_vsize / 3;
73 solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
74 SOLO_DIM_H_MB_NUM(width / 16) |
75 SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
76 SOLO_DIM_V_MB_NUM_FIELD(height / 16));
77
78 /* Set scale 5, 13 dimension */
79 width = solo_dev->video_hsize / 4;
80 height = solo_dev->video_vsize / 2;
81 solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
82 SOLO_DIM_H_MB_NUM(width / 16) |
83 SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
84 SOLO_DIM_V_MB_NUM_FIELD(height / 16));
85
86 /* Progressive */
87 width = VI_PROG_HSIZE;
88 height = VI_PROG_VSIZE;
89 solo_reg_write(solo_dev, SOLO_DIM_PROG,
90 SOLO_DIM_H_MB_NUM(width / 16) |
91 SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
92 SOLO_DIM_V_MB_NUM_FIELD(height / 16));
93
94 /* Clear OSD */
95 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
96 solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16);
97 solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
98 0xF0 << 16 | 0x80 << 8 | 0x80);
99 solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
100
101 /* Clear OSG buffer */
102 buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
103 if (!buf)
104 return;
105
106 for (i = 0; i < solo_dev->nr_chans; i++) {
107 for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
108 solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
109 SOLO_EOSD_EXT_ADDR +
110 (i * SOLO_EOSD_EXT_SIZE) + j,
111 OSG_BUFFER_SIZE);
112 }
113 }
114 kfree(buf);
115}
116
117int solo_osd_print(struct solo_enc_dev *solo_enc)
118{
119 struct solo_dev *solo_dev = solo_enc->solo_dev;
120 char *str = solo_enc->osd_text;
121 u8 *buf;
122 u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
123 int len = strlen(str);
124 int i, j;
125 int x = 1, y = 1;
126
127 if (len == 0) {
128 reg &= ~(1 << solo_enc->ch);
129 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
130 return 0;
131 }
132
133 buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
134 if (!buf)
135 return -ENOMEM;
136
137 for (i = 0; i < len; i++) {
138 for (j = 0; j < 16; j++) {
139 buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
140 (solo_osd_font[(str[i] * 4) + (j / 4)]
141 >> ((3 - (j % 4)) * 8)) & 0xff;
142 }
143 }
144
145 solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR +
146 (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
147 reg |= (1 << solo_enc->ch);
148 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
149
150 kfree(buf);
151
152 return 0;
153}
154
155static void solo_jpeg_config(struct solo_dev *solo_dev)
156{
157 u32 reg;
158 if (solo_dev->flags & FLAGS_6110)
159 reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0);
160 else
161 reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0);
162 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg);
163 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
164 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
165 solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
166 (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
167 ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
168 solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
169 /* que limit, samp limit, pos limit */
170 solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60);
171}
172
173static void solo_mp4e_config(struct solo_dev *solo_dev)
174{
175 int i;
176 u32 reg;
177
178 /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
179 solo_reg_write(solo_dev, SOLO_VE_CFG0,
180 SOLO_VE_INTR_CTRL(0) |
181 SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
182 SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
183
184 solo_reg_write(solo_dev, SOLO_VE_CFG1,
185 SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
186
187 solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
188 solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
189 solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
190 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
191 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
192
193 reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) |
194 SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15);
195 if (solo_dev->flags & FLAGS_6110)
196 reg |= SOLO_DCT_INTERVAL(10);
197 else
198 reg |= SOLO_DCT_INTERVAL(36 / 4);
199 solo_reg_write(solo_dev, SOLO_VE_ATTR, reg);
200
201 for (i = 0; i < solo_dev->nr_chans; i++)
202 solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
203 (SOLO_EREF_EXT_ADDR(solo_dev) +
204 (i * SOLO_EREF_EXT_SIZE)) >> 16);
205
206 if (solo_dev->flags & FLAGS_6110)
207 solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */
208}
209
210int solo_enc_init(struct solo_dev *solo_dev)
211{
212 int i;
213
214 solo_capture_config(solo_dev);
215 solo_mp4e_config(solo_dev);
216 solo_jpeg_config(solo_dev);
217
218 for (i = 0; i < solo_dev->nr_chans; i++) {
219 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
220 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
221 }
222
223 solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
224
225 return 0;
226}
227
228void solo_enc_exit(struct solo_dev *solo_dev)
229{
230 int i;
231
232 solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
233
234 for (i = 0; i < solo_dev->nr_chans; i++) {
235 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);
237 }
238}
diff --git a/drivers/staging/solo6x10/g723.c b/drivers/staging/solo6x10/g723.c
new file mode 100644
index 00000000000..59274bfca95
--- /dev/null
+++ b/drivers/staging/solo6x10/g723.c
@@ -0,0 +1,399 @@
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#include <linux/kernel.h>
21#include <linux/mempool.h>
22#include <linux/poll.h>
23#include <linux/kthread.h>
24#include <linux/slab.h>
25#include <linux/freezer.h>
26#include <sound/core.h>
27#include <sound/initval.h>
28#include <sound/pcm.h>
29#include <sound/control.h>
30#include "solo6x10.h"
31#include "tw28.h"
32
33#define G723_INTR_ORDER 0
34#define G723_FDMA_PAGES 32
35#define G723_PERIOD_BYTES 48
36#define G723_PERIOD_BLOCK 1024
37#define G723_FRAMES_PER_PAGE 48
38
39/* Sets up channels 16-19 for decoding and 0-15 for encoding */
40#define OUTMODE_MASK 0x300
41
42#define SAMPLERATE 8000
43#define BITRATE 25
44
45/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
46 * is broken down to 20 * 48 byte regions (one for each channel possible)
47 * with the rest of the page being dummy data. */
48#define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX)
49#define IRQ_PAGES 4 /* 0 - 4 */
50#define PERIODS_MIN (1 << IRQ_PAGES)
51#define PERIODS_MAX G723_FDMA_PAGES
52
53struct solo_snd_pcm {
54 int on;
55 spinlock_t lock;
56 struct solo_dev *solo_dev;
57 unsigned char g723_buf[G723_PERIOD_BYTES];
58};
59
60static void solo_g723_config(struct solo_dev *solo_dev)
61{
62 int clk_div;
63
64 clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2);
65
66 solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
67 SOLO_AUDIO_BITRATE(BITRATE) |
68 SOLO_AUDIO_CLK_DIV(clk_div));
69
70 solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
71 SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) |
72 SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
73 SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
74
75 solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
76 SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE |
77 SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK));
78}
79
80void solo_g723_isr(struct solo_dev *solo_dev)
81{
82 struct snd_pcm_str *pstr =
83 &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
84 struct snd_pcm_substream *ss;
85 struct solo_snd_pcm *solo_pcm;
86
87 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723);
88
89 for (ss = pstr->substream; ss != NULL; ss = ss->next) {
90 if (snd_pcm_substream_chip(ss) == NULL)
91 continue;
92
93 /* This means open() hasn't been called on this one */
94 if (snd_pcm_substream_chip(ss) == solo_dev)
95 continue;
96
97 /* Haven't triggered a start yet */
98 solo_pcm = snd_pcm_substream_chip(ss);
99 if (!solo_pcm->on)
100 continue;
101
102 snd_pcm_period_elapsed(ss);
103 }
104}
105
106static int snd_solo_hw_params(struct snd_pcm_substream *ss,
107 struct snd_pcm_hw_params *hw_params)
108{
109 return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
110}
111
112static int snd_solo_hw_free(struct snd_pcm_substream *ss)
113{
114 return snd_pcm_lib_free_pages(ss);
115}
116
117static struct snd_pcm_hardware snd_solo_pcm_hw = {
118 .info = (SNDRV_PCM_INFO_MMAP |
119 SNDRV_PCM_INFO_INTERLEAVED |
120 SNDRV_PCM_INFO_BLOCK_TRANSFER |
121 SNDRV_PCM_INFO_MMAP_VALID),
122 .formats = SNDRV_PCM_FMTBIT_U8,
123 .rates = SNDRV_PCM_RATE_8000,
124 .rate_min = 8000,
125 .rate_max = 8000,
126 .channels_min = 1,
127 .channels_max = 1,
128 .buffer_bytes_max = MAX_BUFFER,
129 .period_bytes_min = G723_PERIOD_BYTES,
130 .period_bytes_max = G723_PERIOD_BYTES,
131 .periods_min = PERIODS_MIN,
132 .periods_max = PERIODS_MAX,
133};
134
135static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
136{
137 struct solo_dev *solo_dev = snd_pcm_substream_chip(ss);
138 struct solo_snd_pcm *solo_pcm;
139
140 solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
141 if (solo_pcm == NULL)
142 return -ENOMEM;
143
144 spin_lock_init(&solo_pcm->lock);
145 solo_pcm->solo_dev = solo_dev;
146 ss->runtime->hw = snd_solo_pcm_hw;
147
148 snd_pcm_substream_chip(ss) = solo_pcm;
149
150 return 0;
151}
152
153static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
154{
155 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
156
157 snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
158 kfree(solo_pcm);
159
160 return 0;
161}
162
163static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
164{
165 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
166 struct solo_dev *solo_dev = solo_pcm->solo_dev;
167 int ret = 0;
168
169 spin_lock(&solo_pcm->lock);
170
171 switch (cmd) {
172 case SNDRV_PCM_TRIGGER_START:
173 if (solo_pcm->on == 0) {
174 /* If this is the first user, switch on interrupts */
175 if (atomic_inc_return(&solo_dev->snd_users) == 1)
176 solo_irq_on(solo_dev, SOLO_IRQ_G723);
177 solo_pcm->on = 1;
178 }
179 break;
180 case SNDRV_PCM_TRIGGER_STOP:
181 if (solo_pcm->on) {
182 /* If this was our last user, switch them off */
183 if (atomic_dec_return(&solo_dev->snd_users) == 0)
184 solo_irq_off(solo_dev, SOLO_IRQ_G723);
185 solo_pcm->on = 0;
186 }
187 break;
188 default:
189 ret = -EINVAL;
190 }
191
192 spin_unlock(&solo_pcm->lock);
193
194 return ret;
195}
196
197static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
198{
199 return 0;
200}
201
202static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
203{
204 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
205 struct solo_dev *solo_dev = solo_pcm->solo_dev;
206 snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
207
208 return idx * G723_FRAMES_PER_PAGE;
209}
210
211static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
212 snd_pcm_uframes_t pos, void __user *dst,
213 snd_pcm_uframes_t count)
214{
215 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
216 struct solo_dev *solo_dev = solo_pcm->solo_dev;
217 int err, i;
218
219 for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
220 int page = (pos / G723_FRAMES_PER_PAGE) + i;
221
222 err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0,
223 solo_pcm->g723_buf,
224 SOLO_G723_EXT_ADDR(solo_dev) +
225 (page * G723_PERIOD_BLOCK) +
226 (ss->number * G723_PERIOD_BYTES),
227 G723_PERIOD_BYTES);
228 if (err)
229 return err;
230
231 err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
232 solo_pcm->g723_buf, G723_PERIOD_BYTES);
233
234 if (err)
235 return -EFAULT;
236 }
237
238 return 0;
239}
240
241static struct snd_pcm_ops snd_solo_pcm_ops = {
242 .open = snd_solo_pcm_open,
243 .close = snd_solo_pcm_close,
244 .ioctl = snd_pcm_lib_ioctl,
245 .hw_params = snd_solo_hw_params,
246 .hw_free = snd_solo_hw_free,
247 .prepare = snd_solo_pcm_prepare,
248 .trigger = snd_solo_pcm_trigger,
249 .pointer = snd_solo_pcm_pointer,
250 .copy = snd_solo_pcm_copy,
251};
252
253static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
254 struct snd_ctl_elem_info *info)
255{
256 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
257 info->count = 1;
258 info->value.integer.min = 0;
259 info->value.integer.max = 15;
260 info->value.integer.step = 1;
261
262 return 0;
263}
264
265static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
266 struct snd_ctl_elem_value *value)
267{
268 struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
269 u8 ch = value->id.numid - 1;
270
271 value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
272
273 return 0;
274}
275
276static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_value *value)
278{
279 struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
280 u8 ch = value->id.numid - 1;
281 u8 old_val;
282
283 old_val = tw28_get_audio_gain(solo_dev, ch);
284 if (old_val == value->value.integer.value[0])
285 return 0;
286
287 tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
288
289 return 1;
290}
291
292static struct snd_kcontrol_new snd_solo_capture_volume = {
293 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
294 .name = "Capture Volume",
295 .info = snd_solo_capture_volume_info,
296 .get = snd_solo_capture_volume_get,
297 .put = snd_solo_capture_volume_put,
298};
299
300static int solo_snd_pcm_init(struct solo_dev *solo_dev)
301{
302 struct snd_card *card = solo_dev->snd_card;
303 struct snd_pcm *pcm;
304 struct snd_pcm_substream *ss;
305 int ret;
306 int i;
307
308 ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
309 &pcm);
310 if (ret < 0)
311 return ret;
312
313 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
314 &snd_solo_pcm_ops);
315
316 snd_pcm_chip(pcm) = solo_dev;
317 pcm->info_flags = 0;
318 strcpy(pcm->name, card->shortname);
319
320 for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
321 ss; ss = ss->next, i++)
322 sprintf(ss->name, "Camera #%d Audio", i);
323
324 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
325 SNDRV_DMA_TYPE_CONTINUOUS,
326 snd_dma_continuous_data(GFP_KERNEL),
327 MAX_BUFFER, MAX_BUFFER);
328 if (ret < 0)
329 return ret;
330
331 solo_dev->snd_pcm = pcm;
332
333 return 0;
334}
335
336int solo_g723_init(struct solo_dev *solo_dev)
337{
338 static struct snd_device_ops ops = { NULL };
339 struct snd_card *card;
340 struct snd_kcontrol_new kctl;
341 char name[32];
342 int ret;
343
344 atomic_set(&solo_dev->snd_users, 0);
345
346 /* Allows for easier mapping between video and audio */
347 sprintf(name, "Softlogic%d", solo_dev->vfd->num);
348
349 ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
350 &solo_dev->snd_card);
351 if (ret < 0)
352 return ret;
353
354 card = solo_dev->snd_card;
355
356 strcpy(card->driver, SOLO6X10_NAME);
357 strcpy(card->shortname, "SOLO-6x10 Audio");
358 sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
359 pci_name(solo_dev->pdev), solo_dev->pdev->irq);
360 snd_card_set_dev(card, &solo_dev->pdev->dev);
361
362 ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
363 if (ret < 0)
364 goto snd_error;
365
366 /* Mixer controls */
367 strcpy(card->mixername, "SOLO-6x10");
368 kctl = snd_solo_capture_volume;
369 kctl.count = solo_dev->nr_chans;
370 ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
371 if (ret < 0)
372 return ret;
373
374 ret = solo_snd_pcm_init(solo_dev);
375 if (ret < 0)
376 goto snd_error;
377
378 ret = snd_card_register(card);
379 if (ret < 0)
380 goto snd_error;
381
382 solo_g723_config(solo_dev);
383
384 dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
385
386 return 0;
387
388snd_error:
389 snd_card_free(card);
390 return ret;
391}
392
393void solo_g723_exit(struct solo_dev *solo_dev)
394{
395 solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
396 solo_irq_off(solo_dev, SOLO_IRQ_G723);
397
398 snd_card_free(solo_dev->snd_card);
399}
diff --git a/drivers/staging/solo6x10/gpio.c b/drivers/staging/solo6x10/gpio.c
new file mode 100644
index 00000000000..0925e6f33a9
--- /dev/null
+++ b/drivers/staging/solo6x10/gpio.c
@@ -0,0 +1,102 @@
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#include <linux/kernel.h>
21#include <linux/fs.h>
22#include <asm/uaccess.h>
23#include "solo6x10.h"
24
25static void solo_gpio_mode(struct solo_dev *solo_dev,
26 unsigned int port_mask, unsigned int mode)
27{
28 int port;
29 unsigned int ret;
30
31 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
32
33 /* To set gpio */
34 for (port = 0; port < 16; port++) {
35 if (!((1 << port) & port_mask))
36 continue;
37
38 ret &= (~(3 << (port << 1)));
39 ret |= ((mode & 3) << (port << 1));
40 }
41
42 solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
43
44 /* To set extended gpio - sensor */
45 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
46
47 for (port = 0; port < 16; port++) {
48 if (!((1 << (port + 16)) & port_mask))
49 continue;
50
51 if (!mode)
52 ret &= ~(1 << port);
53 else
54 ret |= 1 << port;
55 }
56
57 solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
58}
59
60static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value)
61{
62 solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
63 solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
64}
65
66static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value)
67{
68 solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
69 solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
70}
71
72static void solo_gpio_config(struct solo_dev *solo_dev)
73{
74 /* Video reset */
75 solo_gpio_mode(solo_dev, 0x30, 1);
76 solo_gpio_clear(solo_dev, 0x30);
77 udelay(100);
78 solo_gpio_set(solo_dev, 0x30);
79 udelay(100);
80
81 /* Warning: Don't touch the next line unless you're sure of what
82 * you're doing: first four gpio [0-3] are used for video. */
83 solo_gpio_mode(solo_dev, 0x0f, 2);
84
85 /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
86 solo_gpio_mode(solo_dev, 0xff00, 1);
87
88 /* Initially set relay status to 0 */
89 solo_gpio_clear(solo_dev, 0xff00);
90}
91
92int solo_gpio_init(struct solo_dev *solo_dev)
93{
94 solo_gpio_config(solo_dev);
95 return 0;
96}
97
98void solo_gpio_exit(struct solo_dev *solo_dev)
99{
100 solo_gpio_clear(solo_dev, 0x30);
101 solo_gpio_config(solo_dev);
102}
diff --git a/drivers/staging/solo6x10/i2c.c b/drivers/staging/solo6x10/i2c.c
new file mode 100644
index 00000000000..ef95a500b4d
--- /dev/null
+++ b/drivers/staging/solo6x10/i2c.c
@@ -0,0 +1,330 @@
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/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
21 * channel. The bus can only handle one i2c event at a time. The below handles
22 * this all wrong. We should be using the status registers to see if the bus
23 * is in use, and have a global lock to check the status register. Also,
24 * the bulk of the work should be handled out-of-interrupt. The ugly loops
25 * that occur during interrupt scare me. The ISR should merely signal
26 * thread context, ACK the interrupt, and move on. -- BenC */
27
28#include <linux/kernel.h>
29#include "solo6x10.h"
30
31u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
32{
33 struct i2c_msg msgs[2];
34 u8 data;
35
36 msgs[0].flags = 0;
37 msgs[0].addr = addr;
38 msgs[0].len = 1;
39 msgs[0].buf = &off;
40
41 msgs[1].flags = I2C_M_RD;
42 msgs[1].addr = addr;
43 msgs[1].len = 1;
44 msgs[1].buf = &data;
45
46 i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
47
48 return data;
49}
50
51void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr,
52 u8 off, u8 data)
53{
54 struct i2c_msg msgs;
55 u8 buf[2];
56
57 buf[0] = off;
58 buf[1] = data;
59 msgs.flags = 0;
60 msgs.addr = addr;
61 msgs.len = 2;
62 msgs.buf = buf;
63
64 i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
65}
66
67static void solo_i2c_flush(struct solo_dev *solo_dev, int wr)
68{
69 u32 ctrl;
70
71 ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
72
73 if (solo_dev->i2c_state == IIC_STATE_START)
74 ctrl |= SOLO_IIC_START;
75
76 if (wr) {
77 ctrl |= SOLO_IIC_WRITE;
78 } else {
79 ctrl |= SOLO_IIC_READ;
80 if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
81 ctrl |= SOLO_IIC_ACK_EN;
82 }
83
84 if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
85 ctrl |= SOLO_IIC_STOP;
86
87 solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
88}
89
90static void solo_i2c_start(struct solo_dev *solo_dev)
91{
92 u32 addr = solo_dev->i2c_msg->addr << 1;
93
94 if (solo_dev->i2c_msg->flags & I2C_M_RD)
95 addr |= 1;
96
97 solo_dev->i2c_state = IIC_STATE_START;
98 solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
99 solo_i2c_flush(solo_dev, 1);
100}
101
102static void solo_i2c_stop(struct solo_dev *solo_dev)
103{
104 solo_irq_off(solo_dev, SOLO_IRQ_IIC);
105 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
106 solo_dev->i2c_state = IIC_STATE_STOP;
107 wake_up(&solo_dev->i2c_wait);
108}
109
110static int solo_i2c_handle_read(struct solo_dev *solo_dev)
111{
112prepare_read:
113 if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
114 solo_i2c_flush(solo_dev, 0);
115 return 0;
116 }
117
118 solo_dev->i2c_msg_ptr = 0;
119 solo_dev->i2c_msg++;
120 solo_dev->i2c_msg_num--;
121
122 if (solo_dev->i2c_msg_num == 0) {
123 solo_i2c_stop(solo_dev);
124 return 0;
125 }
126
127 if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
128 solo_i2c_start(solo_dev);
129 } else {
130 if (solo_dev->i2c_msg->flags & I2C_M_RD)
131 goto prepare_read;
132 else
133 solo_i2c_stop(solo_dev);
134 }
135
136 return 0;
137}
138
139static int solo_i2c_handle_write(struct solo_dev *solo_dev)
140{
141retry_write:
142 if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
143 solo_reg_write(solo_dev, SOLO_IIC_TXD,
144 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
145 solo_dev->i2c_msg_ptr++;
146 solo_i2c_flush(solo_dev, 1);
147 return 0;
148 }
149
150 solo_dev->i2c_msg_ptr = 0;
151 solo_dev->i2c_msg++;
152 solo_dev->i2c_msg_num--;
153
154 if (solo_dev->i2c_msg_num == 0) {
155 solo_i2c_stop(solo_dev);
156 return 0;
157 }
158
159 if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
160 solo_i2c_start(solo_dev);
161 } else {
162 if (solo_dev->i2c_msg->flags & I2C_M_RD)
163 solo_i2c_stop(solo_dev);
164 else
165 goto retry_write;
166 }
167
168 return 0;
169}
170
171int solo_i2c_isr(struct solo_dev *solo_dev)
172{
173 u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
174 int ret = -EINVAL;
175
176 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
177
178 if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
179 solo_dev->i2c_id < 0) {
180 solo_i2c_stop(solo_dev);
181 return -ENXIO;
182 }
183
184 switch (solo_dev->i2c_state) {
185 case IIC_STATE_START:
186 if (solo_dev->i2c_msg->flags & I2C_M_RD) {
187 solo_dev->i2c_state = IIC_STATE_READ;
188 ret = solo_i2c_handle_read(solo_dev);
189 break;
190 }
191
192 solo_dev->i2c_state = IIC_STATE_WRITE;
193 case IIC_STATE_WRITE:
194 ret = solo_i2c_handle_write(solo_dev);
195 break;
196
197 case IIC_STATE_READ:
198 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
199 solo_reg_read(solo_dev, SOLO_IIC_RXD);
200 solo_dev->i2c_msg_ptr++;
201
202 ret = solo_i2c_handle_read(solo_dev);
203 break;
204
205 default:
206 solo_i2c_stop(solo_dev);
207 }
208
209 return ret;
210}
211
212static int solo_i2c_master_xfer(struct i2c_adapter *adap,
213 struct i2c_msg msgs[], int num)
214{
215 struct solo_dev *solo_dev = adap->algo_data;
216 unsigned long timeout;
217 int ret;
218 int i;
219 DEFINE_WAIT(wait);
220
221 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
222 if (&solo_dev->i2c_adap[i] == adap)
223 break;
224 }
225
226 if (i == SOLO_I2C_ADAPTERS)
227 return num; /* XXX Right return value for failure? */
228
229 mutex_lock(&solo_dev->i2c_mutex);
230 solo_dev->i2c_id = i;
231 solo_dev->i2c_msg = msgs;
232 solo_dev->i2c_msg_num = num;
233 solo_dev->i2c_msg_ptr = 0;
234
235 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
236 solo_irq_on(solo_dev, SOLO_IRQ_IIC);
237 solo_i2c_start(solo_dev);
238
239 timeout = HZ / 2;
240
241 for (;;) {
242 prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
243
244 if (solo_dev->i2c_state == IIC_STATE_STOP)
245 break;
246
247 timeout = schedule_timeout(timeout);
248 if (!timeout)
249 break;
250
251 if (signal_pending(current))
252 break;
253 }
254
255 finish_wait(&solo_dev->i2c_wait, &wait);
256 ret = num - solo_dev->i2c_msg_num;
257 solo_dev->i2c_state = IIC_STATE_IDLE;
258 solo_dev->i2c_id = -1;
259
260 mutex_unlock(&solo_dev->i2c_mutex);
261
262 return ret;
263}
264
265static u32 solo_i2c_functionality(struct i2c_adapter *adap)
266{
267 return I2C_FUNC_I2C;
268}
269
270static struct i2c_algorithm solo_i2c_algo = {
271 .master_xfer = solo_i2c_master_xfer,
272 .functionality = solo_i2c_functionality,
273};
274
275int solo_i2c_init(struct solo_dev *solo_dev)
276{
277 int i;
278 int ret;
279
280 solo_reg_write(solo_dev, SOLO_IIC_CFG,
281 SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
282
283 solo_dev->i2c_id = -1;
284 solo_dev->i2c_state = IIC_STATE_IDLE;
285 init_waitqueue_head(&solo_dev->i2c_wait);
286 mutex_init(&solo_dev->i2c_mutex);
287
288 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
289 struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
290
291 snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6X10_NAME, i);
292 adap->algo = &solo_i2c_algo;
293 adap->algo_data = solo_dev;
294 adap->retries = 1;
295 adap->dev.parent = &solo_dev->pdev->dev;
296
297 ret = i2c_add_adapter(adap);
298 if (ret) {
299 adap->algo_data = NULL;
300 break;
301 }
302 }
303
304 if (ret) {
305 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
306 if (!solo_dev->i2c_adap[i].algo_data)
307 break;
308 i2c_del_adapter(&solo_dev->i2c_adap[i]);
309 solo_dev->i2c_adap[i].algo_data = NULL;
310 }
311 return ret;
312 }
313
314 dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
315 SOLO_I2C_ADAPTERS);
316
317 return 0;
318}
319
320void solo_i2c_exit(struct solo_dev *solo_dev)
321{
322 int i;
323
324 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
325 if (!solo_dev->i2c_adap[i].algo_data)
326 continue;
327 i2c_del_adapter(&solo_dev->i2c_adap[i]);
328 solo_dev->i2c_adap[i].algo_data = NULL;
329 }
330}
diff --git a/drivers/staging/solo6x10/jpeg.h b/drivers/staging/solo6x10/jpeg.h
new file mode 100644
index 00000000000..50defec318c
--- /dev/null
+++ b/drivers/staging/solo6x10/jpeg.h
@@ -0,0 +1,105 @@
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_JPEG_H
21#define __SOLO6X10_JPEG_H
22
23static unsigned char jpeg_header[] = {
24 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
25 0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
26 0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
27 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
28 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
29 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
30 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
31 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
32 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
33 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
34 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
35 0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
36 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
37 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
38 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
39 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
40 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
41 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
42 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
43 0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
44 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
45 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
47 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
48 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
49 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
50 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
51 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
52 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
53 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
54 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
55 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
56 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
57 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
58 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
59 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
60 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
61 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
62 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
63 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
64 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
65 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
66 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
67 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
68 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
69 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
70 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
71 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
73 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
74 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
75 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
76 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
77 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
78 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
79 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
80 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
81 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
82 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
83 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
84 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
85 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
86 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
87 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
88 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
89 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
90 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
91 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
92 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
93 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
94 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
95 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
96 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
97 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
98 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
99 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
100};
101
102/* This is the byte marker for the start of SOF0: 0xffc0 marker */
103#define SOF0_START 575
104
105#endif /* __SOLO6X10_JPEG_H */
diff --git a/drivers/staging/solo6x10/osd-font.h b/drivers/staging/solo6x10/osd-font.h
new file mode 100644
index 00000000000..591e0e82e0e
--- /dev/null
+++ b/drivers/staging/solo6x10/osd-font.h
@@ -0,0 +1,154 @@
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
23static 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/solo6x10/p2m.c b/drivers/staging/solo6x10/p2m.c
new file mode 100644
index 00000000000..56210f0fc5e
--- /dev/null
+++ b/drivers/staging/solo6x10/p2m.c
@@ -0,0 +1,306 @@
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#include <linux/kernel.h>
21#include <linux/slab.h>
22#include <linux/scatterlist.h>
23#include "solo6x10.h"
24
25/* #define SOLO_TEST_P2M */
26
27int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
28 void *sys_addr, u32 ext_addr, u32 size)
29{
30 dma_addr_t dma_addr;
31 int ret;
32
33 WARN_ON(!size);
34 BUG_ON(id >= SOLO_NR_P2M);
35
36 if (!size)
37 return -EINVAL;
38
39 dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
40 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
41
42 ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
43
44 pci_unmap_single(solo_dev->pdev, dma_addr, size,
45 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
46
47 return ret;
48}
49
50int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
51 dma_addr_t dma_addr, u32 ext_addr, u32 size)
52{
53 struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
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
66void 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
84int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
85 struct p2m_desc *desc, int desc_count)
86{
87 struct solo_p2m_dev *p2m_dev;
88 unsigned int timeout;
89 int ret = 0;
90 u32 config = 0;
91 dma_addr_t desc_dma = 0;
92
93 BUG_ON(id >= SOLO_NR_P2M);
94 BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
95
96 p2m_dev = &solo_dev->p2m_dev[id];
97
98 mutex_lock(&p2m_dev->mutex);
99
100 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
101
102 INIT_COMPLETION(p2m_dev->completion);
103 p2m_dev->error = 0;
104
105 /* Enable the descriptors */
106 config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
107 desc_dma = pci_map_single(solo_dev->pdev, desc,
108 desc_count * sizeof(*desc),
109 PCI_DMA_TODEVICE);
110 solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
111 solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
112 solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
113 SOLO_P2M_DESC_MODE);
114
115 /* Should have all descriptors completed from one interrupt */
116 timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
117
118 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
119
120 /* Reset back to non-descriptor mode */
121 solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
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
128 if (p2m_dev->error)
129 ret = -EIO;
130 else if (timeout == 0)
131 ret = -EAGAIN;
132
133 mutex_unlock(&p2m_dev->mutex);
134
135 WARN_ON_ONCE(ret);
136
137 return ret;
138}
139
140int 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 }
179
180 WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
181
182 return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
183}
184
185#ifdef SOLO_TEST_P2M
186
187#define P2M_TEST_CHAR 0xbe
188
189static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id,
190 u32 base, int size)
191{
192 u8 *wr_buf;
193 u8 *rd_buf;
194 int i;
195 unsigned long long err_cnt = 0;
196
197 wr_buf = kmalloc(size, GFP_KERNEL);
198 if (!wr_buf) {
199 printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
200 return size;
201 }
202
203 rd_buf = kmalloc(size, GFP_KERNEL);
204 if (!rd_buf) {
205 printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
206 kfree(wr_buf);
207 return size;
208 }
209
210 memset(wr_buf, P2M_TEST_CHAR, size);
211 memset(rd_buf, P2M_TEST_CHAR + 1, size);
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}
225
226#define TEST_CHUNK_SIZE (8 * 1024)
227
228static void run_p2m_test(struct solo_dev *solo_dev)
229{
230 unsigned long long errs = 0;
231 u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
232 int i, d;
233
234 printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
235 SOLO6X10_NAME, size);
236
237 for (i = 0; i < size; i += TEST_CHUNK_SIZE)
238 for (d = 0; d < 4; d++)
239 errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
240
241 printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
242 SOLO6X10_NAME, errs);
243
244 return;
245}
246#else
247#define run_p2m_test(__solo) do {} while (0)
248#endif
249
250void solo_p2m_isr(struct solo_dev *solo_dev, int id)
251{
252 struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
253
254 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
255
256 complete(&p2m_dev->completion);
257}
258
259void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status)
260{
261 struct solo_p2m_dev *p2m_dev;
262 int i;
263
264 if (!(status & SOLO_PCI_ERR_P2M))
265 return;
266
267 for (i = 0; i < SOLO_NR_P2M; i++) {
268 p2m_dev = &solo_dev->p2m_dev[i];
269 p2m_dev->error = 1;
270 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
271 complete(&p2m_dev->completion);
272 }
273}
274
275void solo_p2m_exit(struct solo_dev *solo_dev)
276{
277 int i;
278
279 for (i = 0; i < SOLO_NR_P2M; i++)
280 solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
281}
282
283int solo_p2m_init(struct solo_dev *solo_dev)
284{
285 struct solo_p2m_dev *p2m_dev;
286 int i;
287
288 for (i = 0; i < SOLO_NR_P2M; i++) {
289 p2m_dev = &solo_dev->p2m_dev[i];
290
291 mutex_init(&p2m_dev->mutex);
292 init_completion(&p2m_dev->completion);
293
294 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
295 solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
296 SOLO_P2M_CSC_16BIT_565 |
297 SOLO_P2M_DMA_INTERVAL(3) |
298 SOLO_P2M_DESC_INTR_OPT |
299 SOLO_P2M_PCI_MASTER_MODE);
300 solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
301 }
302
303 run_p2m_test(solo_dev);
304
305 return 0;
306}
diff --git a/drivers/staging/solo6x10/registers.h b/drivers/staging/solo6x10/registers.h
new file mode 100644
index 00000000000..aca544472c9
--- /dev/null
+++ b/drivers/staging/solo6x10/registers.h
@@ -0,0 +1,637 @@
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_REGISTERS_H
21#define __SOLO6X10_REGISTERS_H
22
23#include "offsets.h"
24
25/* Global 6X10 system configuration */
26#define SOLO_SYS_CFG 0x0000
27#define SOLO6010_SYS_CFG_FOUT_EN 0x00000001 /* 6010 only */
28#define SOLO6010_SYS_CFG_PLL_BYPASS 0x00000002 /* 6010 only */
29#define SOLO6010_SYS_CFG_PLL_PWDN 0x00000004 /* 6010 only */
30#define SOLO6010_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) /* 6010 only */
31#define SOLO6010_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) /* 6010 only */
32#define SOLO6010_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) /* 6010 only */
33#define SOLO_SYS_CFG_CLOCK_DIV 0x00080000
34#define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24)
35#define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26)
36#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 /* 6110: must be set */
37#define SOLO_SYS_CFG_RESET 0x80000000
38
39#define SOLO_DMA_CTRL 0x0004
40#define SOLO_DMA_CTRL_REFRESH_CYCLE(n) ((n)<<8)
41/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */
42#define SOLO_DMA_CTRL_SDRAM_SIZE(n) ((n)<<6)
43#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT (1<<5)
44#define SOLO_DMA_CTRL_STROBE_SELECT (1<<4)
45#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3)
46#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2)
47#define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0)
48#define SOLO_DMA_CTRL1 0x0008
49
50#define SOLO_SYS_VCLK 0x000C
51#define SOLO_VCLK_INVERT (1<<22)
52/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
53#define SOLO_VCLK_SELECT(n) ((n)<<20)
54#define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14)
55#define SOLO_VCLK_VIN1213_DELAY(n) ((n)<<12)
56#define SOLO_VCLK_VIN1011_DELAY(n) ((n)<<10)
57#define SOLO_VCLK_VIN0809_DELAY(n) ((n)<<8)
58#define SOLO_VCLK_VIN0607_DELAY(n) ((n)<<6)
59#define SOLO_VCLK_VIN0405_DELAY(n) ((n)<<4)
60#define SOLO_VCLK_VIN0203_DELAY(n) ((n)<<2)
61#define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0)
62
63#define SOLO_IRQ_STAT 0x0010
64#define SOLO_IRQ_ENABLE 0x0014
65#define SOLO_IRQ_P2M(n) (1<<((n)+17))
66#define SOLO_IRQ_GPIO (1<<16)
67#define SOLO_IRQ_VIDEO_LOSS (1<<15)
68#define SOLO_IRQ_VIDEO_IN (1<<14)
69#define SOLO_IRQ_MOTION (1<<13)
70#define SOLO_IRQ_ATA_CMD (1<<12)
71#define SOLO_IRQ_ATA_DIR (1<<11)
72#define SOLO_IRQ_PCI_ERR (1<<10)
73#define SOLO_IRQ_PS2_1 (1<<9)
74#define SOLO_IRQ_PS2_0 (1<<8)
75#define SOLO_IRQ_SPI (1<<7)
76#define SOLO_IRQ_IIC (1<<6)
77#define SOLO_IRQ_UART(n) (1<<((n) + 4))
78#define SOLO_IRQ_G723 (1<<3)
79#define SOLO_IRQ_DECODER (1<<1)
80#define SOLO_IRQ_ENCODER (1<<0)
81
82#define SOLO_CHIP_OPTION 0x001C
83#define SOLO_CHIP_ID_MASK 0x00000007
84
85#define SOLO6110_PLL_CONFIG 0x0020
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
102#define SOLO_EEPROM_CTRL 0x0060
103#define SOLO_EEPROM_ACCESS_EN (1<<7)
104#define SOLO_EEPROM_CS (1<<3)
105#define SOLO_EEPROM_CLK (1<<2)
106#define SOLO_EEPROM_DO (1<<1)
107#define SOLO_EEPROM_DI (1<<0)
108#define SOLO_EEPROM_ENABLE (EEPROM_ACCESS_EN | EEPROM_CS)
109
110#define SOLO_PCI_ERR 0x0070
111#define SOLO_PCI_ERR_FATAL 0x00000001
112#define SOLO_PCI_ERR_PARITY 0x00000002
113#define SOLO_PCI_ERR_TARGET 0x00000004
114#define SOLO_PCI_ERR_TIMEOUT 0x00000008
115#define SOLO_PCI_ERR_P2M 0x00000010
116#define SOLO_PCI_ERR_ATA 0x00000020
117#define SOLO_PCI_ERR_P2M_DESC 0x00000040
118#define SOLO_PCI_ERR_FSM0(__s) (((__s) >> 16) & 0x0f)
119#define SOLO_PCI_ERR_FSM1(__s) (((__s) >> 20) & 0x0f)
120#define SOLO_PCI_ERR_FSM2(__s) (((__s) >> 24) & 0x1f)
121
122#define SOLO_P2M_BASE 0x0080
123
124#define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20))
125#define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */
126#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */
127/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
128#define SOLO_P2M_CSC_16BIT_565 (1<<4)
129#define SOLO_P2M_UV_SWAP (1<<3)
130#define SOLO_P2M_PCI_MASTER_MODE (1<<2)
131#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */
132#define SOLO_P2M_DESC_MODE (1<<0)
133
134#define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20))
135
136#define SOLO_P2M_DESC_ID(n) (0x0088 + ((n)*0x20))
137#define SOLO_P2M_UPDATE_ID(n) ((n)<<0)
138
139#define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20))
140#define SOLO_P2M_COMMAND_DONE (1<<8)
141#define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat))
142
143#define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20))
144#define SOLO_P2M_PCI_INC(n) ((n)<<20)
145#define SOLO_P2M_REPEAT(n) ((n)<<10)
146/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
147#define SOLO_P2M_BURST_SIZE(n) ((n)<<7)
148#define SOLO_P2M_BURST_512 0
149#define SOLO_P2M_BURST_256 1
150#define SOLO_P2M_BURST_128 2
151#define SOLO_P2M_BURST_64 3
152#define SOLO_P2M_BURST_32 4
153#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */
154/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
155#define SOLO_P2M_ALPHA_MODE(n) ((n)<<4)
156#define SOLO_P2M_CSC_ON (1<<3)
157#define SOLO_P2M_INTERRUPT_REQ (1<<2)
158#define SOLO_P2M_WRITE (1<<1)
159#define SOLO_P2M_TRANS_ON (1<<0)
160
161#define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20))
162#define SOLO_P2M_EXT_INC(n) ((n)<<20)
163#define SOLO_P2M_COPY_SIZE(n) ((n)<<0)
164
165#define SOLO_P2M_TAR_ADR(n) (0x0098 + ((n)*0x20))
166
167#define SOLO_P2M_EXT_ADR(n) (0x009C + ((n)*0x20))
168
169#define SOLO_P2M_BUFFER(i) (0x2000 + ((i)*4))
170
171#define SOLO_VI_CH_SWITCH_0 0x0100
172#define SOLO_VI_CH_SWITCH_1 0x0104
173#define SOLO_VI_CH_SWITCH_2 0x0108
174
175#define SOLO_VI_CH_ENA 0x010C
176#define SOLO_VI_CH_FORMAT 0x0110
177#define SOLO_VI_FD_SEL_MASK(n) ((n)<<16)
178#define SOLO_VI_PROG_MASK(n) ((n)<<0)
179
180#define SOLO_VI_FMT_CFG 0x0114
181#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31)
182#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30)
183#define SOLO_VI_FMT_TEST_SIGNAL (1<<28)
184
185#define SOLO_VI_PAGE_SW 0x0118
186#define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8)
187#define SOLO_FI_INV_DISP_OUT(n) ((n)<<7)
188#define SOLO_DISP_SYNC_FI(n) ((n)<<6)
189#define SOLO_PIP_PAGE_ADD(n) ((n)<<3)
190#define SOLO_NORMAL_PAGE_ADD(n) ((n)<<0)
191
192#define SOLO_VI_ACT_I_P 0x011C
193#define SOLO_VI_ACT_I_S 0x0120
194#define SOLO_VI_ACT_P 0x0124
195#define SOLO_VI_FI_INVERT (1<<31)
196#define SOLO_VI_H_START(n) ((n)<<21)
197#define SOLO_VI_V_START(n) ((n)<<11)
198#define SOLO_VI_V_STOP(n) ((n)<<0)
199
200#define SOLO_VI_STATUS0 0x0128
201#define SOLO_VI_STATUS0_PAGE(__n) ((__n) & 0x07)
202#define SOLO_VI_STATUS1 0x012C
203
204/* XXX: Might be better off in kernel level disp.h */
205#define DISP_PAGE(stat) ((stat) & 0x07)
206
207#define SOLO_VI_PB_CONFIG 0x0130
208#define SOLO_VI_PB_USER_MODE (1<<1)
209#define SOLO_VI_PB_PAL (1<<0)
210#define SOLO_VI_PB_RANGE_HV 0x0134
211#define SOLO_VI_PB_HSIZE(h) ((h)<<12)
212#define SOLO_VI_PB_VSIZE(v) ((v)<<0)
213#define SOLO_VI_PB_ACT_H 0x0138
214#define SOLO_VI_PB_HSTART(n) ((n)<<12)
215#define SOLO_VI_PB_HSTOP(n) ((n)<<0)
216#define SOLO_VI_PB_ACT_V 0x013C
217#define SOLO_VI_PB_VSTART(n) ((n)<<12)
218#define SOLO_VI_PB_VSTOP(n) ((n)<<0)
219
220#define SOLO_VI_MOSAIC(ch) (0x0140 + ((ch)*4))
221#define SOLO_VI_MOSAIC_SX(x) ((x)<<24)
222#define SOLO_VI_MOSAIC_EX(x) ((x)<<16)
223#define SOLO_VI_MOSAIC_SY(x) ((x)<<8)
224#define SOLO_VI_MOSAIC_EY(x) ((x)<<0)
225
226#define SOLO_VI_WIN_CTRL0(ch) (0x0180 + ((ch)*4))
227#define SOLO_VI_WIN_CTRL1(ch) (0x01C0 + ((ch)*4))
228
229#define SOLO_VI_WIN_CHANNEL(n) ((n)<<28)
230
231#define SOLO_VI_WIN_PIP(n) ((n)<<27)
232#define SOLO_VI_WIN_SCALE(n) ((n)<<24)
233
234#define SOLO_VI_WIN_SX(x) ((x)<<12)
235#define SOLO_VI_WIN_EX(x) ((x)<<0)
236
237#define SOLO_VI_WIN_SY(x) ((x)<<12)
238#define SOLO_VI_WIN_EY(x) ((x)<<0)
239
240#define SOLO_VI_WIN_ON(ch) (0x0200 + ((ch)*4))
241
242#define SOLO_VI_WIN_SW 0x0240
243#define SOLO_VI_WIN_LIVE_AUTO_MUTE 0x0244
244
245#define SOLO_VI_MOT_ADR 0x0260
246#define SOLO_VI_MOTION_EN(mask) ((mask)<<16)
247#define SOLO_VI_MOT_CTRL 0x0264
248#define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24)
249#define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16)
250#define SOLO_VI_MOTION_INTR_START_STOP (1<<15)
251#define SOLO_VI_MOTION_FREEZE_DATA (1<<14)
252#define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0)
253#define SOLO_VI_MOT_CLEAR 0x0268
254#define SOLO_VI_MOT_STATUS 0x026C
255#define SOLO_VI_MOTION_CNT(n) ((n)<<0)
256#define SOLO_VI_MOTION_BORDER 0x0270
257#define SOLO_VI_MOTION_BAR 0x0274
258#define SOLO_VI_MOTION_Y_SET (1<<29)
259#define SOLO_VI_MOTION_Y_ADD (1<<28)
260#define SOLO_VI_MOTION_CB_SET (1<<27)
261#define SOLO_VI_MOTION_CB_ADD (1<<26)
262#define SOLO_VI_MOTION_CR_SET (1<<25)
263#define SOLO_VI_MOTION_CR_ADD (1<<24)
264#define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16)
265#define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8)
266#define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0)
267
268#define SOLO_VO_FMT_ENC 0x0300
269#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31)
270#define SOLO_VO_FMT_TYPE_PAL (1<<30)
271#define SOLO_VO_FMT_TYPE_NTSC 0
272#define SOLO_VO_USER_SET (1<<29)
273
274#define SOLO_VO_FI_CHANGE (1<<20)
275#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19)
276#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18)
277#define SOLO_VO_USER_COLOR_SET_NAV (1<<17)
278#define SOLO_VO_USER_COLOR_SET_NAH (1<<16)
279#define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8)
280#define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4)
281#define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0)
282
283#define SOLO_VO_ACT_H 0x0304
284#define SOLO_VO_H_BLANK(n) ((n)<<22)
285#define SOLO_VO_H_START(n) ((n)<<11)
286#define SOLO_VO_H_STOP(n) ((n)<<0)
287
288#define SOLO_VO_ACT_V 0x0308
289#define SOLO_VO_V_BLANK(n) ((n)<<22)
290#define SOLO_VO_V_START(n) ((n)<<11)
291#define SOLO_VO_V_STOP(n) ((n)<<0)
292
293#define SOLO_VO_RANGE_HV 0x030C
294#define SOLO_VO_SYNC_INVERT (1<<24)
295#define SOLO_VO_HSYNC_INVERT (1<<23)
296#define SOLO_VO_VSYNC_INVERT (1<<22)
297#define SOLO_VO_H_LEN(n) ((n)<<11)
298#define SOLO_VO_V_LEN(n) ((n)<<0)
299
300#define SOLO_VO_DISP_CTRL 0x0310
301#define SOLO_VO_DISP_ON (1<<31)
302#define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24)
303#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22)
304#define SOLO_VO_DISP_SINGLE_PAGE (1<<21)
305#define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff)
306
307#define SOLO_VO_DISP_ERASE 0x0314
308#define SOLO_VO_DISP_ERASE_ON (1<<0)
309
310#define SOLO_VO_ZOOM_CTRL 0x0318
311#define SOLO_VO_ZOOM_VER_ON (1<<24)
312#define SOLO_VO_ZOOM_HOR_ON (1<<23)
313#define SOLO_VO_ZOOM_V_COMP (1<<22)
314#define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11)
315#define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0)
316
317#define SOLO_VO_FREEZE_CTRL 0x031C
318#define SOLO_VO_FREEZE_ON (1<<1)
319#define SOLO_VO_FREEZE_INTERPOLATION (1<<0)
320
321#define SOLO_VO_BKG_COLOR 0x0320
322#define SOLO_BG_Y(y) ((y)<<16)
323#define SOLO_BG_U(u) ((u)<<8)
324#define SOLO_BG_V(v) ((v)<<0)
325
326#define SOLO_VO_DEINTERLACE 0x0324
327#define SOLO_VO_DEINTERLACE_THRESHOLD(n) ((n)<<8)
328#define SOLO_VO_DEINTERLACE_EDGE_VALUE(n) ((n)<<0)
329
330#define SOLO_VO_BORDER_LINE_COLOR 0x0330
331#define SOLO_VO_BORDER_FILL_COLOR 0x0334
332#define SOLO_VO_BORDER_LINE_MASK 0x0338
333#define SOLO_VO_BORDER_FILL_MASK 0x033c
334
335#define SOLO_VO_BORDER_X(n) (0x0340+((n)*4))
336#define SOLO_VO_BORDER_Y(n) (0x0354+((n)*4))
337
338#define SOLO_VO_CELL_EXT_SET 0x0368
339#define SOLO_VO_CELL_EXT_START 0x036c
340#define SOLO_VO_CELL_EXT_STOP 0x0370
341
342#define SOLO_VO_CELL_EXT_SET2 0x0374
343#define SOLO_VO_CELL_EXT_START2 0x0378
344#define SOLO_VO_CELL_EXT_STOP2 0x037c
345
346#define SOLO_VO_RECTANGLE_CTRL(n) (0x0368+((n)*12))
347#define SOLO_VO_RECTANGLE_START(n) (0x036c+((n)*12))
348#define SOLO_VO_RECTANGLE_STOP(n) (0x0370+((n)*12))
349
350#define SOLO_VO_CURSOR_POS (0x0380)
351#define SOLO_VO_CURSOR_CLR (0x0384)
352#define SOLO_VO_CURSOR_CLR2 (0x0388)
353#define SOLO_VO_CURSOR_MASK(id) (0x0390+((id)*4))
354
355#define SOLO_VO_EXPANSION(id) (0x0250+((id)*4))
356
357#define SOLO_OSG_CONFIG 0x03E0
358#define SOLO_VO_OSG_ON (1<<31)
359#define SOLO_VO_OSG_COLOR_MUTE (1<<28)
360#define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22)
361#define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16)
362#define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff)
363
364#define SOLO_OSG_ERASE 0x03E4
365#define SOLO_OSG_ERASE_ON (0x80)
366#define SOLO_OSG_ERASE_OFF (0x00)
367
368#define SOLO_VO_OSG_BLINK 0x03E8
369#define SOLO_VO_OSG_BLINK_ON (1<<1)
370#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0)
371
372#define SOLO_CAP_BASE 0x0400
373#define SOLO_CAP_MAX_PAGE(n) ((n)<<16)
374#define SOLO_CAP_BASE_ADDR(n) ((n)<<0)
375#define SOLO_CAP_BTW 0x0404
376#define SOLO_CAP_PROG_BANDWIDTH(n) ((n)<<8)
377#define SOLO_CAP_MAX_BANDWIDTH(n) ((n)<<0)
378
379#define SOLO_DIM_SCALE1 0x0408
380#define SOLO_DIM_SCALE2 0x040C
381#define SOLO_DIM_SCALE3 0x0410
382#define SOLO_DIM_SCALE4 0x0414
383#define SOLO_DIM_SCALE5 0x0418
384#define SOLO_DIM_V_MB_NUM_FRAME(n) ((n)<<16)
385#define SOLO_DIM_V_MB_NUM_FIELD(n) ((n)<<8)
386#define SOLO_DIM_H_MB_NUM(n) ((n)<<0)
387
388#define SOLO_DIM_PROG 0x041C
389#define SOLO_CAP_STATUS 0x0420
390
391#define SOLO_CAP_CH_SCALE(ch) (0x0440+((ch)*4))
392#define SOLO_CAP_CH_COMP_ENA_E(ch) (0x0480+((ch)*4))
393#define SOLO_CAP_CH_INTV(ch) (0x04C0+((ch)*4))
394#define SOLO_CAP_CH_INTV_E(ch) (0x0500+((ch)*4))
395
396
397#define SOLO_VE_CFG0 0x0610
398#define SOLO_VE_TWO_PAGE_MODE (1<<31)
399#define SOLO_VE_INTR_CTRL(n) ((n)<<24)
400#define SOLO_VE_BLOCK_SIZE(n) ((n)<<16)
401#define SOLO_VE_BLOCK_BASE(n) ((n)<<0)
402
403#define SOLO_VE_CFG1 0x0614
404#define SOLO6110_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 only */
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)
408#define SOLO_VE_MOTION_MODE(n) ((n)<<16)
409#define SOLO_VE_MOTION_BASE(n) ((n)<<0)
410
411#define SOLO_VE_WMRK_POLY 0x061C
412#define SOLO_VE_VMRK_INIT_KEY 0x0620
413#define SOLO_VE_WMRK_STRL 0x0624
414#define SOLO_VE_ENCRYP_POLY 0x0628
415#define SOLO_VE_ENCRYP_INIT 0x062C
416#define SOLO_VE_ATTR 0x0630
417#define SOLO_VE_LITTLE_ENDIAN (1<<31)
418#define SOLO_COMP_ATTR_RN (1<<30)
419#define SOLO_COMP_ATTR_FCODE(n) ((n)<<27)
420#define SOLO_COMP_TIME_INC(n) ((n)<<25)
421#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21)
422#define SOLO_DCT_INTERVAL(n) ((n)<<16)
423
424#define SOLO_VE_STATE(n) (0x0640+((n)*4))
425
426#define SOLO_VE_JPEG_QP_TBL 0x0670
427#define SOLO_VE_JPEG_QP_CH_L 0x0674
428#define SOLO_VE_JPEG_QP_CH_H 0x0678
429#define SOLO_VE_JPEG_CFG 0x067C
430#define SOLO_VE_JPEG_CTRL 0x0680
431
432#define SOLO_VE_OSD_CH 0x0690
433#define SOLO_VE_OSD_BASE 0x0694
434#define SOLO_VE_OSD_CLR 0x0698
435#define SOLO_VE_OSD_OPT 0x069C
436
437#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_QP(ch) (0x0780+((ch)*4))
440#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_E(ch) (0x0840+((ch)*4))
443#define SOLO_VE_CH_REF_BASE(ch) (0x0880+((ch)*4))
444#define SOLO_VE_CH_REF_BASE_E(ch) (0x08C0+((ch)*4))
445
446#define SOLO_VE_MPEG4_QUE(n) (0x0A00+((n)*8))
447#define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8))
448
449#define SOLO_VD_CFG0 0x0900
450#define SOLO6010_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) /* 6010 only */
451#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_RES (1<<21)
454#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20)
455#define SOLO_VD_CFG_SINGLE_MODE (1<<18)
456#define SOLO_VD_CFG_SCAL_MANUAL (1<<17)
457#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16)
458#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15)
459#define SOLO_VD_CFG_START_FI (1<<14)
460#define SOLO_VD_CFG_ERR_LOCK (1<<13)
461#define SOLO_VD_CFG_ERR_INT_ENA (1<<12)
462#define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8)
463#define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0)
464
465#define SOLO_VD_CFG1 0x0904
466
467#define SOLO_VD_DEINTERLACE 0x0908
468#define SOLO_VD_DEINTERLACE_THRESHOLD(n) ((n)<<8)
469#define SOLO_VD_DEINTERLACE_EDGE_VALUE(n) ((n)<<0)
470
471#define SOLO_VD_CODE_ADR 0x090C
472
473#define SOLO_VD_CTRL 0x0910
474#define SOLO_VD_OPER_ON (1<<31)
475#define SOLO_VD_MAX_ITEM(n) ((n)<<0)
476
477#define SOLO_VD_STATUS0 0x0920
478#define SOLO_VD_STATUS0_INTR_ACK (1<<22)
479#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21)
480#define SOLO_VD_STATUS0_INTR_ERR (1<<20)
481
482#define SOLO_VD_STATUS1 0x0924
483
484#define SOLO_VD_IDX0 0x0930
485#define SOLO_VD_IDX_INTERLACE (1<<30)
486#define SOLO_VD_IDX_CHANNEL(n) ((n)<<24)
487#define SOLO_VD_IDX_SIZE(n) ((n)<<0)
488
489#define SOLO_VD_IDX1 0x0934
490#define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28)
491#define SOLO_VD_IDX_WINDOW(n) ((n)<<24)
492#define SOLO_VD_IDX_DEINTERLACE (1<<16)
493#define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8)
494#define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0)
495
496#define SOLO_VD_IDX2 0x0938
497#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31)
498#define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff)
499
500#define SOLO_VD_IDX3 0x093C
501#define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28)
502#define SOLO_VD_IDX_INTERLACE_WR (1<<27)
503#define SOLO_VD_IDX_INTERPOL (1<<26)
504#define SOLO_VD_IDX_HOR2X (1<<25)
505#define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12)
506#define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0)
507
508#define SOLO_VD_IDX4 0x0940
509#define SOLO_VD_IDX_DEC_WR_PAGE(n) ((n)<<8)
510#define SOLO_VD_IDX_DISP_RD_PAGE(n) ((n)<<0)
511
512#define SOLO_VD_WR_PAGE(n) (0x03F0 + ((n) * 4))
513
514
515#define SOLO_GPIO_CONFIG_0 0x0B00
516#define SOLO_GPIO_CONFIG_1 0x0B04
517#define SOLO_GPIO_DATA_OUT 0x0B08
518#define SOLO_GPIO_DATA_IN 0x0B0C
519#define SOLO_GPIO_INT_ACK_STA 0x0B10
520#define SOLO_GPIO_INT_ENA 0x0B14
521#define SOLO_GPIO_INT_CFG_0 0x0B18
522#define SOLO_GPIO_INT_CFG_1 0x0B1C
523
524
525#define SOLO_IIC_CFG 0x0B20
526#define SOLO_IIC_ENABLE (1<<8)
527#define SOLO_IIC_PRESCALE(n) ((n)<<0)
528
529#define SOLO_IIC_CTRL 0x0B24
530#define SOLO_IIC_AUTO_CLEAR (1<<20)
531#define SOLO_IIC_STATE_RX_ACK (1<<19)
532#define SOLO_IIC_STATE_BUSY (1<<18)
533#define SOLO_IIC_STATE_SIG_ERR (1<<17)
534#define SOLO_IIC_STATE_TRNS (1<<16)
535#define SOLO_IIC_CH_SET(n) ((n)<<5)
536#define SOLO_IIC_ACK_EN (1<<4)
537#define SOLO_IIC_START (1<<3)
538#define SOLO_IIC_STOP (1<<2)
539#define SOLO_IIC_READ (1<<1)
540#define SOLO_IIC_WRITE (1<<0)
541
542#define SOLO_IIC_TXD 0x0B28
543#define SOLO_IIC_RXD 0x0B2C
544
545/*
546 * UART REGISTER
547 */
548#define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20))
549#define SOLO_UART_CLK_DIV(n) ((n)<<24)
550#define SOLO_MODEM_CTRL_EN (1<<20)
551#define SOLO_PARITY_ERROR_DROP (1<<18)
552#define SOLO_IRQ_ERR_EN (1<<17)
553#define SOLO_IRQ_RX_EN (1<<16)
554#define SOLO_IRQ_TX_EN (1<<15)
555#define SOLO_RX_EN (1<<14)
556#define SOLO_TX_EN (1<<13)
557#define SOLO_UART_HALF_DUPLEX (1<<12)
558#define SOLO_UART_LOOPBACK (1<<11)
559
560#define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6))
561#define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6))
562#define SOLO_BAUDRATE_57600 ((0<<9)|(2<<6))
563#define SOLO_BAUDRATE_38400 ((0<<9)|(3<<6))
564#define SOLO_BAUDRATE_19200 ((0<<9)|(4<<6))
565#define SOLO_BAUDRATE_9600 ((0<<9)|(5<<6))
566#define SOLO_BAUDRATE_4800 ((0<<9)|(6<<6))
567#define SOLO_BAUDRATE_2400 ((1<<9)|(6<<6))
568#define SOLO_BAUDRATE_1200 ((2<<9)|(6<<6))
569#define SOLO_BAUDRATE_300 ((3<<9)|(6<<6))
570
571#define SOLO_UART_DATA_BIT_8 (3<<4)
572#define SOLO_UART_DATA_BIT_7 (2<<4)
573#define SOLO_UART_DATA_BIT_6 (1<<4)
574#define SOLO_UART_DATA_BIT_5 (0<<4)
575
576#define SOLO_UART_STOP_BIT_1 (0<<2)
577#define SOLO_UART_STOP_BIT_2 (1<<2)
578
579#define SOLO_UART_PARITY_NONE (0<<0)
580#define SOLO_UART_PARITY_EVEN (2<<0)
581#define SOLO_UART_PARITY_ODD (3<<0)
582
583#define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20))
584#define SOLO_UART_CTS (1<<15)
585#define SOLO_UART_RX_BUSY (1<<14)
586#define SOLO_UART_OVERRUN (1<<13)
587#define SOLO_UART_FRAME_ERR (1<<12)
588#define SOLO_UART_PARITY_ERR (1<<11)
589#define SOLO_UART_TX_BUSY (1<<5)
590
591#define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f)
592#define SOLO_UART_RX_BUFF_SIZE 8
593#define SOLO_UART_TX_BUFF_CNT(stat) (((stat)>>0) & 0x1f)
594#define SOLO_UART_TX_BUFF_SIZE 8
595
596#define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20))
597#define SOLO_UART_TX_DATA_PUSH (1<<8)
598#define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20))
599#define SOLO_UART_RX_DATA_POP (1<<8)
600
601#define SOLO_TIMER_CLOCK_NUM 0x0be0
602#define SOLO_TIMER_WATCHDOG 0x0be4
603#define SOLO_TIMER_USEC 0x0be8
604#define SOLO_TIMER_SEC 0x0bec
605
606#define SOLO_AUDIO_CONTROL 0x0D00
607#define SOLO_AUDIO_ENABLE (1<<31)
608#define SOLO_AUDIO_MASTER_MODE (1<<30)
609#define SOLO_AUDIO_I2S_MODE (1<<29)
610#define SOLO_AUDIO_I2S_LR_SWAP (1<<27)
611#define SOLO_AUDIO_I2S_8BIT (1<<26)
612#define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24)
613#define SOLO_AUDIO_MIX_9TO0 (1<<23)
614#define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20)
615#define SOLO_AUDIO_MIX_19TO10 (1<<19)
616#define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16)
617#define SOLO_AUDIO_MODE(n) ((n)<<0)
618#define SOLO_AUDIO_SAMPLE 0x0D04
619#define SOLO_AUDIO_EE_MODE_ON (1<<30)
620#define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25)
621#define SOLO_AUDIO_BITRATE(n) ((n)<<16)
622#define SOLO_AUDIO_CLK_DIV(n) ((n)<<0)
623#define SOLO_AUDIO_FDMA_INTR 0x0D08
624#define SOLO_AUDIO_FDMA_INTERVAL(n) ((n)<<19)
625#define SOLO_AUDIO_INTR_ORDER(n) ((n)<<16)
626#define SOLO_AUDIO_FDMA_BASE(n) ((n)<<0)
627#define SOLO_AUDIO_EVOL_0 0x0D0C
628#define SOLO_AUDIO_EVOL_1 0x0D10
629#define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10))
630#define SOLO_AUDIO_STA 0x0D14
631
632
633#define SOLO_WATCHDOG 0x0BE4
634#define WATCHDOG_STAT(status) (status<<8)
635#define WATCHDOG_TIME(sec) (sec&0xff)
636
637#endif /* __SOLO6X10_REGISTERS_H */
diff --git a/drivers/staging/solo6x10/solo6x10.h b/drivers/staging/solo6x10/solo6x10.h
new file mode 100644
index 00000000000..abee7213202
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6x10.h
@@ -0,0 +1,336 @@
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_H
21#define __SOLO6X10_H
22
23#include <linux/version.h>
24#include <linux/pci.h>
25#include <linux/i2c.h>
26#include <linux/semaphore.h>
27#include <linux/mutex.h>
28#include <linux/list.h>
29#include <linux/wait.h>
30#include <linux/delay.h>
31#include <linux/slab.h>
32#include <asm/io.h>
33#include <linux/atomic.h>
34#include <linux/videodev2.h>
35#include <media/v4l2-dev.h>
36#include <media/videobuf-core.h>
37#include "registers.h"
38
39#ifndef PCI_VENDOR_ID_SOFTLOGIC
40#define PCI_VENDOR_ID_SOFTLOGIC 0x9413
41#define PCI_DEVICE_ID_SOLO6010 0x6010
42#define PCI_DEVICE_ID_SOLO6110 0x6110
43#endif
44
45#ifndef PCI_VENDOR_ID_BLUECHERRY
46#define PCI_VENDOR_ID_BLUECHERRY 0x1BB3
47/* Neugent Softlogic 6010 based cards */
48#define PCI_DEVICE_ID_NEUSOLO_4 0x4304
49#define PCI_DEVICE_ID_NEUSOLO_9 0x4309
50#define PCI_DEVICE_ID_NEUSOLO_16 0x4310
51/* Bluecherry Softlogic 6010 based cards */
52#define PCI_DEVICE_ID_BC_SOLO_4 0x4E04
53#define PCI_DEVICE_ID_BC_SOLO_9 0x4E09
54#define PCI_DEVICE_ID_BC_SOLO_16 0x4E10
55/* Bluecherry Softlogic 6110 based cards */
56#define PCI_DEVICE_ID_BC_6110_4 0x5304
57#define PCI_DEVICE_ID_BC_6110_8 0x5308
58#define PCI_DEVICE_ID_BC_6110_16 0x5310
59#endif /* Bluecherry */
60
61#define SOLO6X10_NAME "solo6x10"
62
63#define SOLO_MAX_CHANNELS 16
64
65/* Make sure these two match */
66#define SOLO6X10_VERSION "2.1.0"
67#define SOLO6X10_VER_MAJOR 2
68#define SOLO6X10_VER_MINOR 0
69#define SOLO6X10_VER_SUB 0
70#define SOLO6X10_VER_NUM \
71 KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB)
72
73#define FLAGS_6110 1
74
75/*
76 * The SOLO6x10 actually has 8 i2c channels, but we only use 2.
77 * 0 - Techwell chip(s)
78 * 1 - SAA7128
79 */
80#define SOLO_I2C_ADAPTERS 2
81#define SOLO_I2C_TW 0
82#define SOLO_I2C_SAA 1
83
84/* DMA Engine setup */
85#define SOLO_NR_P2M 4
86#define SOLO_NR_P2M_DESC 256
87/* MPEG and JPEG share the same interrupt and locks so they must be together
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/* Encoder standard modes */
99#define SOLO_ENC_MODE_CIF 2
100#define SOLO_ENC_MODE_HD1 1
101#define SOLO_ENC_MODE_D1 9
102
103#define SOLO_DEFAULT_GOP 30
104#define SOLO_DEFAULT_QP 3
105
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
113#define V4L2_BUF_FLAG_MOTION_ON 0x0400
114#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800
115#endif
116#ifndef V4L2_CID_MOTION_ENABLE
117#define PRIVATE_CIDS
118#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0)
119#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1)
120#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2)
121#endif
122
123enum SOLO_I2C_STATE {
124 IIC_STATE_IDLE,
125 IIC_STATE_START,
126 IIC_STATE_READ,
127 IIC_STATE_WRITE,
128 IIC_STATE_STOP
129};
130
131struct p2m_desc {
132 u32 ctrl;
133 u32 ext;
134 u32 ta;
135 u32 fa;
136};
137
138struct solo_p2m_dev {
139 struct mutex mutex;
140 struct completion completion;
141 int error;
142};
143
144#define OSD_TEXT_MAX 30
145
146enum solo_enc_types {
147 SOLO_ENC_TYPE_STD,
148 SOLO_ENC_TYPE_EXT,
149};
150
151struct solo_enc_dev {
152 struct solo_dev *solo_dev;
153 /* V4L2 Items */
154 struct video_device *vfd;
155 /* General accounting */
156 wait_queue_head_t thread_wait;
157 spinlock_t lock;
158 atomic_t readers;
159 u8 ch;
160 u8 mode, gop, qp, interlaced, interval;
161 u8 reset_gop;
162 u8 bw_weight;
163 u8 motion_detected;
164 u16 motion_thresh;
165 u16 width;
166 u16 height;
167 char osd_text[OSD_TEXT_MAX + 1];
168};
169
170struct solo_enc_buf {
171 u8 vop;
172 u8 ch;
173 enum solo_enc_types type;
174 u32 off;
175 u32 size;
176 u32 jpeg_off;
177 u32 jpeg_size;
178 struct timeval ts;
179};
180
181/* The SOLO6x10 PCI Device */
182struct solo_dev {
183 /* General stuff */
184 struct pci_dev *pdev;
185 u8 __iomem *reg_base;
186 int nr_chans;
187 int nr_ext;
188 u32 flags;
189 u32 irq_mask;
190 u32 motion_mask;
191 spinlock_t reg_io_lock;
192
193 /* tw28xx accounting */
194 u8 tw2865, tw2864, tw2815;
195 u8 tw28_cnt;
196
197 /* i2c related items */
198 struct i2c_adapter i2c_adap[SOLO_I2C_ADAPTERS];
199 enum SOLO_I2C_STATE i2c_state;
200 struct mutex i2c_mutex;
201 int i2c_id;
202 wait_queue_head_t i2c_wait;
203 struct i2c_msg *i2c_msg;
204 unsigned int i2c_msg_num;
205 unsigned int i2c_msg_ptr;
206
207 /* P2M DMA Engine */
208 struct solo_p2m_dev p2m_dev[SOLO_NR_P2M];
209
210 /* V4L2 Display items */
211 struct video_device *vfd;
212 unsigned int erasing;
213 unsigned int frame_blank;
214 u8 cur_disp_ch;
215 wait_queue_head_t disp_thread_wait;
216
217 /* V4L2 Encoder items */
218 struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS];
219 u16 enc_bw_remain;
220 /* IDX into hw mp4 encoder */
221 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
226 /* Current video settings */
227 u32 video_type;
228 u16 video_hsize, video_vsize;
229 u16 vout_hstart, vout_vstart;
230 u16 vin_hstart, vin_vstart;
231 u8 fps;
232
233 /* Audio components */
234 struct snd_card *snd_card;
235 struct snd_pcm *snd_pcm;
236 atomic_t snd_users;
237 int g723_hw_idx;
238};
239
240static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
241{
242 unsigned long flags;
243 u32 ret;
244 u16 val;
245
246 spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
247
248 ret = readl(solo_dev->reg_base + reg);
249 rmb();
250 pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
251 rmb();
252
253 spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
254
255 return ret;
256}
257
258static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data)
259{
260 unsigned long flags;
261 u16 val;
262
263 spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
264
265 writel(data, solo_dev->reg_base + reg);
266 wmb();
267 pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
268 rmb();
269
270 spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
271}
272
273void solo_irq_on(struct solo_dev *solo_dev, u32 mask);
274void solo_irq_off(struct solo_dev *solo_dev, u32 mask);
275
276/* Init/exit routeines for subsystems */
277int solo_disp_init(struct solo_dev *solo_dev);
278void solo_disp_exit(struct solo_dev *solo_dev);
279
280int solo_gpio_init(struct solo_dev *solo_dev);
281void solo_gpio_exit(struct solo_dev *solo_dev);
282
283int solo_i2c_init(struct solo_dev *solo_dev);
284void solo_i2c_exit(struct solo_dev *solo_dev);
285
286int solo_p2m_init(struct solo_dev *solo_dev);
287void solo_p2m_exit(struct solo_dev *solo_dev);
288
289int solo_v4l2_init(struct solo_dev *solo_dev);
290void solo_v4l2_exit(struct solo_dev *solo_dev);
291
292int solo_enc_init(struct solo_dev *solo_dev);
293void solo_enc_exit(struct solo_dev *solo_dev);
294
295int solo_enc_v4l2_init(struct solo_dev *solo_dev);
296void solo_enc_v4l2_exit(struct solo_dev *solo_dev);
297
298int solo_g723_init(struct solo_dev *solo_dev);
299void solo_g723_exit(struct solo_dev *solo_dev);
300
301/* ISR's */
302int solo_i2c_isr(struct solo_dev *solo_dev);
303void solo_p2m_isr(struct solo_dev *solo_dev, int id);
304void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status);
305void solo_enc_v4l2_isr(struct solo_dev *solo_dev);
306void solo_g723_isr(struct solo_dev *solo_dev);
307void solo_motion_isr(struct solo_dev *solo_dev);
308void solo_video_in_isr(struct solo_dev *solo_dev);
309
310/* i2c read/write */
311u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off);
312void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off,
313 u8 data);
314
315/* P2M DMA */
316int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
317 dma_addr_t dma_addr, u32 ext_addr, u32 size);
318int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
319 void *sys_addr, u32 ext_addr, u32 size);
320int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
321 struct p2m_desc *pdesc, int wr,
322 struct scatterlist *sglist, u32 sg_off,
323 u32 ext_addr, u32 size);
324void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
325 u32 ext_addr, u32 size, int repeat, u32 ext_size);
326int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
327 struct p2m_desc *desc, int desc_count);
328
329/* Set the threshold for motion detection */
330void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
331#define SOLO_DEF_MOT_THRESH 0x0300
332
333/* Write text on OSD */
334int solo_osd_print(struct solo_enc_dev *solo_enc);
335
336#endif /* __SOLO6X10_H */
diff --git a/drivers/staging/solo6x10/tw28.c b/drivers/staging/solo6x10/tw28.c
new file mode 100644
index 00000000000..db56b42c56c
--- /dev/null
+++ b/drivers/staging/solo6x10/tw28.c
@@ -0,0 +1,821 @@
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#include <linux/kernel.h>
21#include "solo6x10.h"
22#include "tw28.h"
23
24/* XXX: Some of these values are masked into an 8-bit regs, and shifted
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)
28#define DEFAULT_VDELAY_NTSC (7 - 2)
29#define DEFAULT_VACTIVE_NTSC (240 + 4)
30
31#define DEFAULT_HDELAY_PAL (32 + 4)
32#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL)
33#define DEFAULT_VDELAY_PAL (6)
34#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
35
36static u8 tbl_tw2864_template[] = {
37 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
38 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
39 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
40 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
41 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
42 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
43 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
44 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
53 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
54 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
55 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
56 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
57 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
58 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
59 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
62 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
63 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
64 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
65 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
66 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
67 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
68 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
69};
70
71static u8 tbl_tw2865_ntsc_template[] = {
72 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
73 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
74 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
75 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
76 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
77 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
78 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
79 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
80 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
81 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
86 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
87 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
88 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
89 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
90 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
91 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
92 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
93 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
94 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
95 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
96 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
97 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
98 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
99 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
100 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
101 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
102 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
103 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
104};
105
106static u8 tbl_tw2865_pal_template[] = {
107 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
108 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
109 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
110 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
111 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
112 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
113 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
114 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
115 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
116 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
121 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
122 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
123 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
124 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
125 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
126 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
127 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
128 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
129 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
130 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
131 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
132 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
133 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
134 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
135 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
136 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
137 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
138 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
139};
140
141#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
142
143static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
144 u8 tw_off)
145{
146 if (is_tw286x(solo_dev, chip_id))
147 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
148 TW_CHIP_OFFSET_ADDR(chip_id),
149 tw6x_off);
150 else
151 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
152 TW_CHIP_OFFSET_ADDR(chip_id),
153 tw_off);
154}
155
156static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
157 u8 tw6x_off, u8 tw_off, u8 val)
158{
159 if (is_tw286x(solo_dev, chip_id))
160 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
161 TW_CHIP_OFFSET_ADDR(chip_id),
162 tw6x_off, val);
163 else
164 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
165 TW_CHIP_OFFSET_ADDR(chip_id),
166 tw_off, val);
167}
168
169static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
170 u8 val)
171{
172 int i;
173
174 for (i = 0; i < 5; i++) {
175 u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
176 if (rval == val)
177 return;
178
179 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
180 msleep_interruptible(1);
181 }
182
183/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
184 addr, off, val); */
185}
186
187static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
188{
189 u8 tbl_tw2865_common[256];
190 int i;
191
192 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
193 memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
194 sizeof(tbl_tw2865_common));
195 else
196 memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
197 sizeof(tbl_tw2865_common));
198
199 /* ALINK Mode */
200 if (solo_dev->nr_chans == 4) {
201 tbl_tw2865_common[0xd2] = 0x01;
202 tbl_tw2865_common[0xcf] = 0x00;
203 } else if (solo_dev->nr_chans == 8) {
204 tbl_tw2865_common[0xd2] = 0x02;
205 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
206 tbl_tw2865_common[0xcf] = 0x80;
207 } else if (solo_dev->nr_chans == 16) {
208 tbl_tw2865_common[0xd2] = 0x03;
209 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
210 tbl_tw2865_common[0xcf] = 0x83;
211 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
212 tbl_tw2865_common[0xcf] = 0x83;
213 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
214 tbl_tw2865_common[0xcf] = 0x80;
215 }
216
217 for (i = 0; i < 0xff; i++) {
218 /* Skip read only registers */
219 if (i >= 0xb8 && i <= 0xc1)
220 continue;
221 if ((i & ~0x30) == 0x00 ||
222 (i & ~0x30) == 0x0c ||
223 (i & ~0x30) == 0x0d)
224 continue;
225 if (i >= 0xc4 && i <= 0xc7)
226 continue;
227 if (i == 0xfd)
228 continue;
229
230 tw_write_and_verify(solo_dev, dev_addr, i,
231 tbl_tw2865_common[i]);
232 }
233
234 return 0;
235}
236
237static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
238{
239 u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
240 int i;
241
242 memcpy(tbl_tw2864_common, tbl_tw2864_template,
243 sizeof(tbl_tw2864_common));
244
245 if (solo_dev->tw2865 == 0) {
246 /* IRQ Mode */
247 if (solo_dev->nr_chans == 4) {
248 tbl_tw2864_common[0xd2] = 0x01;
249 tbl_tw2864_common[0xcf] = 0x00;
250 } else if (solo_dev->nr_chans == 8) {
251 tbl_tw2864_common[0xd2] = 0x02;
252 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
253 tbl_tw2864_common[0xcf] = 0x43;
254 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
255 tbl_tw2864_common[0xcf] = 0x40;
256 } else if (solo_dev->nr_chans == 16) {
257 tbl_tw2864_common[0xd2] = 0x03;
258 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
259 tbl_tw2864_common[0xcf] = 0x43;
260 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
261 tbl_tw2864_common[0xcf] = 0x43;
262 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
263 tbl_tw2864_common[0xcf] = 0x43;
264 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
265 tbl_tw2864_common[0xcf] = 0x40;
266 }
267 } else {
268 /* ALINK Mode. Assumes that the first tw28xx is a
269 * 2865 and these are in cascade. */
270 for (i = 0; i <= 4; i++)
271 tbl_tw2864_common[0x08 | i << 4] = 0x12;
272
273 if (solo_dev->nr_chans == 8) {
274 tbl_tw2864_common[0xd2] = 0x02;
275 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
276 tbl_tw2864_common[0xcf] = 0x80;
277 } else if (solo_dev->nr_chans == 16) {
278 tbl_tw2864_common[0xd2] = 0x03;
279 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
280 tbl_tw2864_common[0xcf] = 0x83;
281 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
282 tbl_tw2864_common[0xcf] = 0x83;
283 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
284 tbl_tw2864_common[0xcf] = 0x80;
285 }
286 }
287
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++) {
303 /* Skip read only registers */
304 if (i >= 0xb8 && i <= 0xc1)
305 continue;
306 if ((i & ~0x30) == 0x00 ||
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;
313 if (i == 0xfd)
314 continue;
315
316 tw_write_and_verify(solo_dev, dev_addr, i,
317 tbl_tw2864_common[i]);
318 }
319
320 return 0;
321}
322
323static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
324{
325 u8 tbl_ntsc_tw2815_common[] = {
326 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
327 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
328 };
329
330 u8 tbl_pal_tw2815_common[] = {
331 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
332 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
333 };
334
335 u8 tbl_tw2815_sfr[] = {
336 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
337 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
338 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
339 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
340 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
341 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
342 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */
343 };
344 u8 *tbl_tw2815_common;
345 int i;
346 int ch;
347
348 tbl_ntsc_tw2815_common[0x06] = 0;
349
350 /* Horizontal Delay Control */
351 tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
352 tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
353
354 /* Horizontal Active Control */
355 tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
356 tbl_ntsc_tw2815_common[0x06] |=
357 ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
358
359 /* Vertical Delay Control */
360 tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
361 tbl_ntsc_tw2815_common[0x06] |=
362 ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
363
364 /* Vertical Active Control */
365 tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
366 tbl_ntsc_tw2815_common[0x06] |=
367 ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
368
369 tbl_pal_tw2815_common[0x06] = 0;
370
371 /* Horizontal Delay Control */
372 tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
373 tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
374
375 /* Horizontal Active Control */
376 tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
377 tbl_pal_tw2815_common[0x06] |=
378 ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
379
380 /* Vertical Delay Control */
381 tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
382 tbl_pal_tw2815_common[0x06] |=
383 ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
384
385 /* Vertical Active Control */
386 tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
387 tbl_pal_tw2815_common[0x06] |=
388 ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
389
390 tbl_tw2815_common =
391 (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
392 tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
393
394 /* Dual ITU-R BT.656 format */
395 tbl_tw2815_common[0x0d] |= 0x04;
396
397 /* Audio configuration */
398 tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
399
400 if (solo_dev->nr_chans == 4) {
401 tbl_tw2815_sfr[0x63 - 0x40] |= 1;
402 tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
403 } else if (solo_dev->nr_chans == 8) {
404 tbl_tw2815_sfr[0x63 - 0x40] |= 2;
405 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
406 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
407 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
408 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
409 } else if (solo_dev->nr_chans == 16) {
410 tbl_tw2815_sfr[0x63 - 0x40] |= 3;
411 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
412 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
413 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
414 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
415 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
416 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
417 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
418 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
419 }
420
421 /* Output mode of R_ADATM pin (0 mixing, 1 record) */
422 /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
423
424 /* 8KHz, used to be 16KHz, but changed for remote client compat */
425 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
426 tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
427
428 /* Playback of right channel */
429 tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
430
431 /* Reserved value (XXX ??) */
432 tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
433
434 /* Analog output gain and mix ratio playback on full */
435 tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
436 /* Select playback audio and mute all except */
437 tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
438 tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
439
440 /* End of audio configuration */
441
442 for (ch = 0; ch < 4; ch++) {
443 tbl_tw2815_common[0x0d] &= ~3;
444 switch (ch) {
445 case 0:
446 tbl_tw2815_common[0x0d] |= 0x21;
447 break;
448 case 1:
449 tbl_tw2815_common[0x0d] |= 0x20;
450 break;
451 case 2:
452 tbl_tw2815_common[0x0d] |= 0x23;
453 break;
454 case 3:
455 tbl_tw2815_common[0x0d] |= 0x22;
456 break;
457 }
458
459 for (i = 0; i < 0x0f; i++) {
460 if (i == 0x00)
461 continue; /* read-only */
462 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
463 dev_addr, (ch * 0x10) + i,
464 tbl_tw2815_common[i]);
465 }
466 }
467
468 for (i = 0x40; i < 0x76; i++) {
469 /* Skip read-only and nop registers */
470 if (i == 0x40 || i == 0x59 || i == 0x5a ||
471 i == 0x5d || i == 0x5e || i == 0x5f)
472 continue;
473
474 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
475 tbl_tw2815_sfr[i - 0x40]);
476 }
477
478 return 0;
479}
480
481#define FIRST_ACTIVE_LINE 0x0008
482#define LAST_ACTIVE_LINE 0x0102
483
484static void saa7128_setup(struct solo_dev *solo_dev)
485{
486 int i;
487 unsigned char regs[128] = {
488 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
493 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
494 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
495 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
497 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
498 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
499 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
500 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
501 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
502 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
503 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
504 };
505
506 regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
507 regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
508 regs[0x7C] = ((1 << 7) |
509 (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
510 (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
511
512 /* PAL: XXX: We could do a second set of regs to avoid this */
513 if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
514 regs[0x28] = 0xE1;
515
516 regs[0x5A] = 0x0F;
517 regs[0x61] = 0x02;
518 regs[0x62] = 0x35;
519 regs[0x63] = 0xCB;
520 regs[0x64] = 0x8A;
521 regs[0x65] = 0x09;
522 regs[0x66] = 0x2A;
523
524 regs[0x6C] = 0xf1;
525 regs[0x6E] = 0x20;
526
527 regs[0x7A] = 0x06 + 12;
528 regs[0x7b] = 0x24 + 12;
529 regs[0x7c] |= 1 << 6;
530 }
531
532 /* First 0x25 bytes are read-only? */
533 for (i = 0x26; i < 128; i++) {
534 if (i == 0x60 || i == 0x7D)
535 continue;
536 solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
537 }
538
539 return;
540}
541
542int solo_tw28_init(struct solo_dev *solo_dev)
543{
544 int i;
545 u8 value;
546
547 /* Detect techwell chip type */
548 for (i = 0; i < TW_NUM_CHIP; i++) {
549 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
550 TW_CHIP_OFFSET_ADDR(i), 0xFF);
551
552 switch (value >> 3) {
553 case 0x18:
554 solo_dev->tw2865 |= 1 << i;
555 solo_dev->tw28_cnt++;
556 break;
557 case 0x0c:
558 solo_dev->tw2864 |= 1 << i;
559 solo_dev->tw28_cnt++;
560 break;
561 default:
562 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
563 TW_CHIP_OFFSET_ADDR(i), 0x59);
564 if ((value >> 3) == 0x04) {
565 solo_dev->tw2815 |= 1 << i;
566 solo_dev->tw28_cnt++;
567 }
568 }
569 }
570
571 if (!solo_dev->tw28_cnt)
572 return -EINVAL;
573
574 saa7128_setup(solo_dev);
575
576 for (i = 0; i < solo_dev->tw28_cnt; i++) {
577 if ((solo_dev->tw2865 & (1 << i)))
578 tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
579 else if ((solo_dev->tw2864 & (1 << i)))
580 tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
581 else
582 tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
583 }
584
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;
597}
598
599/*
600 * We accessed the video status signal in the Techwell chip through
601 * iic/i2c because the video status reported by register REG_VI_STATUS1
602 * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
603 * status signal values.
604 */
605int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
606{
607 u8 val, chip_num;
608
609 /* Get the right chip and on-chip channel */
610 chip_num = ch / 4;
611 ch %= 4;
612
613 val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
614 TW_AV_STAT_ADDR) & 0x0f;
615
616 return val & (1 << ch) ? 1 : 0;
617}
618
619#if 0
620/* Status of audio from up to 4 techwell chips are combined into 1 variable.
621 * See techwell datasheet for details. */
622u16 tw28_get_audio_status(struct solo_dev *solo_dev)
623{
624 u8 val;
625 u16 status = 0;
626 int i;
627
628 for (i = 0; i < solo_dev->tw28_cnt; i++) {
629 val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
630 TW_AV_STAT_ADDR) & 0xf0) >> 4;
631 status |= val << (i * 4);
632 }
633
634 return status;
635}
636#endif
637
638int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
639{
640 char sval;
641 u8 chip_num;
642
643 /* Get the right chip and on-chip channel */
644 chip_num = ch / 4;
645 ch %= 4;
646
647 if (val > 255 || val < 0)
648 return -ERANGE;
649
650 switch (ctrl) {
651 case V4L2_CID_SHARPNESS:
652 /* Only 286x has sharpness */
653 if (val > 0x0f || val < 0)
654 return -ERANGE;
655 if (is_tw286x(solo_dev, chip_num)) {
656 u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
657 TW_CHIP_OFFSET_ADDR(chip_num),
658 TW286x_SHARPNESS(chip_num));
659 v &= 0xf0;
660 v |= val;
661 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
662 TW_CHIP_OFFSET_ADDR(chip_num),
663 TW286x_SHARPNESS(chip_num), v);
664 } else if (val != 0)
665 return -ERANGE;
666 break;
667
668 case V4L2_CID_HUE:
669 if (is_tw286x(solo_dev, chip_num))
670 sval = val - 128;
671 else
672 sval = (char)val;
673 tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
674 TW_HUE_ADDR(ch), sval);
675
676 break;
677
678 case V4L2_CID_SATURATION:
679 if (is_tw286x(solo_dev, chip_num)) {
680 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
681 TW_CHIP_OFFSET_ADDR(chip_num),
682 TW286x_SATURATIONU_ADDR(ch), val);
683 }
684 tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
685 TW_SATURATION_ADDR(ch), val);
686
687 break;
688
689 case V4L2_CID_CONTRAST:
690 tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
691 TW_CONTRAST_ADDR(ch), val);
692 break;
693
694 case V4L2_CID_BRIGHTNESS:
695 if (is_tw286x(solo_dev, chip_num))
696 sval = val - 128;
697 else
698 sval = (char)val;
699 tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
700 TW_BRIGHTNESS_ADDR(ch), sval);
701
702 break;
703 default:
704 return -EINVAL;
705 }
706
707 return 0;
708}
709
710int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
711 s32 *val)
712{
713 u8 rval, chip_num;
714
715 /* Get the right chip and on-chip channel */
716 chip_num = ch / 4;
717 ch %= 4;
718
719 switch (ctrl) {
720 case V4L2_CID_SHARPNESS:
721 /* Only 286x has sharpness */
722 if (is_tw286x(solo_dev, chip_num)) {
723 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
724 TW_CHIP_OFFSET_ADDR(chip_num),
725 TW286x_SHARPNESS(chip_num));
726 *val = rval & 0x0f;
727 } else
728 *val = 0;
729 break;
730 case V4L2_CID_HUE:
731 rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
732 TW_HUE_ADDR(ch));
733 if (is_tw286x(solo_dev, chip_num))
734 *val = (s32)((char)rval) + 128;
735 else
736 *val = rval;
737 break;
738 case V4L2_CID_SATURATION:
739 *val = tw_readbyte(solo_dev, chip_num,
740 TW286x_SATURATIONU_ADDR(ch),
741 TW_SATURATION_ADDR(ch));
742 break;
743 case V4L2_CID_CONTRAST:
744 *val = tw_readbyte(solo_dev, chip_num,
745 TW286x_CONTRAST_ADDR(ch),
746 TW_CONTRAST_ADDR(ch));
747 break;
748 case V4L2_CID_BRIGHTNESS:
749 rval = tw_readbyte(solo_dev, chip_num,
750 TW286x_BRIGHTNESS_ADDR(ch),
751 TW_BRIGHTNESS_ADDR(ch));
752 if (is_tw286x(solo_dev, chip_num))
753 *val = (s32)((char)rval) + 128;
754 else
755 *val = rval;
756 break;
757 default:
758 return -EINVAL;
759 }
760
761 return 0;
762}
763
764#if 0
765/*
766 * For audio output volume, the output channel is only 1. In this case we
767 * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
768 * is the base address of the techwell chip.
769 */
770void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
771{
772 unsigned int val;
773 unsigned int chip_num;
774
775 chip_num = (solo_dev->nr_chans - 1) / 4;
776
777 val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
778 TW_AUDIO_OUTPUT_VOL_ADDR);
779
780 u_val = (val & 0x0f) | (u_val << 4);
781
782 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
783 TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
784}
785#endif
786
787u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
788{
789 u8 val;
790 u8 chip_num;
791
792 /* Get the right chip and on-chip channel */
793 chip_num = ch / 4;
794 ch %= 4;
795
796 val = tw_readbyte(solo_dev, chip_num,
797 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
798 TW_AUDIO_INPUT_GAIN_ADDR(ch));
799
800 return (ch % 2) ? (val >> 4) : (val & 0x0f);
801}
802
803void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
804{
805 u8 old_val;
806 u8 chip_num;
807
808 /* Get the right chip and on-chip channel */
809 chip_num = ch / 4;
810 ch %= 4;
811
812 old_val = tw_readbyte(solo_dev, chip_num,
813 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
814 TW_AUDIO_INPUT_GAIN_ADDR(ch));
815
816 val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
817 ((ch % 2) ? (val << 4) : val);
818
819 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
820 TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
821}
diff --git a/drivers/staging/solo6x10/tw28.h b/drivers/staging/solo6x10/tw28.h
new file mode 100644
index 00000000000..a44a03afbd3
--- /dev/null
+++ b/drivers/staging/solo6x10/tw28.h
@@ -0,0 +1,63 @@
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_TW28_H
21#define __SOLO6X10_TW28_H
22
23#include "solo6x10.h"
24
25#define TW_NUM_CHIP 4
26#define TW_BASE_ADDR 0x28
27#define TW_CHIP_OFFSET_ADDR(n) (TW_BASE_ADDR + (n))
28
29/* tw2815 */
30#define TW_AV_STAT_ADDR 0x5a
31#define TW_HUE_ADDR(n) (0x07 | ((n) << 4))
32#define TW_SATURATION_ADDR(n) (0x08 | ((n) << 4))
33#define TW_CONTRAST_ADDR(n) (0x09 | ((n) << 4))
34#define TW_BRIGHTNESS_ADDR(n) (0x0a | ((n) << 4))
35#define TW_AUDIO_OUTPUT_VOL_ADDR 0x70
36#define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0))
37
38/* tw286x */
39#define TW286X_AV_STAT_ADDR 0xfd
40#define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4))
41#define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4))
42#define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4))
43#define TW286x_CONTRAST_ADDR(n) (0x02 | ((n) << 4))
44#define TW286x_BRIGHTNESS_ADDR(n) (0x01 | ((n) << 4))
45#define TW286x_SHARPNESS(n) (0x03 | ((n) << 4))
46#define TW286x_AUDIO_OUTPUT_VOL_ADDR 0xdf
47#define TW286x_AUDIO_INPUT_GAIN_ADDR(n) (0xD0 + ((n > 1) ? 1 : 0))
48
49int solo_tw28_init(struct solo_dev *solo_dev);
50
51int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
52int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
53
54u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
55void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
56int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch);
57
58#if 0
59unsigned int tw2815_get_audio_status(struct SOLO *solo);
60void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val);
61#endif
62
63#endif /* __SOLO6X10_TW28_H */
diff --git a/drivers/staging/solo6x10/v4l2-enc.c b/drivers/staging/solo6x10/v4l2-enc.c
new file mode 100644
index 00000000000..bee7280bbed
--- /dev/null
+++ b/drivers/staging/solo6x10/v4l2-enc.c
@@ -0,0 +1,1825 @@
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#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/kthread.h>
23#include <linux/freezer.h>
24#include <media/v4l2-ioctl.h>
25#include <media/v4l2-common.h>
26#include <media/videobuf-dma-sg.h>
27#include "solo6x10.h"
28#include "tw28.h"
29#include "jpeg.h"
30
31#define MIN_VID_BUFFERS 4
32#define FRAME_BUF_SIZE (128 * 1024)
33#define MP4_QS 16
34
35static int solo_enc_thread(void *data);
36
37extern unsigned video_nr;
38
39struct solo_enc_fh {
40 struct solo_enc_dev *enc;
41 u32 fmt;
42 u16 rd_idx;
43 u8 enc_on;
44 enum solo_enc_types type;
45 struct videobuf_queue vidq;
46 struct list_head vidq_active;
47 struct task_struct *kthread;
48 struct p2m_desc desc[SOLO_NR_P2M_DESC];
49};
50
51static const u32 solo_user_ctrls[] = {
52 V4L2_CID_BRIGHTNESS,
53 V4L2_CID_CONTRAST,
54 V4L2_CID_SATURATION,
55 V4L2_CID_HUE,
56 V4L2_CID_SHARPNESS,
57 0
58};
59
60static const u32 solo_mpeg_ctrls[] = {
61 V4L2_CID_MPEG_VIDEO_ENCODING,
62 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
63 0
64};
65
66static const u32 solo_private_ctrls[] = {
67 V4L2_CID_MOTION_ENABLE,
68 V4L2_CID_MOTION_THRESHOLD,
69 0
70};
71
72static const u32 solo_fmtx_ctrls[] = {
73 V4L2_CID_RDS_TX_RADIO_TEXT,
74 0
75};
76
77static const u32 *solo_ctrl_classes[] = {
78 solo_user_ctrls,
79 solo_mpeg_ctrls,
80 solo_fmtx_ctrls,
81 solo_private_ctrls,
82 NULL
83};
84
85static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
86{
87 struct solo_dev *solo_dev = solo_enc->solo_dev;
88 u8 ch = solo_enc->ch;
89
90 if (solo_dev->motion_mask & (1 << ch))
91 return 1;
92 return 0;
93}
94
95static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
96{
97 struct solo_dev *solo_dev = solo_enc->solo_dev;
98 u8 ch = solo_enc->ch;
99
100 spin_lock(&solo_enc->lock);
101
102 if (on)
103 solo_dev->motion_mask |= (1 << ch);
104 else
105 solo_dev->motion_mask &= ~(1 << ch);
106
107 /* Do this regardless of if we are turning on or off */
108 solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
109 1 << solo_enc->ch);
110 solo_enc->motion_detected = 0;
111
112 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
113 SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
114 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
115
116 if (solo_dev->motion_mask)
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}
123
124/* Should be called with solo_enc->lock held */
125static void solo_update_mode(struct solo_enc_dev *solo_enc)
126{
127 struct solo_dev *solo_dev = solo_enc->solo_dev;
128
129 assert_spin_locked(&solo_enc->lock);
130
131 solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
132 solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
133
134 switch (solo_enc->mode) {
135 case SOLO_ENC_MODE_CIF:
136 solo_enc->width = solo_dev->video_hsize >> 1;
137 solo_enc->height = solo_dev->video_vsize;
138 break;
139 case SOLO_ENC_MODE_D1:
140 solo_enc->width = solo_dev->video_hsize;
141 solo_enc->height = solo_dev->video_vsize << 1;
142 solo_enc->bw_weight <<= 2;
143 break;
144 default:
145 WARN(1, "mode is unknown\n");
146 }
147}
148
149/* Should be called with solo_enc->lock held */
150static int solo_enc_on(struct solo_enc_fh *fh)
151{
152 struct solo_enc_dev *solo_enc = fh->enc;
153 u8 ch = solo_enc->ch;
154 struct solo_dev *solo_dev = solo_enc->solo_dev;
155 u8 interval;
156
157 assert_spin_locked(&solo_enc->lock);
158
159 if (fh->enc_on)
160 return 0;
161
162 solo_update_mode(solo_enc);
163
164 /* Make sure to bw check on first reader */
165 if (!atomic_read(&solo_enc->readers)) {
166 if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
167 return -EBUSY;
168 else
169 solo_dev->enc_bw_remain -= solo_enc->bw_weight;
170 }
171
172 fh->enc_on = 1;
173 fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
174
175 if (fh->type == SOLO_ENC_TYPE_EXT)
176 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
177
178 if (atomic_inc_return(&solo_enc->readers) > 1)
179 return 0;
180
181 /* Disable all encoding for this channel */
182 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
183
184 /* Common for both std and ext encoding */
185 solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
186 solo_enc->interlaced ? 1 : 0);
187
188 if (solo_enc->interlaced)
189 interval = solo_enc->interval - 1;
190 else
191 interval = solo_enc->interval;
192
193 /* Standard encoding only */
194 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
195 solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
196 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
197
198 /* Extended encoding only */
199 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
200 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
201 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
202
203 /* Enables the standard encoder */
204 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
205
206 /* Settle down Beavis... */
207 mdelay(10);
208
209 return 0;
210}
211
212static void solo_enc_off(struct solo_enc_fh *fh)
213{
214 struct solo_enc_dev *solo_enc = fh->enc;
215 struct solo_dev *solo_dev = solo_enc->solo_dev;
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
228 if (atomic_dec_return(&solo_enc->readers) > 0)
229 return;
230
231 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
232 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
233}
234
235static int solo_start_fh_thread(struct solo_enc_fh *fh)
236{
237 struct solo_enc_dev *solo_enc = fh->enc;
238
239 fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc");
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
250 return 0;
251}
252
253static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch)
254{
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
260static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop)
261{
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
273static void enc_write_sg(struct scatterlist *sglist, void *buf, int size)
274{
275 struct scatterlist *sg;
276 u8 *src = buf;
277
278 for (sg = sglist; sg && size > 0; sg = sg_next(sg)) {
279 u8 *p = sg_virt(sg);
280 size_t len = sg_dma_len(sg);
281 int i;
282
283 for (i = 0; i < len && size; i++)
284 p[i] = *(src++);
285 }
286}
287
288static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev,
289 struct p2m_desc *desc,
290 struct scatterlist *sglist, int skip,
291 unsigned int off, unsigned int size)
292{
293 int ret;
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
314 return ret;
315}
316
317static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev,
318 dma_addr_t buf, unsigned int off,
319 unsigned int size)
320{
321 int ret;
322
323 if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
324 return -EINVAL;
325
326 if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
327 return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
328 SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
329 }
330
331 /* Buffer wrap */
332 ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
333 SOLO_MP4E_EXT_ADDR(solo_dev) + off,
334 SOLO_MP4E_EXT_SIZE(solo_dev) - off);
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
344static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf,
345 unsigned int off, unsigned int size)
346{
347 int ret;
348
349 dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size,
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
354 return ret;
355}
356
357static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev,
358 struct p2m_desc *desc,
359 struct scatterlist *sglist, int skip,
360 unsigned int off, unsigned int size)
361{
362 int ret;
363
364 if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
365 return -EINVAL;
366
367 if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) {
368 return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG,
369 desc, 0, sglist, skip,
370 SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
371 }
372
373 /* Buffer wrap */
374 ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
375 sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off,
376 SOLO_JPEG_EXT_SIZE(solo_dev) - off);
377
378 ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
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
383 return ret;
384}
385
386/* Returns true of __chk is within the first __range bytes of __off */
387#define OFF_IN_RANGE(__off, __range, __chk) \
388 ((__off <= __chk) && ((__off + __range) >= __chk))
389
390static void solo_jpeg_header(struct solo_enc_dev *solo_enc,
391 struct videobuf_dmabuf *vbuf)
392{
393 struct scatterlist *sg;
394 void *src = jpeg_header;
395 size_t copied = 0;
396 size_t to_copy = sizeof(jpeg_header);
397
398 for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) {
399 size_t this_copy = min(sg_dma_len(sg),
400 (unsigned int)(to_copy - copied));
401 u8 *p = sg_virt(sg);
402
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 }
418}
419
420static 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
438static inline int vop_interlaced(__le32 *vh)
439{
440 return (__le32_to_cpu(vh[0]) >> 30) & 1;
441}
442
443static inline u32 vop_size(__le32 *vh)
444{
445 return __le32_to_cpu(vh[0]) & 0xFFFFF;
446}
447
448static inline u8 vop_hsize(__le32 *vh)
449{
450 return (__le32_to_cpu(vh[1]) >> 8) & 0xFF;
451}
452
453static 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 */
459static 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
466static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count)
467{
468
469 value <<= 32 - count; // shift to the right
470
471 while (count--) {
472 **out <<= 1;
473 **out |= !!(value & (1 << 31)); /* MSB */
474 value <<= 1;
475 if (++(*bits) % 8 == 0)
476 (*out)++;
477 }
478}
479
480static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */
481{
482 uint32_t max = 0, cnt = 0;
483
484 while (value > max) {
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
492static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */
493{
494 if (value <= 0)
495 write_ue(out, bits, -value * 2);
496 else
497 write_ue(out, bits, value * 2 - 1);
498}
499
500static void write_mpeg4_end(u8 **out, unsigned *bits)
501{
502 write_bits(out, bits, 0, 1);
503 /* align on 32-bit boundary */
504 if (*bits % 32)
505 write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32);
506}
507
508static void write_h264_end(u8 **out, unsigned *bits, int align)
509{
510 write_bits(out, bits, 1, 1);
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
518static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev,
519 __le32 *vh, unsigned fps, unsigned interval)
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
572static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh)
573{
574 static const u8 sps[] = {
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}
619
620static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
621 struct videobuf_buffer *vb,
622 struct videobuf_dmabuf *vbuf)
623{
624 struct solo_enc_dev *solo_enc = fh->enc;
625 struct solo_dev *solo_dev = solo_enc->solo_dev;
626
627#define VH_WORDS 16
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;
634
635 if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
636 return -EINVAL;
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
643 if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size))
644 return -EINVAL;
645
646 vb->width = vop_hsize(vh) << 4;
647 vb->height = vop_vsize(vh) << 4;
648 vb->size = vop_size(vh);
649
650 /* If this is a key frame, add extra m4v header */
651 if (!enc_buf->vop) {
652 u8 header[MAX_VOL_HEADER_LENGTH], *out = header;
653
654 if (solo_dev->flags & FLAGS_6110)
655 h264_write_vol(&out, solo_dev, vh);
656 else
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 }
665
666 /* Now get the actual mpeg payload */
667 frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
668 frame_size = enc_buf->size - sizeof(vh);
669
670 ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
671 skip, frame_off, frame_size);
672 WARN_ON_ONCE(ret);
673
674 return ret;
675}
676
677static void solo_enc_fillbuf(struct solo_enc_fh *fh,
678 struct videobuf_buffer *vb)
679{
680 struct solo_enc_dev *solo_enc = fh->enc;
681 struct solo_dev *solo_dev = solo_enc->solo_dev;
682 struct solo_enc_buf *enc_buf = NULL;
683 struct videobuf_dmabuf *vbuf;
684 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
691 idx = (idx + 1) % SOLO_NR_RING_BUFS;
692
693 if (ebuf->ch != solo_enc->ch)
694 continue;
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 }
706
707 fh->rd_idx = idx;
708
709 if (WARN_ON_ONCE(!enc_buf))
710 goto buf_err;
711
712 if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
713 vb->bsize < enc_buf->size) ||
714 (fh->fmt == V4L2_PIX_FMT_MJPEG &&
715 vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
716 WARN_ON_ONCE(1);
717 goto buf_err;
718 }
719
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)
725 ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
726 else
727 ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
728
729 if (!ret)
730 error = 0;
731
732buf_err:
733 if (error) {
734 vb->state = VIDEOBUF_ERROR;
735 } else {
736 vb->field_count++;
737 vb->ts = enc_buf->ts;
738 vb->state = VIDEOBUF_DONE;
739 }
740
741 wake_up(&vb->done);
742
743 return;
744}
745
746static void solo_enc_thread_try(struct solo_enc_fh *fh)
747{
748 struct solo_enc_dev *solo_enc = fh->enc;
749 struct solo_dev *solo_dev = solo_enc->solo_dev;
750 struct videobuf_buffer *vb;
751
752 for (;;) {
753 spin_lock(&solo_enc->lock);
754
755 if (fh->rd_idx == solo_dev->enc_wr_idx)
756 break;
757
758 if (list_empty(&fh->vidq_active))
759 break;
760
761 vb = list_first_entry(&fh->vidq_active,
762 struct videobuf_buffer, queue);
763
764 if (!waitqueue_active(&vb->done))
765 break;
766
767 list_del(&vb->queue);
768
769 spin_unlock(&solo_enc->lock);
770
771 solo_enc_fillbuf(fh, vb);
772 }
773
774 assert_spin_locked(&solo_enc->lock);
775 spin_unlock(&solo_enc->lock);
776}
777
778static 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
784 set_freezable();
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 }
794
795 remove_wait_queue(&solo_enc->thread_wait, &wait);
796
797 return 0;
798}
799
800void solo_motion_isr(struct solo_dev *solo_dev)
801{
802 u32 status;
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}
822
823void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
824{
825 struct solo_enc_buf *enc_buf;
826 u32 mpeg_current, mpeg_next, mpeg_size;
827 u32 jpeg_current, jpeg_next, jpeg_size;
828 u32 reg_mpeg_size;
829 u8 cur_q, vop_type;
830 u8 ch;
831 enum solo_enc_types enc_type;
832
833 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER);
834
835 cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS;
836
837 reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7;
838
839 while (solo_dev->enc_idx != cur_q) {
840 mpeg_current = solo_reg_read(solo_dev,
841 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;
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
850 ch = (mpeg_current >> 24) & 0x1f;
851 if (ch >= SOLO_MAX_CHANNELS) {
852 ch -= SOLO_MAX_CHANNELS;
853 enc_type = SOLO_ENC_TYPE_EXT;
854 } else
855 enc_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
872 /* XXX I think this means we had a ring overflow? */
873 if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) {
874 enc_reset_gop(solo_dev, ch);
875 continue;
876 }
877
878 /* When resetting the GOP, skip frames until I-frame */
879 if (enc_gop_reset(solo_dev, ch, vop_type))
880 continue;
881
882 enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx];
883
884 enc_buf->vop = vop_type;
885 enc_buf->ch = ch;
886 enc_buf->off = mpeg_current;
887 enc_buf->size = mpeg_size;
888 enc_buf->jpeg_off = jpeg_current;
889 enc_buf->jpeg_size = jpeg_size;
890 enc_buf->type = enc_type;
891
892 do_gettimeofday(&enc_buf->ts);
893
894 solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) %
895 SOLO_NR_RING_BUFS;
896
897 wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait);
898 }
899
900 return;
901}
902
903static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
904 unsigned int *size)
905{
906 *size = FRAME_BUF_SIZE;
907
908 if (*count < MIN_VID_BUFFERS)
909 *count = MIN_VID_BUFFERS;
910
911 return 0;
912}
913
914static int solo_enc_buf_prepare(struct videobuf_queue *vq,
915 struct videobuf_buffer *vb,
916 enum v4l2_field field)
917{
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;
922 if (vb->baddr != 0 && vb->bsize < vb->size)
923 return -EINVAL;
924
925 /* These properties only change when queue is idle */
926 vb->width = solo_enc->width;
927 vb->height = solo_enc->height;
928 vb->field = field;
929
930 if (vb->state == VIDEOBUF_NEEDS_INIT) {
931 int rc = videobuf_iolock(vq, vb, NULL);
932 if (rc < 0) {
933 struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
934 videobuf_dma_unmap(vq->dev, dma);
935 videobuf_dma_free(dma);
936 vb->state = VIDEOBUF_NEEDS_INIT;
937 return rc;
938 }
939 }
940 vb->state = VIDEOBUF_PREPARED;
941
942 return 0;
943}
944
945static void solo_enc_buf_queue(struct videobuf_queue *vq,
946 struct videobuf_buffer *vb)
947{
948 struct solo_enc_fh *fh = vq->priv_data;
949
950 vb->state = VIDEOBUF_QUEUED;
951 list_add_tail(&vb->queue, &fh->vidq_active);
952 wake_up_interruptible(&fh->enc->thread_wait);
953}
954
955static void solo_enc_buf_release(struct videobuf_queue *vq,
956 struct videobuf_buffer *vb)
957{
958 struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
959
960 videobuf_dma_unmap(vq->dev, dma);
961 videobuf_dma_free(dma);
962 vb->state = VIDEOBUF_NEEDS_INIT;
963}
964
965static struct videobuf_queue_ops solo_enc_video_qops = {
966 .buf_setup = solo_enc_buf_setup,
967 .buf_prepare = solo_enc_buf_prepare,
968 .buf_queue = solo_enc_buf_queue,
969 .buf_release = solo_enc_buf_release,
970};
971
972static unsigned int solo_enc_poll(struct file *file,
973 struct poll_table_struct *wait)
974{
975 struct solo_enc_fh *fh = file->private_data;
976
977 return videobuf_poll_stream(file, &fh->vidq, wait);
978}
979
980static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
981{
982 struct solo_enc_fh *fh = file->private_data;
983
984 return videobuf_mmap_mapper(&fh->vidq, vma);
985}
986
987static int solo_enc_open(struct file *file)
988{
989 struct solo_enc_dev *solo_enc = video_drvdata(file);
990 struct solo_enc_fh *fh;
991
992 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
993 if (fh == NULL)
994 return -ENOMEM;
995
996 fh->enc = solo_enc;
997 file->private_data = fh;
998 INIT_LIST_HEAD(&fh->vidq_active);
999 fh->fmt = V4L2_PIX_FMT_MPEG;
1000 fh->type = SOLO_ENC_TYPE_STD;
1001
1002 videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops,
1003 &solo_enc->solo_dev->pdev->dev,
1004 &solo_enc->lock,
1005 V4L2_BUF_TYPE_VIDEO_CAPTURE,
1006 V4L2_FIELD_INTERLACED,
1007 sizeof(struct videobuf_buffer), fh, NULL);
1008
1009 return 0;
1010}
1011
1012static ssize_t solo_enc_read(struct file *file, char __user *data,
1013 size_t count, loff_t *ppos)
1014{
1015 struct solo_enc_fh *fh = file->private_data;
1016 struct solo_enc_dev *solo_enc = fh->enc;
1017
1018 /* Make sure the encoder is on */
1019 if (!fh->enc_on) {
1020 int ret;
1021
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
1033 return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
1034 file->f_flags & O_NONBLOCK);
1035}
1036
1037static int solo_enc_release(struct file *file)
1038{
1039 struct solo_enc_fh *fh = file->private_data;
1040 struct solo_enc_dev *solo_enc = fh->enc;
1041
1042 videobuf_stop(&fh->vidq);
1043 videobuf_mmap_free(&fh->vidq);
1044
1045 spin_lock(&solo_enc->lock);
1046 solo_enc_off(fh);
1047 spin_unlock(&solo_enc->lock);
1048
1049 kfree(fh);
1050
1051 return 0;
1052}
1053
1054static int solo_enc_querycap(struct file *file, void *priv,
1055 struct v4l2_capability *cap)
1056{
1057 struct solo_enc_fh *fh = priv;
1058 struct solo_enc_dev *solo_enc = fh->enc;
1059 struct solo_dev *solo_dev = solo_enc->solo_dev;
1060
1061 strcpy(cap->driver, SOLO6X10_NAME);
1062 snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
1063 solo_enc->ch);
1064 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
1065 pci_name(solo_dev->pdev));
1066 cap->version = SOLO6X10_VER_NUM;
1067 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
1068 V4L2_CAP_READWRITE |
1069 V4L2_CAP_STREAMING;
1070 return 0;
1071}
1072
1073static int solo_enc_enum_input(struct file *file, void *priv,
1074 struct v4l2_input *input)
1075{
1076 struct solo_enc_fh *fh = priv;
1077 struct solo_enc_dev *solo_enc = fh->enc;
1078 struct solo_dev *solo_dev = solo_enc->solo_dev;
1079
1080 if (input->index)
1081 return -EINVAL;
1082
1083 snprintf(input->name, sizeof(input->name), "Encoder %d",
1084 solo_enc->ch + 1);
1085 input->type = V4L2_INPUT_TYPE_CAMERA;
1086
1087 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
1088 input->std = V4L2_STD_NTSC_M;
1089 else
1090 input->std = V4L2_STD_PAL_B;
1091
1092 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
1093 input->status = V4L2_IN_ST_NO_SIGNAL;
1094
1095 return 0;
1096}
1097
1098static int solo_enc_set_input(struct file *file, void *priv, unsigned int index)
1099{
1100 if (index)
1101 return -EINVAL;
1102
1103 return 0;
1104}
1105
1106static int solo_enc_get_input(struct file *file, void *priv,
1107 unsigned int *index)
1108{
1109 *index = 0;
1110
1111 return 0;
1112}
1113
1114static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
1115 struct v4l2_fmtdesc *f)
1116{
1117 switch (f->index) {
1118 case 0:
1119 f->pixelformat = V4L2_PIX_FMT_MPEG;
1120 strcpy(f->description, "MPEG-4 AVC");
1121 break;
1122 case 1:
1123 f->pixelformat = V4L2_PIX_FMT_MJPEG;
1124 strcpy(f->description, "MJPEG");
1125 break;
1126 default:
1127 return -EINVAL;
1128 }
1129
1130 f->flags = V4L2_FMT_FLAG_COMPRESSED;
1131
1132 return 0;
1133}
1134
1135static int solo_enc_try_fmt_cap(struct file *file, void *priv,
1136 struct v4l2_format *f)
1137{
1138 struct solo_enc_fh *fh = priv;
1139 struct solo_enc_dev *solo_enc = fh->enc;
1140 struct solo_dev *solo_dev = solo_enc->solo_dev;
1141 struct v4l2_pix_format *pix = &f->fmt.pix;
1142
1143 if (pix->pixelformat != V4L2_PIX_FMT_MPEG &&
1144 pix->pixelformat != V4L2_PIX_FMT_MJPEG)
1145 return -EINVAL;
1146
1147 /* We cannot change width/height in mid read */
1148 if (atomic_read(&solo_enc->readers) > 0) {
1149 if (pix->width != solo_enc->width ||
1150 pix->height != solo_enc->height)
1151 return -EBUSY;
1152 }
1153
1154 if (pix->width < solo_dev->video_hsize ||
1155 pix->height < solo_dev->video_vsize << 1) {
1156 /* Default to CIF 1/2 size */
1157 pix->width = solo_dev->video_hsize >> 1;
1158 pix->height = solo_dev->video_vsize;
1159 } else {
1160 /* Full frame */
1161 pix->width = solo_dev->video_hsize;
1162 pix->height = solo_dev->video_vsize << 1;
1163 }
1164
1165 if (pix->field == V4L2_FIELD_ANY)
1166 pix->field = V4L2_FIELD_INTERLACED;
1167 else if (pix->field != V4L2_FIELD_INTERLACED)
1168 pix->field = V4L2_FIELD_INTERLACED;
1169
1170 /* Just set these */
1171 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
1172 pix->sizeimage = FRAME_BUF_SIZE;
1173
1174 return 0;
1175}
1176
1177static int solo_enc_set_fmt_cap(struct file *file, void *priv,
1178 struct v4l2_format *f)
1179{
1180 struct solo_enc_fh *fh = priv;
1181 struct solo_enc_dev *solo_enc = fh->enc;
1182 struct solo_dev *solo_dev = solo_enc->solo_dev;
1183 struct v4l2_pix_format *pix = &f->fmt.pix;
1184 int ret;
1185
1186 spin_lock(&solo_enc->lock);
1187
1188 ret = solo_enc_try_fmt_cap(file, priv, f);
1189 if (ret) {
1190 spin_unlock(&solo_enc->lock);
1191 return ret;
1192 }
1193
1194 if (pix->width == solo_dev->video_hsize)
1195 solo_enc->mode = SOLO_ENC_MODE_D1;
1196 else
1197 solo_enc->mode = SOLO_ENC_MODE_CIF;
1198
1199 /* This does not change the encoder at all */
1200 fh->fmt = pix->pixelformat;
1201
1202 if (pix->priv)
1203 fh->type = SOLO_ENC_TYPE_EXT;
1204 ret = solo_enc_on(fh);
1205
1206 spin_unlock(&solo_enc->lock);
1207
1208 if (ret)
1209 return ret;
1210
1211 return solo_start_fh_thread(fh);
1212}
1213
1214static int solo_enc_get_fmt_cap(struct file *file, void *priv,
1215 struct v4l2_format *f)
1216{
1217 struct solo_enc_fh *fh = priv;
1218 struct solo_enc_dev *solo_enc = fh->enc;
1219 struct v4l2_pix_format *pix = &f->fmt.pix;
1220
1221 pix->width = solo_enc->width;
1222 pix->height = solo_enc->height;
1223 pix->pixelformat = fh->fmt;
1224 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
1225 V4L2_FIELD_NONE;
1226 pix->sizeimage = FRAME_BUF_SIZE;
1227 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
1228
1229 return 0;
1230}
1231
1232static int solo_enc_reqbufs(struct file *file, void *priv,
1233 struct v4l2_requestbuffers *req)
1234{
1235 struct solo_enc_fh *fh = priv;
1236
1237 return videobuf_reqbufs(&fh->vidq, req);
1238}
1239
1240static int solo_enc_querybuf(struct file *file, void *priv,
1241 struct v4l2_buffer *buf)
1242{
1243 struct solo_enc_fh *fh = priv;
1244
1245 return videobuf_querybuf(&fh->vidq, buf);
1246}
1247
1248static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
1249{
1250 struct solo_enc_fh *fh = priv;
1251
1252 return videobuf_qbuf(&fh->vidq, buf);
1253}
1254
1255static int solo_enc_dqbuf(struct file *file, void *priv,
1256 struct v4l2_buffer *buf)
1257{
1258 struct solo_enc_fh *fh = priv;
1259 struct solo_enc_dev *solo_enc = fh->enc;
1260 int ret;
1261
1262 /* Make sure the encoder is on */
1263 if (!fh->enc_on) {
1264 spin_lock(&solo_enc->lock);
1265 ret = solo_enc_on(fh);
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
1275 ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
1276 if (ret)
1277 return ret;
1278
1279 /* Signal motion detection */
1280 if (solo_is_motion_on(solo_enc)) {
1281 buf->flags |= V4L2_BUF_FLAG_MOTION_ON;
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
1304 return 0;
1305}
1306
1307static int solo_enc_streamon(struct file *file, void *priv,
1308 enum v4l2_buf_type i)
1309{
1310 struct solo_enc_fh *fh = priv;
1311
1312 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1313 return -EINVAL;
1314
1315 return videobuf_streamon(&fh->vidq);
1316}
1317
1318static int solo_enc_streamoff(struct file *file, void *priv,
1319 enum v4l2_buf_type i)
1320{
1321 struct solo_enc_fh *fh = priv;
1322
1323 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1324 return -EINVAL;
1325
1326 return videobuf_streamoff(&fh->vidq);
1327}
1328
1329static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i)
1330{
1331 return 0;
1332}
1333
1334static int solo_enum_framesizes(struct file *file, void *priv,
1335 struct v4l2_frmsizeenum *fsize)
1336{
1337 struct solo_enc_fh *fh = priv;
1338 struct solo_dev *solo_dev = fh->enc->solo_dev;
1339
1340 if (fsize->pixel_format != V4L2_PIX_FMT_MPEG)
1341 return -EINVAL;
1342
1343 switch (fsize->index) {
1344 case 0:
1345 fsize->discrete.width = solo_dev->video_hsize >> 1;
1346 fsize->discrete.height = solo_dev->video_vsize;
1347 break;
1348 case 1:
1349 fsize->discrete.width = solo_dev->video_hsize;
1350 fsize->discrete.height = solo_dev->video_vsize << 1;
1351 break;
1352 default:
1353 return -EINVAL;
1354 }
1355
1356 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1357
1358 return 0;
1359}
1360
1361static int solo_enum_frameintervals(struct file *file, void *priv,
1362 struct v4l2_frmivalenum *fintv)
1363{
1364 struct solo_enc_fh *fh = priv;
1365 struct solo_dev *solo_dev = fh->enc->solo_dev;
1366
1367 if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index)
1368 return -EINVAL;
1369
1370 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1371
1372 fintv->stepwise.min.numerator = solo_dev->fps;
1373 fintv->stepwise.min.denominator = 1;
1374
1375 fintv->stepwise.max.numerator = solo_dev->fps;
1376 fintv->stepwise.max.denominator = 15;
1377
1378 fintv->stepwise.step.numerator = 1;
1379 fintv->stepwise.step.denominator = 1;
1380
1381 return 0;
1382}
1383
1384static int solo_g_parm(struct file *file, void *priv,
1385 struct v4l2_streamparm *sp)
1386{
1387 struct solo_enc_fh *fh = priv;
1388 struct solo_enc_dev *solo_enc = fh->enc;
1389 struct solo_dev *solo_dev = solo_enc->solo_dev;
1390 struct v4l2_captureparm *cp = &sp->parm.capture;
1391
1392 cp->capability = V4L2_CAP_TIMEPERFRAME;
1393 cp->timeperframe.numerator = solo_enc->interval;
1394 cp->timeperframe.denominator = solo_dev->fps;
1395 cp->capturemode = 0;
1396 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1397 cp->readbuffers = 2;
1398
1399 return 0;
1400}
1401
1402static int solo_s_parm(struct file *file, void *priv,
1403 struct v4l2_streamparm *sp)
1404{
1405 struct solo_enc_fh *fh = priv;
1406 struct solo_enc_dev *solo_enc = fh->enc;
1407 struct solo_dev *solo_dev = solo_enc->solo_dev;
1408 struct v4l2_captureparm *cp = &sp->parm.capture;
1409
1410 spin_lock(&solo_enc->lock);
1411
1412 if (atomic_read(&solo_enc->readers) > 0) {
1413 spin_unlock(&solo_enc->lock);
1414 return -EBUSY;
1415 }
1416
1417 if ((cp->timeperframe.numerator == 0) ||
1418 (cp->timeperframe.denominator == 0)) {
1419 /* reset framerate */
1420 cp->timeperframe.numerator = 1;
1421 cp->timeperframe.denominator = solo_dev->fps;
1422 }
1423
1424 if (cp->timeperframe.denominator != solo_dev->fps)
1425 cp->timeperframe.denominator = solo_dev->fps;
1426
1427 if (cp->timeperframe.numerator > 15)
1428 cp->timeperframe.numerator = 15;
1429
1430 solo_enc->interval = cp->timeperframe.numerator;
1431
1432 cp->capability = V4L2_CAP_TIMEPERFRAME;
1433
1434 solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1);
1435 solo_update_mode(solo_enc);
1436
1437 spin_unlock(&solo_enc->lock);
1438
1439 return 0;
1440}
1441
1442static int solo_queryctrl(struct file *file, void *priv,
1443 struct v4l2_queryctrl *qc)
1444{
1445 struct solo_enc_fh *fh = priv;
1446 struct solo_enc_dev *solo_enc = fh->enc;
1447 struct solo_dev *solo_dev = solo_enc->solo_dev;
1448
1449 qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
1450 if (!qc->id)
1451 return -EINVAL;
1452
1453 switch (qc->id) {
1454 case V4L2_CID_BRIGHTNESS:
1455 case V4L2_CID_CONTRAST:
1456 case V4L2_CID_SATURATION:
1457 case V4L2_CID_HUE:
1458 return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80);
1459 case V4L2_CID_SHARPNESS:
1460 return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00);
1461 case V4L2_CID_MPEG_VIDEO_ENCODING:
1462 return v4l2_ctrl_query_fill(
1463 qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
1464 V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
1465 V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
1466 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1467 return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps);
1468#ifdef PRIVATE_CIDS
1469 case V4L2_CID_MOTION_THRESHOLD:
1470 qc->flags |= V4L2_CTRL_FLAG_SLIDER;
1471 qc->type = V4L2_CTRL_TYPE_INTEGER;
1472 qc->minimum = 0;
1473 qc->maximum = 0xffff;
1474 qc->step = 1;
1475 qc->default_value = SOLO_DEF_MOT_THRESH;
1476 strlcpy(qc->name, "Motion Detection Threshold",
1477 sizeof(qc->name));
1478 return 0;
1479 case V4L2_CID_MOTION_ENABLE:
1480 qc->type = V4L2_CTRL_TYPE_BOOLEAN;
1481 qc->minimum = 0;
1482 qc->maximum = qc->step = 1;
1483 qc->default_value = 0;
1484 strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name));
1485 return 0;
1486#else
1487 case V4L2_CID_MOTION_THRESHOLD:
1488 return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1,
1489 SOLO_DEF_MOT_THRESH);
1490 case V4L2_CID_MOTION_ENABLE:
1491 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
1492#endif
1493 case V4L2_CID_RDS_TX_RADIO_TEXT:
1494 qc->type = V4L2_CTRL_TYPE_STRING;
1495 qc->minimum = 0;
1496 qc->maximum = OSD_TEXT_MAX;
1497 qc->step = 1;
1498 qc->default_value = 0;
1499 strlcpy(qc->name, "OSD Text", sizeof(qc->name));
1500 return 0;
1501 }
1502
1503 return -EINVAL;
1504}
1505
1506static int solo_querymenu(struct file *file, void *priv,
1507 struct v4l2_querymenu *qmenu)
1508{
1509 struct v4l2_queryctrl qctrl;
1510 int err;
1511
1512 qctrl.id = qmenu->id;
1513 err = solo_queryctrl(file, priv, &qctrl);
1514 if (err)
1515 return err;
1516
1517 return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
1518}
1519
1520static int solo_g_ctrl(struct file *file, void *priv,
1521 struct v4l2_control *ctrl)
1522{
1523 struct solo_enc_fh *fh = priv;
1524 struct solo_enc_dev *solo_enc = fh->enc;
1525 struct solo_dev *solo_dev = solo_enc->solo_dev;
1526
1527 switch (ctrl->id) {
1528 case V4L2_CID_BRIGHTNESS:
1529 case V4L2_CID_CONTRAST:
1530 case V4L2_CID_SATURATION:
1531 case V4L2_CID_HUE:
1532 case V4L2_CID_SHARPNESS:
1533 return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
1534 &ctrl->value);
1535 case V4L2_CID_MPEG_VIDEO_ENCODING:
1536 ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
1537 break;
1538 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1539 ctrl->value = solo_enc->gop;
1540 break;
1541 case V4L2_CID_MOTION_THRESHOLD:
1542 ctrl->value = solo_enc->motion_thresh;
1543 break;
1544 case V4L2_CID_MOTION_ENABLE:
1545 ctrl->value = solo_is_motion_on(solo_enc);
1546 break;
1547 default:
1548 return -EINVAL;
1549 }
1550
1551 return 0;
1552}
1553
1554static int solo_s_ctrl(struct file *file, void *priv,
1555 struct v4l2_control *ctrl)
1556{
1557 struct solo_enc_fh *fh = priv;
1558 struct solo_enc_dev *solo_enc = fh->enc;
1559 struct solo_dev *solo_dev = solo_enc->solo_dev;
1560
1561 switch (ctrl->id) {
1562 case V4L2_CID_BRIGHTNESS:
1563 case V4L2_CID_CONTRAST:
1564 case V4L2_CID_SATURATION:
1565 case V4L2_CID_HUE:
1566 case V4L2_CID_SHARPNESS:
1567 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
1568 ctrl->value);
1569 case V4L2_CID_MPEG_VIDEO_ENCODING:
1570 if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
1571 return -ERANGE;
1572 break;
1573 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1574 if (ctrl->value < 1 || ctrl->value > 255)
1575 return -ERANGE;
1576 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;
1582 case V4L2_CID_MOTION_THRESHOLD:
1583 /* TODO accept value on lower 16-bits and use high
1584 * 16-bits to assign the value to a specific block */
1585 if (ctrl->value < 0 || ctrl->value > 0xffff)
1586 return -ERANGE;
1587 solo_enc->motion_thresh = ctrl->value;
1588 solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value);
1589 break;
1590 case V4L2_CID_MOTION_ENABLE:
1591 solo_motion_toggle(solo_enc, ctrl->value);
1592 break;
1593 default:
1594 return -EINVAL;
1595 }
1596
1597 return 0;
1598}
1599
1600static int solo_s_ext_ctrls(struct file *file, void *priv,
1601 struct v4l2_ext_controls *ctrls)
1602{
1603 struct solo_enc_fh *fh = priv;
1604 struct solo_enc_dev *solo_enc = fh->enc;
1605 int i;
1606
1607 for (i = 0; i < ctrls->count; i++) {
1608 struct v4l2_ext_control *ctrl = (ctrls->controls + i);
1609 int err;
1610
1611 switch (ctrl->id) {
1612 case V4L2_CID_RDS_TX_RADIO_TEXT:
1613 if (ctrl->size - 1 > OSD_TEXT_MAX)
1614 err = -ERANGE;
1615 else {
1616 err = copy_from_user(solo_enc->osd_text,
1617 ctrl->string,
1618 OSD_TEXT_MAX);
1619 solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
1620 if (!err)
1621 err = solo_osd_print(solo_enc);
1622 }
1623 break;
1624 default:
1625 err = -EINVAL;
1626 }
1627
1628 if (err < 0) {
1629 ctrls->error_idx = i;
1630 return err;
1631 }
1632 }
1633
1634 return 0;
1635}
1636
1637static int solo_g_ext_ctrls(struct file *file, void *priv,
1638 struct v4l2_ext_controls *ctrls)
1639{
1640 struct solo_enc_fh *fh = priv;
1641 struct solo_enc_dev *solo_enc = fh->enc;
1642 int i;
1643
1644 for (i = 0; i < ctrls->count; i++) {
1645 struct v4l2_ext_control *ctrl = (ctrls->controls + i);
1646 int err;
1647
1648 switch (ctrl->id) {
1649 case V4L2_CID_RDS_TX_RADIO_TEXT:
1650 if (ctrl->size < OSD_TEXT_MAX) {
1651 ctrl->size = OSD_TEXT_MAX;
1652 err = -ENOSPC;
1653 } else {
1654 err = copy_to_user(ctrl->string,
1655 solo_enc->osd_text,
1656 OSD_TEXT_MAX);
1657 }
1658 break;
1659 default:
1660 err = -EINVAL;
1661 }
1662
1663 if (err < 0) {
1664 ctrls->error_idx = i;
1665 return err;
1666 }
1667 }
1668
1669 return 0;
1670}
1671
1672static const struct v4l2_file_operations solo_enc_fops = {
1673 .owner = THIS_MODULE,
1674 .open = solo_enc_open,
1675 .release = solo_enc_release,
1676 .read = solo_enc_read,
1677 .poll = solo_enc_poll,
1678 .mmap = solo_enc_mmap,
1679 .ioctl = video_ioctl2,
1680};
1681
1682static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1683 .vidioc_querycap = solo_enc_querycap,
1684 .vidioc_s_std = solo_enc_s_std,
1685 /* Input callbacks */
1686 .vidioc_enum_input = solo_enc_enum_input,
1687 .vidioc_s_input = solo_enc_set_input,
1688 .vidioc_g_input = solo_enc_get_input,
1689 /* Video capture format callbacks */
1690 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1691 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1692 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1693 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1694 /* Streaming I/O */
1695 .vidioc_reqbufs = solo_enc_reqbufs,
1696 .vidioc_querybuf = solo_enc_querybuf,
1697 .vidioc_qbuf = solo_enc_qbuf,
1698 .vidioc_dqbuf = solo_enc_dqbuf,
1699 .vidioc_streamon = solo_enc_streamon,
1700 .vidioc_streamoff = solo_enc_streamoff,
1701 /* Frame size and interval */
1702 .vidioc_enum_framesizes = solo_enum_framesizes,
1703 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1704 /* Video capture parameters */
1705 .vidioc_s_parm = solo_s_parm,
1706 .vidioc_g_parm = solo_g_parm,
1707 /* Controls */
1708 .vidioc_queryctrl = solo_queryctrl,
1709 .vidioc_querymenu = solo_querymenu,
1710 .vidioc_g_ctrl = solo_g_ctrl,
1711 .vidioc_s_ctrl = solo_s_ctrl,
1712 .vidioc_g_ext_ctrls = solo_g_ext_ctrls,
1713 .vidioc_s_ext_ctrls = solo_s_ext_ctrls,
1714};
1715
1716static struct video_device solo_enc_template = {
1717 .name = SOLO6X10_NAME,
1718 .fops = &solo_enc_fops,
1719 .ioctl_ops = &solo_enc_ioctl_ops,
1720 .minor = -1,
1721 .release = video_device_release,
1722
1723 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
1724 .current_norm = V4L2_STD_NTSC_M,
1725};
1726
1727static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch)
1728{
1729 struct solo_enc_dev *solo_enc;
1730 int ret;
1731
1732 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1733 if (!solo_enc)
1734 return ERR_PTR(-ENOMEM);
1735
1736 solo_enc->vfd = video_device_alloc();
1737 if (!solo_enc->vfd) {
1738 kfree(solo_enc);
1739 return ERR_PTR(-ENOMEM);
1740 }
1741
1742 solo_enc->solo_dev = solo_dev;
1743 solo_enc->ch = ch;
1744
1745 *solo_enc->vfd = solo_enc_template;
1746 solo_enc->vfd->parent = &solo_dev->pdev->dev;
1747 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER,
1748 video_nr);
1749 if (ret < 0) {
1750 video_device_release(solo_enc->vfd);
1751 kfree(solo_enc);
1752 return ERR_PTR(ret);
1753 }
1754
1755 video_set_drvdata(solo_enc->vfd, solo_enc);
1756
1757 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1758 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
1759 solo_enc->vfd->num);
1760
1761 if (video_nr != -1)
1762 video_nr++;
1763
1764 spin_lock_init(&solo_enc->lock);
1765 init_waitqueue_head(&solo_enc->thread_wait);
1766 atomic_set(&solo_enc->readers, 0);
1767
1768 solo_enc->qp = SOLO_DEFAULT_QP;
1769 solo_enc->gop = solo_dev->fps;
1770 solo_enc->interval = 1;
1771 solo_enc->mode = SOLO_ENC_MODE_CIF;
1772 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
1773
1774 spin_lock(&solo_enc->lock);
1775 solo_update_mode(solo_enc);
1776 spin_unlock(&solo_enc->lock);
1777
1778 return solo_enc;
1779}
1780
1781static void solo_enc_free(struct solo_enc_dev *solo_enc)
1782{
1783 if (solo_enc == NULL)
1784 return;
1785
1786 video_unregister_device(solo_enc->vfd);
1787 kfree(solo_enc);
1788}
1789
1790int solo_enc_v4l2_init(struct solo_dev *solo_dev)
1791{
1792 int i;
1793
1794 for (i = 0; i < solo_dev->nr_chans; i++) {
1795 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i);
1796 if (IS_ERR(solo_dev->v4l2_enc[i]))
1797 break;
1798 }
1799
1800 if (i != solo_dev->nr_chans) {
1801 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
1802 while (i--)
1803 solo_enc_free(solo_dev->v4l2_enc[i]);
1804 return ret;
1805 }
1806
1807 /* D1@MAX-FPS * 4 */
1808 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1809
1810 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1811 solo_dev->v4l2_enc[0]->vfd->num,
1812 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1813
1814 return 0;
1815}
1816
1817void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
1818{
1819 int i;
1820
1821 solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
1822
1823 for (i = 0; i < solo_dev->nr_chans; i++)
1824 solo_enc_free(solo_dev->v4l2_enc[i]);
1825}
diff --git a/drivers/staging/solo6x10/v4l2.c b/drivers/staging/solo6x10/v4l2.c
new file mode 100644
index 00000000000..571c3a348d3
--- /dev/null
+++ b/drivers/staging/solo6x10/v4l2.c
@@ -0,0 +1,964 @@
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#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/kthread.h>
23#include <linux/freezer.h>
24#include <media/v4l2-ioctl.h>
25#include <media/v4l2-common.h>
26#include <media/videobuf-dma-sg.h>
27#include "solo6x10.h"
28#include "tw28.h"
29
30#define SOLO_HW_BPL 2048
31#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
32
33/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
34#define solo_vlines(__solo) (__solo->video_vsize * 2)
35#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
36 solo_vlines(__solo))
37#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
38
39#define MIN_VID_BUFFERS 4
40
41/* Simple file handle */
42struct solo_filehandle {
43 struct solo_dev *solo_dev;
44 struct videobuf_queue vidq;
45 struct task_struct *kthread;
46 spinlock_t slock;
47 int old_write;
48 struct list_head vidq_active;
49 struct p2m_desc desc[SOLO_NR_P2M_DESC];
50 int desc_idx;
51};
52
53unsigned video_nr = -1;
54module_param(video_nr, uint, 0644);
55MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
56
57static void erase_on(struct solo_dev *solo_dev)
58{
59 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
60 solo_dev->erasing = 1;
61 solo_dev->frame_blank = 0;
62}
63
64static int erase_off(struct solo_dev *solo_dev)
65{
66 if (!solo_dev->erasing)
67 return 0;
68
69 /* First time around, assert erase off */
70 if (!solo_dev->frame_blank)
71 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
72 /* Keep the erasing flag on for 8 frames minimum */
73 if (solo_dev->frame_blank++ >= 8)
74 solo_dev->erasing = 0;
75
76 return 1;
77}
78
79void solo_video_in_isr(struct solo_dev *solo_dev)
80{
81 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
82 wake_up_interruptible(&solo_dev->disp_thread_wait);
83}
84
85static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
86 int sx, int sy, int ex, int ey, int scale)
87{
88 if (ch >= solo_dev->nr_chans)
89 return;
90
91 /* Here, we just keep window/channel the same */
92 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
93 SOLO_VI_WIN_CHANNEL(ch) |
94 SOLO_VI_WIN_SX(sx) |
95 SOLO_VI_WIN_EX(ex) |
96 SOLO_VI_WIN_SCALE(scale));
97
98 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
99 SOLO_VI_WIN_SY(sy) |
100 SOLO_VI_WIN_EY(ey));
101}
102
103static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
104{
105 u8 ch = idx * 4;
106
107 if (ch >= solo_dev->nr_chans)
108 return -EINVAL;
109
110 if (!on) {
111 u8 i;
112 for (i = ch; i < ch + 4; i++)
113 solo_win_setup(solo_dev, i, solo_dev->video_hsize,
114 solo_vlines(solo_dev),
115 solo_dev->video_hsize,
116 solo_vlines(solo_dev), 0);
117 return 0;
118 }
119
120 /* Row 1 */
121 solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
122 solo_vlines(solo_dev) / 2, 3);
123 solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
124 solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
125 /* Row 2 */
126 solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
127 solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
128 solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
129 solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
130 solo_vlines(solo_dev), 3);
131
132 return 0;
133}
134
135static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
136{
137 int sy, ysize, hsize, i;
138
139 if (!on) {
140 for (i = 0; i < 16; i++)
141 solo_win_setup(solo_dev, i, solo_dev->video_hsize,
142 solo_vlines(solo_dev),
143 solo_dev->video_hsize,
144 solo_vlines(solo_dev), 0);
145 return 0;
146 }
147
148 ysize = solo_vlines(solo_dev) / 4;
149 hsize = solo_dev->video_hsize / 4;
150
151 for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
152 solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
153 sy + ysize, 5);
154 solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
155 hsize * 2, sy + ysize, 5);
156 solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
157 hsize * 3, sy + ysize, 5);
158 solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
159 solo_dev->video_hsize, sy + ysize, 5);
160 }
161
162 return 0;
163}
164
165static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
166{
167 u8 ext_ch;
168
169 if (ch < solo_dev->nr_chans) {
170 solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
171 on ? 0 : solo_vlines(solo_dev),
172 solo_dev->video_hsize, solo_vlines(solo_dev),
173 on ? 1 : 0);
174 return 0;
175 }
176
177 if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
178 return -EINVAL;
179
180 ext_ch = ch - solo_dev->nr_chans;
181
182 /* 4up's first */
183 if (ext_ch < 4)
184 return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
185
186 /* Remaining case is 16up for 16-port */
187 return solo_v4l2_ch_ext_16up(solo_dev, on);
188}
189
190static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
191{
192 if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
193 return -EINVAL;
194
195 erase_on(solo_dev);
196
197 solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
198 solo_v4l2_ch(solo_dev, ch, 1);
199
200 solo_dev->cur_disp_ch = ch;
201
202 return 0;
203}
204
205static 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
212static 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
226static 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
242static void solo_fillbuf(struct solo_filehandle *fh,
243 struct videobuf_buffer *vb)
244{
245 struct solo_dev *solo_dev = fh->solo_dev;
246 struct videobuf_dmabuf *vbuf;
247 unsigned int fdma_addr;
248 int error = 1;
249 int i;
250 struct scatterlist *sg;
251 dma_addr_t sg_dma;
252 int sg_size_left;
253
254 vbuf = videobuf_to_dma(vb);
255 if (!vbuf)
256 goto finish_buf;
257
258 if (erase_off(solo_dev)) {
259 int i;
260
261 /* Just blit to the entire sg list, ignoring size */
262 for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
263 void *p = sg_virt(sg);
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 }
271
272 error = 0;
273 goto finish_buf;
274 }
275
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
335 i += lines - 1;
336 fdma_addr += SOLO_HW_BPL * lines;
337 sg_dma += lines * line_len;
338 sg_size_left -= lines * line_len;
339 }
340
341 error = disp_flush_descs(fh);
342
343finish_buf:
344 if (error) {
345 vb->state = VIDEOBUF_ERROR;
346 } else {
347 vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
348 vb->state = VIDEOBUF_DONE;
349 vb->field_count++;
350 do_gettimeofday(&vb->ts);
351 }
352
353 wake_up(&vb->done);
354
355 return;
356}
357
358static void solo_thread_try(struct solo_filehandle *fh)
359{
360 struct videobuf_buffer *vb;
361 unsigned int cur_write;
362
363 for (;;) {
364 spin_lock(&fh->slock);
365
366 if (list_empty(&fh->vidq_active))
367 break;
368
369 vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
370 queue);
371
372 if (!waitqueue_active(&vb->done))
373 break;
374
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;
381 list_del(&vb->queue);
382
383 spin_unlock(&fh->slock);
384
385 solo_fillbuf(fh, vb);
386 }
387
388 assert_spin_locked(&fh->slock);
389 spin_unlock(&fh->slock);
390}
391
392static int solo_thread(void *data)
393{
394 struct solo_filehandle *fh = data;
395 struct solo_dev *solo_dev = fh->solo_dev;
396 DECLARE_WAITQUEUE(wait, current);
397
398 set_freezable();
399 add_wait_queue(&solo_dev->disp_thread_wait, &wait);
400
401 for (;;) {
402 long timeout = schedule_timeout_interruptible(HZ);
403 if (timeout == -ERESTARTSYS || kthread_should_stop())
404 break;
405 solo_thread_try(fh);
406 try_to_freeze();
407 }
408
409 remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
410
411 return 0;
412}
413
414static int solo_start_thread(struct solo_filehandle *fh)
415{
416 fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp");
417
418 if (IS_ERR(fh->kthread))
419 return PTR_ERR(fh->kthread);
420
421 return 0;
422}
423
424static void solo_stop_thread(struct solo_filehandle *fh)
425{
426 if (fh->kthread) {
427 kthread_stop(fh->kthread);
428 fh->kthread = NULL;
429 }
430}
431
432static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
433 unsigned int *size)
434{
435 struct solo_filehandle *fh = vq->priv_data;
436 struct solo_dev *solo_dev = fh->solo_dev;
437
438 *size = solo_image_size(solo_dev);
439
440 if (*count < MIN_VID_BUFFERS)
441 *count = MIN_VID_BUFFERS;
442
443 return 0;
444}
445
446static int solo_buf_prepare(struct videobuf_queue *vq,
447 struct videobuf_buffer *vb, enum v4l2_field field)
448{
449 struct solo_filehandle *fh = vq->priv_data;
450 struct solo_dev *solo_dev = fh->solo_dev;
451
452 vb->size = solo_image_size(solo_dev);
453 if (vb->baddr != 0 && vb->bsize < vb->size)
454 return -EINVAL;
455
456 /* XXX: These properties only change when queue is idle */
457 vb->width = solo_dev->video_hsize;
458 vb->height = solo_vlines(solo_dev);
459 vb->bytesperline = solo_bytesperline(solo_dev);
460 vb->field = field;
461
462 if (vb->state == VIDEOBUF_NEEDS_INIT) {
463 int rc = videobuf_iolock(vq, vb, NULL);
464 if (rc < 0) {
465 struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
466 videobuf_dma_unmap(vq->dev, dma);
467 videobuf_dma_free(dma);
468 vb->state = VIDEOBUF_NEEDS_INIT;
469 return rc;
470 }
471 }
472 vb->state = VIDEOBUF_PREPARED;
473
474 return 0;
475}
476
477static void solo_buf_queue(struct videobuf_queue *vq,
478 struct videobuf_buffer *vb)
479{
480 struct solo_filehandle *fh = vq->priv_data;
481 struct solo_dev *solo_dev = fh->solo_dev;
482
483 vb->state = VIDEOBUF_QUEUED;
484 list_add_tail(&vb->queue, &fh->vidq_active);
485 wake_up_interruptible(&solo_dev->disp_thread_wait);
486}
487
488static void solo_buf_release(struct videobuf_queue *vq,
489 struct videobuf_buffer *vb)
490{
491 struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
492
493 videobuf_dma_unmap(vq->dev, dma);
494 videobuf_dma_free(dma);
495 vb->state = VIDEOBUF_NEEDS_INIT;
496}
497
498static struct videobuf_queue_ops solo_video_qops = {
499 .buf_setup = solo_buf_setup,
500 .buf_prepare = solo_buf_prepare,
501 .buf_queue = solo_buf_queue,
502 .buf_release = solo_buf_release,
503};
504
505static unsigned int solo_v4l2_poll(struct file *file,
506 struct poll_table_struct *wait)
507{
508 struct solo_filehandle *fh = file->private_data;
509
510 return videobuf_poll_stream(file, &fh->vidq, wait);
511}
512
513static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
514{
515 struct solo_filehandle *fh = file->private_data;
516
517 return videobuf_mmap_mapper(&fh->vidq, vma);
518}
519
520static int solo_v4l2_open(struct file *file)
521{
522 struct solo_dev *solo_dev = video_drvdata(file);
523 struct solo_filehandle *fh;
524 int ret;
525
526 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
527 if (fh == NULL)
528 return -ENOMEM;
529
530 spin_lock_init(&fh->slock);
531 INIT_LIST_HEAD(&fh->vidq_active);
532 fh->solo_dev = solo_dev;
533 file->private_data = fh;
534
535 ret = solo_start_thread(fh);
536 if (ret) {
537 kfree(fh);
538 return ret;
539 }
540
541 videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
542 &solo_dev->pdev->dev, &fh->slock,
543 V4L2_BUF_TYPE_VIDEO_CAPTURE,
544 SOLO_DISP_PIX_FIELD,
545 sizeof(struct videobuf_buffer), fh, NULL);
546
547 return 0;
548}
549
550static ssize_t solo_v4l2_read(struct file *file, char __user *data,
551 size_t count, loff_t *ppos)
552{
553 struct solo_filehandle *fh = file->private_data;
554
555 return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
556 file->f_flags & O_NONBLOCK);
557}
558
559static int solo_v4l2_release(struct file *file)
560{
561 struct solo_filehandle *fh = file->private_data;
562
563 videobuf_stop(&fh->vidq);
564 videobuf_mmap_free(&fh->vidq);
565 solo_stop_thread(fh);
566 kfree(fh);
567
568 return 0;
569}
570
571static int solo_querycap(struct file *file, void *priv,
572 struct v4l2_capability *cap)
573{
574 struct solo_filehandle *fh = priv;
575 struct solo_dev *solo_dev = fh->solo_dev;
576
577 strcpy(cap->driver, SOLO6X10_NAME);
578 strcpy(cap->card, "Softlogic 6x10");
579 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
580 pci_name(solo_dev->pdev));
581 cap->version = SOLO6X10_VER_NUM;
582 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
583 V4L2_CAP_READWRITE |
584 V4L2_CAP_STREAMING;
585 return 0;
586}
587
588static int solo_enum_ext_input(struct solo_dev *solo_dev,
589 struct v4l2_input *input)
590{
591 static const char *dispnames_1[] = { "4UP" };
592 static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
593 static const char *dispnames_5[] = {
594 "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
595 };
596 const char **dispnames;
597
598 if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
599 return -EINVAL;
600
601 if (solo_dev->nr_ext == 5)
602 dispnames = dispnames_5;
603 else if (solo_dev->nr_ext == 2)
604 dispnames = dispnames_2;
605 else
606 dispnames = dispnames_1;
607
608 snprintf(input->name, sizeof(input->name), "Multi %s",
609 dispnames[input->index - solo_dev->nr_chans]);
610
611 return 0;
612}
613
614static int solo_enum_input(struct file *file, void *priv,
615 struct v4l2_input *input)
616{
617 struct solo_filehandle *fh = priv;
618 struct solo_dev *solo_dev = fh->solo_dev;
619
620 if (input->index >= solo_dev->nr_chans) {
621 int ret = solo_enum_ext_input(solo_dev, input);
622 if (ret < 0)
623 return ret;
624 } else {
625 snprintf(input->name, sizeof(input->name), "Camera %d",
626 input->index + 1);
627
628 /* We can only check this for normal inputs */
629 if (!tw28_get_video_status(solo_dev, input->index))
630 input->status = V4L2_IN_ST_NO_SIGNAL;
631 }
632
633 input->type = V4L2_INPUT_TYPE_CAMERA;
634
635 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
636 input->std = V4L2_STD_NTSC_M;
637 else
638 input->std = V4L2_STD_PAL_B;
639
640 return 0;
641}
642
643static int solo_set_input(struct file *file, void *priv, unsigned int index)
644{
645 struct solo_filehandle *fh = priv;
646
647 return solo_v4l2_set_ch(fh->solo_dev, index);
648}
649
650static int solo_get_input(struct file *file, void *priv, unsigned int *index)
651{
652 struct solo_filehandle *fh = priv;
653
654 *index = fh->solo_dev->cur_disp_ch;
655
656 return 0;
657}
658
659static int solo_enum_fmt_cap(struct file *file, void *priv,
660 struct v4l2_fmtdesc *f)
661{
662 if (f->index)
663 return -EINVAL;
664
665 f->pixelformat = V4L2_PIX_FMT_UYVY;
666 strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
667
668 return 0;
669}
670
671static int solo_try_fmt_cap(struct file *file, void *priv,
672 struct v4l2_format *f)
673{
674 struct solo_filehandle *fh = priv;
675 struct solo_dev *solo_dev = fh->solo_dev;
676 struct v4l2_pix_format *pix = &f->fmt.pix;
677 int image_size = solo_image_size(solo_dev);
678
679 /* Check supported sizes */
680 if (pix->width != solo_dev->video_hsize)
681 pix->width = solo_dev->video_hsize;
682 if (pix->height != solo_vlines(solo_dev))
683 pix->height = solo_vlines(solo_dev);
684 if (pix->sizeimage != image_size)
685 pix->sizeimage = image_size;
686
687 /* Check formats */
688 if (pix->field == V4L2_FIELD_ANY)
689 pix->field = SOLO_DISP_PIX_FIELD;
690
691 if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
692 pix->field != SOLO_DISP_PIX_FIELD ||
693 pix->colorspace != V4L2_COLORSPACE_SMPTE170M)
694 return -EINVAL;
695
696 return 0;
697}
698
699static int solo_set_fmt_cap(struct file *file, void *priv,
700 struct v4l2_format *f)
701{
702 struct solo_filehandle *fh = priv;
703
704 if (videobuf_queue_is_busy(&fh->vidq))
705 return -EBUSY;
706
707 /* For right now, if it doesn't match our running config,
708 * then fail */
709 return solo_try_fmt_cap(file, priv, f);
710}
711
712static int solo_get_fmt_cap(struct file *file, void *priv,
713 struct v4l2_format *f)
714{
715 struct solo_filehandle *fh = priv;
716 struct solo_dev *solo_dev = fh->solo_dev;
717 struct v4l2_pix_format *pix = &f->fmt.pix;
718
719 pix->width = solo_dev->video_hsize;
720 pix->height = solo_vlines(solo_dev);
721 pix->pixelformat = V4L2_PIX_FMT_UYVY;
722 pix->field = SOLO_DISP_PIX_FIELD;
723 pix->sizeimage = solo_image_size(solo_dev);
724 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
725 pix->bytesperline = solo_bytesperline(solo_dev);
726
727 return 0;
728}
729
730static int solo_reqbufs(struct file *file, void *priv,
731 struct v4l2_requestbuffers *req)
732{
733 struct solo_filehandle *fh = priv;
734
735 return videobuf_reqbufs(&fh->vidq, req);
736}
737
738static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
739{
740 struct solo_filehandle *fh = priv;
741
742 return videobuf_querybuf(&fh->vidq, buf);
743}
744
745static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
746{
747 struct solo_filehandle *fh = priv;
748
749 return videobuf_qbuf(&fh->vidq, buf);
750}
751
752static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
753{
754 struct solo_filehandle *fh = priv;
755
756 return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
757}
758
759static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
760{
761 struct solo_filehandle *fh = priv;
762
763 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
764 return -EINVAL;
765
766 return videobuf_streamon(&fh->vidq);
767}
768
769static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
770{
771 struct solo_filehandle *fh = priv;
772
773 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
774 return -EINVAL;
775
776 return videobuf_streamoff(&fh->vidq);
777}
778
779static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
780{
781 return 0;
782}
783
784static const u32 solo_motion_ctrls[] = {
785 V4L2_CID_MOTION_TRACE,
786 0
787};
788
789static const u32 *solo_ctrl_classes[] = {
790 solo_motion_ctrls,
791 NULL
792};
793
794static int solo_disp_queryctrl(struct file *file, void *priv,
795 struct v4l2_queryctrl *qc)
796{
797 qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
798 if (!qc->id)
799 return -EINVAL;
800
801 switch (qc->id) {
802#ifdef PRIVATE_CIDS
803 case V4L2_CID_MOTION_TRACE:
804 qc->type = V4L2_CTRL_TYPE_BOOLEAN;
805 qc->minimum = 0;
806 qc->maximum = qc->step = 1;
807 qc->default_value = 0;
808 strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
809 return 0;
810#else
811 case V4L2_CID_MOTION_TRACE:
812 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
813#endif
814 }
815 return -EINVAL;
816}
817
818static int solo_disp_g_ctrl(struct file *file, void *priv,
819 struct v4l2_control *ctrl)
820{
821 struct solo_filehandle *fh = priv;
822 struct solo_dev *solo_dev = fh->solo_dev;
823
824 switch (ctrl->id) {
825 case V4L2_CID_MOTION_TRACE:
826 ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
827 ? 1 : 0;
828 return 0;
829 }
830 return -EINVAL;
831}
832
833static int solo_disp_s_ctrl(struct file *file, void *priv,
834 struct v4l2_control *ctrl)
835{
836 struct solo_filehandle *fh = priv;
837 struct solo_dev *solo_dev = fh->solo_dev;
838
839 switch (ctrl->id) {
840 case V4L2_CID_MOTION_TRACE:
841 if (ctrl->value) {
842 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
843 SOLO_VI_MOTION_Y_ADD |
844 SOLO_VI_MOTION_Y_VALUE(0x20) |
845 SOLO_VI_MOTION_CB_VALUE(0x10) |
846 SOLO_VI_MOTION_CR_VALUE(0x10));
847 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
848 SOLO_VI_MOTION_CR_ADD |
849 SOLO_VI_MOTION_Y_VALUE(0x10) |
850 SOLO_VI_MOTION_CB_VALUE(0x80) |
851 SOLO_VI_MOTION_CR_VALUE(0x10));
852 } else {
853 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
854 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
855 }
856 return 0;
857 }
858 return -EINVAL;
859}
860
861static const struct v4l2_file_operations solo_v4l2_fops = {
862 .owner = THIS_MODULE,
863 .open = solo_v4l2_open,
864 .release = solo_v4l2_release,
865 .read = solo_v4l2_read,
866 .poll = solo_v4l2_poll,
867 .mmap = solo_v4l2_mmap,
868 .ioctl = video_ioctl2,
869};
870
871static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
872 .vidioc_querycap = solo_querycap,
873 .vidioc_s_std = solo_s_std,
874 /* Input callbacks */
875 .vidioc_enum_input = solo_enum_input,
876 .vidioc_s_input = solo_set_input,
877 .vidioc_g_input = solo_get_input,
878 /* Video capture format callbacks */
879 .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap,
880 .vidioc_try_fmt_vid_cap = solo_try_fmt_cap,
881 .vidioc_s_fmt_vid_cap = solo_set_fmt_cap,
882 .vidioc_g_fmt_vid_cap = solo_get_fmt_cap,
883 /* Streaming I/O */
884 .vidioc_reqbufs = solo_reqbufs,
885 .vidioc_querybuf = solo_querybuf,
886 .vidioc_qbuf = solo_qbuf,
887 .vidioc_dqbuf = solo_dqbuf,
888 .vidioc_streamon = solo_streamon,
889 .vidioc_streamoff = solo_streamoff,
890 /* Controls */
891 .vidioc_queryctrl = solo_disp_queryctrl,
892 .vidioc_g_ctrl = solo_disp_g_ctrl,
893 .vidioc_s_ctrl = solo_disp_s_ctrl,
894};
895
896static struct video_device solo_v4l2_template = {
897 .name = SOLO6X10_NAME,
898 .fops = &solo_v4l2_fops,
899 .ioctl_ops = &solo_v4l2_ioctl_ops,
900 .minor = -1,
901 .release = video_device_release,
902
903 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
904 .current_norm = V4L2_STD_NTSC_M,
905};
906
907int solo_v4l2_init(struct solo_dev *solo_dev)
908{
909 int ret;
910 int i;
911
912 init_waitqueue_head(&solo_dev->disp_thread_wait);
913
914 solo_dev->vfd = video_device_alloc();
915 if (!solo_dev->vfd)
916 return -ENOMEM;
917
918 *solo_dev->vfd = solo_v4l2_template;
919 solo_dev->vfd->parent = &solo_dev->pdev->dev;
920
921 ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
922 if (ret < 0) {
923 video_device_release(solo_dev->vfd);
924 solo_dev->vfd = NULL;
925 return ret;
926 }
927
928 video_set_drvdata(solo_dev->vfd, solo_dev);
929
930 snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
931 SOLO6X10_NAME, solo_dev->vfd->num);
932
933 if (video_nr != -1)
934 video_nr++;
935
936 dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
937 "%d inputs (%d extended)\n", solo_dev->vfd->num,
938 solo_dev->nr_chans, solo_dev->nr_ext);
939
940 /* Cycle all the channels and clear */
941 for (i = 0; i < solo_dev->nr_chans; i++) {
942 solo_v4l2_set_ch(solo_dev, i);
943 while (erase_off(solo_dev))
944 ;/* Do nothing */
945 }
946
947 /* Set the default display channel */
948 solo_v4l2_set_ch(solo_dev, 0);
949 while (erase_off(solo_dev))
950 ;/* Do nothing */
951
952 solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
953
954 return 0;
955}
956
957void solo_v4l2_exit(struct solo_dev *solo_dev)
958{
959 solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
960 if (solo_dev->vfd) {
961 video_unregister_device(solo_dev->vfd);
962 solo_dev->vfd = NULL;
963 }
964}