aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Collins <bcollins@bluecherry.net>2010-06-17 13:27:26 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-22 18:57:44 -0400
commitfaa4fd2a09517b39cc1f5d622453f97a59acfdac (patch)
tree019ae8a1b66a91cb80fb4e69a000fdf2bc141343 /drivers
parent412b2d08b93165303d698267d1eeac19e14e67a4 (diff)
Staging: solo6x10: New driver (staging) for Softlogic 6x10
This driver supports Softlogic 6x10 based codec cards Signed-off-by: Ben Collins <bcollins@bluecherry.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/solo6x10/Kconfig7
-rw-r--r--drivers/staging/solo6x10/Makefile6
-rw-r--r--drivers/staging/solo6x10/solo6010-core.c282
-rw-r--r--drivers/staging/solo6x10/solo6010-disp.c271
-rw-r--r--drivers/staging/solo6x10/solo6010-enc.c229
-rw-r--r--drivers/staging/solo6x10/solo6010-g723.c398
-rw-r--r--drivers/staging/solo6x10/solo6010-gpio.c103
-rw-r--r--drivers/staging/solo6x10/solo6010-i2c.c331
-rw-r--r--drivers/staging/solo6x10/solo6010-jpeg.h105
-rw-r--r--drivers/staging/solo6x10/solo6010-offsets.h78
-rw-r--r--drivers/staging/solo6x10/solo6010-osd-font.h154
-rw-r--r--drivers/staging/solo6x10/solo6010-p2m.c208
-rw-r--r--drivers/staging/solo6x10/solo6010-registers.h657
-rw-r--r--drivers/staging/solo6x10/solo6010-tw28.c678
-rw-r--r--drivers/staging/solo6x10/solo6010-tw28.h65
-rw-r--r--drivers/staging/solo6x10/solo6010-v4l2-enc.c1564
-rw-r--r--drivers/staging/solo6x10/solo6010-v4l2.c859
-rw-r--r--drivers/staging/solo6x10/solo6010.h316
18 files changed, 6311 insertions, 0 deletions
diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig
new file mode 100644
index 00000000000..8aaa3637b60
--- /dev/null
+++ b/drivers/staging/solo6x10/Kconfig
@@ -0,0 +1,7 @@
1config SOLO6X10
2 tristate "Softlogic 6x10 MPEG codec cards"
3 depends on PCI && VIDEO_DEV
4 select VIDEOBUF_DMA_CONTIG
5 ---help---
6 This driver supports the Softlogic based MPEG-4 and h.264 codec
7 codec cards.
diff --git a/drivers/staging/solo6x10/Makefile b/drivers/staging/solo6x10/Makefile
new file mode 100644
index 00000000000..7e70044d8da
--- /dev/null
+++ b/drivers/staging/solo6x10/Makefile
@@ -0,0 +1,6 @@
1solo6x10-objs := solo6010-core.o solo6010-i2c.o solo6010-p2m.o \
2 solo6010-v4l2.o solo6010-tw28.o solo6010-gpio.o \
3 solo6010-disp.o solo6010-enc.o solo6010-v4l2-enc.o \
4 solo6010-g723.o
5
6obj-$(CONFIG_SOLO6X10) := solo6x10.o
diff --git a/drivers/staging/solo6x10/solo6010-core.c b/drivers/staging/solo6x10/solo6010-core.c
new file mode 100644
index 00000000000..98c6739fc19
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-core.c
@@ -0,0 +1,282 @@
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/videodev2.h>
25
26#include "solo6010.h"
27#include "solo6010-tw28.h"
28
29MODULE_DESCRIPTION("Softlogic 6010 MP4 Encoder/Decoder V4L2/ALSA Driver");
30MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
31MODULE_VERSION(SOLO6010_VERSION);
32MODULE_LICENSE("GPL");
33
34void solo6010_irq_on(struct solo6010_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 solo6010_irq_off(struct solo6010_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 solo6010_isr(int irq, void *data)
48{
49 struct solo6010_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 solo6010_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 solo6010_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 solo6010_pci_probe(struct pci_dev *pdev,
133 const struct pci_device_id *id)
134{
135 struct solo6010_dev *solo_dev;
136 int ret;
137 int sdram;
138 u8 chip_id;
139
140 if ((solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL)) == NULL)
141 return -ENOMEM;
142
143 solo_dev->pdev = pdev;
144 spin_lock_init(&solo_dev->reg_io_lock);
145 pci_set_drvdata(pdev, solo_dev);
146
147 if ((ret = pci_enable_device(pdev)))
148 goto fail_probe;
149
150 pci_set_master(pdev);
151
152 if ((ret = pci_request_regions(pdev, SOLO6010_NAME)))
153 goto fail_probe;
154
155 if ((solo_dev->reg_base = pci_ioremap_bar(pdev, 0)) == NULL) {
156 ret = -ENOMEM;
157 goto fail_probe;
158 }
159
160 chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
161 SOLO_CHIP_ID_MASK;
162 switch (chip_id) {
163 case 7:
164 solo_dev->nr_chans = 16;
165 solo_dev->nr_ext = 5;
166 break;
167 case 6:
168 solo_dev->nr_chans = 8;
169 solo_dev->nr_ext = 2;
170 break;
171 default:
172 dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
173 "defaulting to 4 channels\n",
174 chip_id);
175 case 5:
176 solo_dev->nr_chans = 4;
177 solo_dev->nr_ext = 1;
178 }
179
180 /* Disable all interrupts to start */
181 solo6010_irq_off(solo_dev, ~0);
182
183 /* Initial global settings */
184 solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT |
185 SOLO_SYS_CFG_INPUTDIV(25) |
186 SOLO_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
187 SOLO_SYS_CFG_OUTDIV(3));
188 solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
189
190 /* PLL locking time of 1ms */
191 mdelay(1);
192
193 ret = request_irq(pdev->irq, solo6010_isr, IRQF_SHARED, SOLO6010_NAME,
194 solo_dev);
195 if (ret)
196 goto fail_probe;
197
198 /* Handle this from the start */
199 solo6010_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
200
201 if ((ret = solo_i2c_init(solo_dev)))
202 goto fail_probe;
203
204 /* Setup the DMA engine */
205 sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
206 solo_reg_write(solo_dev, SOLO_DMA_CTRL,
207 SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
208 SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
209 SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
210 SOLO_DMA_CTRL_READ_CLK_SELECT |
211 SOLO_DMA_CTRL_LATENCY(1));
212
213 if ((ret = solo_p2m_init(solo_dev)))
214 goto fail_probe;
215
216 if ((ret = solo_disp_init(solo_dev)))
217 goto fail_probe;
218
219 if ((ret = solo_gpio_init(solo_dev)))
220 goto fail_probe;
221
222 if ((ret = solo_tw28_init(solo_dev)))
223 goto fail_probe;
224
225 if ((ret = solo_v4l2_init(solo_dev)))
226 goto fail_probe;
227
228 if ((ret = solo_enc_init(solo_dev)))
229 goto fail_probe;
230
231 if ((ret = solo_enc_v4l2_init(solo_dev)))
232 goto fail_probe;
233
234 if ((ret = solo_g723_init(solo_dev)))
235 goto fail_probe;
236
237 return 0;
238
239fail_probe:
240 free_solo_dev(solo_dev);
241 return ret;
242}
243
244static void __devexit solo6010_pci_remove(struct pci_dev *pdev)
245{
246 struct solo6010_dev *solo_dev = pci_get_drvdata(pdev);
247
248 free_solo_dev(solo_dev);
249}
250
251static struct pci_device_id solo6010_id_table[] = {
252 {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
253 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
254 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
255 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
256 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_4)},
257 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_9)},
258 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_16)},
259 {0,}
260};
261
262MODULE_DEVICE_TABLE(pci, solo6010_id_table);
263
264static struct pci_driver solo6010_pci_driver = {
265 .name = SOLO6010_NAME,
266 .id_table = solo6010_id_table,
267 .probe = solo6010_pci_probe,
268 .remove = solo6010_pci_remove,
269};
270
271static int __init solo6010_module_init(void)
272{
273 return pci_register_driver(&solo6010_pci_driver);
274}
275
276static void __exit solo6010_module_exit(void)
277{
278 pci_unregister_driver(&solo6010_pci_driver);
279}
280
281module_init(solo6010_module_init);
282module_exit(solo6010_module_exit);
diff --git a/drivers/staging/solo6x10/solo6010-disp.c b/drivers/staging/solo6x10/solo6010-disp.c
new file mode 100644
index 00000000000..555f024f72e
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-disp.c
@@ -0,0 +1,271 @@
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
25#include "solo6010.h"
26
27#define SOLO_VCLK_DELAY 3
28#define SOLO_PROGRESSIVE_VSIZE 1024
29
30#define SOLO_MOT_THRESH_W 64
31#define SOLO_MOT_THRESH_H 64
32#define SOLO_MOT_THRESH_SIZE 8192
33#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
34#define SOLO_MOT_FLAG_SIZE 512
35#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32)
36
37static unsigned video_type;
38module_param(video_type, uint, 0644);
39MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
40
41static void solo_vin_config(struct solo6010_dev *solo_dev)
42{
43 solo_dev->vin_hstart = 8;
44 solo_dev->vin_vstart = 2;
45
46 solo_reg_write(solo_dev, SOLO_SYS_VCLK,
47 SOLO_VCLK_SELECT(2) |
48 SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
49 SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
50 SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
51 SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
52 SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
53 SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
54 SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
55 SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
56
57 solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
58 SOLO_VI_H_START(solo_dev->vin_hstart) |
59 SOLO_VI_V_START(solo_dev->vin_vstart) |
60 SOLO_VI_V_STOP(solo_dev->vin_vstart +
61 solo_dev->video_vsize));
62
63 solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
64 SOLO_VI_H_START(solo_dev->vout_hstart) |
65 SOLO_VI_V_START(solo_dev->vout_vstart) |
66 SOLO_VI_V_STOP(solo_dev->vout_vstart +
67 solo_dev->video_vsize));
68
69 solo_reg_write(solo_dev, SOLO_VI_ACT_P,
70 SOLO_VI_H_START(0) |
71 SOLO_VI_V_START(1) |
72 SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
73
74 solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
75 SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
76
77 solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
78 solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
79
80 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
81 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
82 SOLO_VI_PB_USER_MODE);
83 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
84 SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
85 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
86 SOLO_VI_PB_VSTART(4) |
87 SOLO_VI_PB_VSTOP(4 + 240));
88 } else {
89 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
90 SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
91 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
92 SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
93 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
94 SOLO_VI_PB_VSTART(4) |
95 SOLO_VI_PB_VSTOP(4 + 288));
96 }
97 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
98 SOLO_VI_PB_HSTOP(16 + 720));
99}
100
101static void solo_disp_config(struct solo6010_dev *solo_dev)
102{
103 solo_dev->vout_hstart = 6;
104 solo_dev->vout_vstart = 8;
105
106 solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
107 (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
108 solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
109 (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
110 solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
111 (16 << 24) | (128 << 16) | (16 << 8) | 128);
112
113 solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
114 solo_dev->video_type |
115 SOLO_VO_USER_COLOR_SET_NAV |
116 SOLO_VO_NA_COLOR_Y(0) |
117 SOLO_VO_NA_COLOR_CB(0) |
118 SOLO_VO_NA_COLOR_CR(0));
119
120 solo_reg_write(solo_dev, SOLO_VO_ACT_H,
121 SOLO_VO_H_START(solo_dev->vout_hstart) |
122 SOLO_VO_H_STOP(solo_dev->vout_hstart +
123 solo_dev->video_hsize));
124
125 solo_reg_write(solo_dev, SOLO_VO_ACT_V,
126 SOLO_VO_V_START(solo_dev->vout_vstart) |
127 SOLO_VO_V_STOP(solo_dev->vout_vstart +
128 solo_dev->video_vsize));
129
130 solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
131 SOLO_VO_H_LEN(solo_dev->video_hsize) |
132 SOLO_VO_V_LEN(solo_dev->video_vsize));
133
134 solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
135
136 solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
137 SOLO_VO_DISP_ERASE_COUNT(8) |
138 SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR(solo_dev)));
139
140 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
141
142 /* Enable channels we support */
143 solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
144
145 /* Disable the watchdog */
146 solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
147}
148
149static int solo_dma_vin_region(struct solo6010_dev *solo_dev, u32 off,
150 u16 val, int reg_size)
151{
152 u16 buf[64];
153 int i;
154 int ret = 0;
155
156 for (i = 0; i < sizeof(buf) >> 1; i++)
157 buf[i] = val;
158
159 for (i = 0; i < reg_size; i += sizeof(buf))
160 ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
161 SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
162 sizeof(buf));
163
164 return ret;
165}
166
167void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val)
168{
169 if (ch > solo_dev->nr_chans)
170 return;
171
172 solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
173 (ch * SOLO_MOT_THRESH_SIZE * 2),
174 val, SOLO_MOT_THRESH_REAL);
175}
176
177/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
178 * threshold and working table for each channel. Atleast that's what the
179 * spec says. However, this code (take from rdk) has some mystery 8k
180 * block right after the flag area, before the first thresh table. */
181static void solo_motion_config(struct solo6010_dev *solo_dev)
182{
183 int i;
184
185 for (i = 0; i < solo_dev->nr_chans; i++) {
186 /* Clear motion flag area */
187 solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
188 SOLO_MOT_FLAG_SIZE);
189
190 /* Clear working cache table */
191 solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
192 SOLO_MOT_THRESH_SIZE +
193 (i * SOLO_MOT_THRESH_SIZE * 2),
194 0x0000, SOLO_MOT_THRESH_REAL);
195
196 /* Set default threshold table */
197 solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
198 }
199
200 /* Default motion settings */
201 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
202 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
203 solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
204 SOLO_VI_MOTION_FRAME_COUNT(3) |
205 SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
206 | //SOLO_VI_MOTION_INTR_START_STOP |
207 SOLO_VI_MOTION_SAMPLE_COUNT(10));
208
209 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
210 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
211}
212
213int solo_disp_init(struct solo6010_dev *solo_dev)
214{
215 int i;
216
217 solo_dev->video_hsize = 704;
218 if (video_type == 0) {
219 solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
220 solo_dev->video_vsize = 240;
221 solo_dev->fps = 30;
222 } else {
223 solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
224 solo_dev->video_vsize = 288;
225 solo_dev->fps = 25;
226 }
227
228 solo_vin_config(solo_dev);
229 solo_motion_config(solo_dev);
230 solo_disp_config(solo_dev);
231
232 for (i = 0; i < solo_dev->nr_chans; i++)
233 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
234
235 return 0;
236}
237
238void solo_disp_exit(struct solo6010_dev *solo_dev)
239{
240 int i;
241
242 solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
243
244 solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
245 solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
246 solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
247
248 for (i = 0; i < solo_dev->nr_chans; i++) {
249 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
250 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
251 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
252 }
253
254 /* Set default border */
255 for (i = 0; i < 5; i++)
256 solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
257
258 for (i = 0; i < 5; i++)
259 solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
260
261 solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
262 solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
263
264 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
265 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
266 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
267
268 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
269 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
270 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
271}
diff --git a/drivers/staging/solo6x10/solo6010-enc.c b/drivers/staging/solo6x10/solo6010-enc.c
new file mode 100644
index 00000000000..a6cf0a8a3f2
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-enc.c
@@ -0,0 +1,229 @@
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
22#include "solo6010.h"
23#include "solo6010-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 solo6010_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,
97 SOLO_EOSD_EXT_ADDR(solo_dev) >> 16);
98 solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
99 0xF0 << 16 | 0x80 << 8 | 0x80);
100 solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
101
102 /* Clear OSG buffer */
103 buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
104 if (!buf)
105 return;
106
107 for (i = 0; i < solo_dev->nr_chans; i++) {
108 for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
109 solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
110 SOLO_EOSD_EXT_ADDR(solo_dev) +
111 (i * SOLO_EOSD_EXT_SIZE) + j,
112 OSG_BUFFER_SIZE);
113 }
114 }
115 kfree(buf);
116}
117
118int solo_osd_print(struct solo_enc_dev *solo_enc)
119{
120 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
121 char *str = solo_enc->osd_text;
122 u8 *buf;
123 u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
124 int len = strlen(str);
125 int i, j;
126 int x = 1, y = 1;
127
128 if (len == 0) {
129 reg &= ~(1 << solo_enc->ch);
130 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
131 return 0;
132 }
133
134 buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
135 if (!buf)
136 return -ENOMEM;
137
138 for (i = 0; i < len; i++) {
139 for (j = 0; j < 16; j++) {
140 buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
141 (solo_osd_font[(str[i] * 4) + (j / 4)]
142 >> ((3 - (j % 4)) * 8)) & 0xff;
143 }
144 }
145
146 solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR(solo_dev) +
147 (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
148 reg |= (1 << solo_enc->ch);
149 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
150
151 kfree(buf);
152
153 return 0;
154}
155
156static void solo_jpeg_config(struct solo6010_dev *solo_dev)
157{
158 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
159 (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0));
160 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
161 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
162 solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
163 (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
164 ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
165 solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
166}
167
168static void solo_mp4e_config(struct solo6010_dev *solo_dev)
169{
170 int i;
171
172 /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
173 solo_reg_write(solo_dev, SOLO_VE_CFG0,
174 SOLO_VE_INTR_CTRL(0) |
175 SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
176 SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
177
178 solo_reg_write(solo_dev, SOLO_VE_CFG1,
179 SOLO_VE_BYTE_ALIGN(2) |
180 SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
181
182 solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
183 solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
184 solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
185 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
186 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
187
188 solo_reg_write(solo_dev, SOLO_VE_ATTR,
189 SOLO_VE_LITTLE_ENDIAN |
190 SOLO_COMP_ATTR_FCODE(1) |
191 SOLO_COMP_TIME_INC(0) |
192 SOLO_COMP_TIME_WIDTH(15) |
193 SOLO_DCT_INTERVAL(36 / 4));
194
195 for (i = 0; i < solo_dev->nr_chans; i++)
196 solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
197 (SOLO_EREF_EXT_ADDR(solo_dev) +
198 (i * SOLO_EREF_EXT_SIZE)) >> 16);
199}
200
201int solo_enc_init(struct solo6010_dev *solo_dev)
202{
203 int i;
204
205 solo_capture_config(solo_dev);
206 solo_mp4e_config(solo_dev);
207 solo_jpeg_config(solo_dev);
208
209 for (i = 0; i < solo_dev->nr_chans; i++) {
210 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
211 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
212 }
213
214 solo6010_irq_on(solo_dev, SOLO_IRQ_ENCODER);
215
216 return 0;
217}
218
219void solo_enc_exit(struct solo6010_dev *solo_dev)
220{
221 int i;
222
223 solo6010_irq_off(solo_dev, SOLO_IRQ_ENCODER);
224
225 for (i = 0; i < solo_dev->nr_chans; i++) {
226 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
227 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
228 }
229}
diff --git a/drivers/staging/solo6x10/solo6010-g723.c b/drivers/staging/solo6x10/solo6010-g723.c
new file mode 100644
index 00000000000..e82846c1d6c
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-g723.c
@@ -0,0 +1,398 @@
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/freezer.h>
25
26#include <sound/core.h>
27#include <sound/initval.h>
28#include <sound/pcm.h>
29#include <sound/control.h>
30
31#include "solo6010.h"
32#include "solo6010-tw28.h"
33
34#define G723_INTR_ORDER 0
35#define G723_FDMA_PAGES 32
36#define G723_PERIOD_BYTES 48
37#define G723_PERIOD_BLOCK 1024
38#define G723_FRAMES_PER_PAGE 48
39
40/* Sets up channels 16-19 for decoding and 0-15 for encoding */
41#define OUTMODE_MASK 0x300
42
43#define SAMPLERATE 8000
44#define BITRATE 25
45
46/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
47 * is broken down to 20 * 48 byte regions (one for each channel possible)
48 * with the rest of the page being dummy data. */
49#define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX)
50#define IRQ_PAGES 4 // 0 - 4
51#define PERIODS_MIN (1 << IRQ_PAGES)
52#define PERIODS_MAX G723_FDMA_PAGES
53
54struct solo_snd_pcm {
55 int on;
56 spinlock_t lock;
57 struct solo6010_dev *solo_dev;
58 unsigned char g723_buf[G723_PERIOD_BYTES];
59};
60
61static void solo_g723_config(struct solo6010_dev *solo_dev)
62{
63 int clk_div;
64
65 clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2);
66
67 solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
68 SOLO_AUDIO_BITRATE(BITRATE) |
69 SOLO_AUDIO_CLK_DIV(clk_div));
70
71 solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
72 SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) |
73 SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
74 SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
75
76 solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
77 SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE |
78 SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK));
79}
80
81void solo_g723_isr(struct solo6010_dev *solo_dev)
82{
83 struct snd_pcm_str *pstr =
84 &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
85 struct snd_pcm_substream *ss;
86 struct solo_snd_pcm *solo_pcm;
87
88 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723);
89
90 for (ss = pstr->substream; ss != NULL; ss = ss->next) {
91 if (snd_pcm_substream_chip(ss) == NULL)
92 continue;
93
94 /* This means open() hasn't been called on this one */
95 if (snd_pcm_substream_chip(ss) == solo_dev)
96 continue;
97
98 /* Haven't triggered a start yet */
99 solo_pcm = snd_pcm_substream_chip(ss);
100 if (!solo_pcm->on)
101 continue;
102
103 snd_pcm_period_elapsed(ss);
104 }
105}
106
107static int snd_solo_hw_params(struct snd_pcm_substream *ss,
108 struct snd_pcm_hw_params *hw_params)
109{
110 return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
111}
112
113static int snd_solo_hw_free(struct snd_pcm_substream *ss)
114{
115 return snd_pcm_lib_free_pages(ss);
116}
117
118static struct snd_pcm_hardware snd_solo_pcm_hw = {
119 .info = (SNDRV_PCM_INFO_MMAP |
120 SNDRV_PCM_INFO_INTERLEAVED |
121 SNDRV_PCM_INFO_BLOCK_TRANSFER |
122 SNDRV_PCM_INFO_MMAP_VALID),
123 .formats = SNDRV_PCM_FMTBIT_U8,
124 .rates = SNDRV_PCM_RATE_8000,
125 .rate_min = 8000,
126 .rate_max = 8000,
127 .channels_min = 1,
128 .channels_max = 1,
129 .buffer_bytes_max = MAX_BUFFER,
130 .period_bytes_min = G723_PERIOD_BYTES,
131 .period_bytes_max = G723_PERIOD_BYTES,
132 .periods_min = PERIODS_MIN,
133 .periods_max = PERIODS_MAX,
134};
135
136static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
137{
138 struct solo6010_dev *solo_dev = snd_pcm_substream_chip(ss);
139 struct solo_snd_pcm *solo_pcm;
140
141 solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
142 if (solo_pcm == NULL)
143 return -ENOMEM;
144
145 spin_lock_init(&solo_pcm->lock);
146 solo_pcm->solo_dev = solo_dev;
147 ss->runtime->hw = snd_solo_pcm_hw;
148
149 snd_pcm_substream_chip(ss) = solo_pcm;
150
151 return 0;
152}
153
154static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
155{
156 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
157
158 snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
159 kfree(solo_pcm);
160
161 return 0;
162}
163
164static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
165{
166 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
167 struct solo6010_dev *solo_dev = solo_pcm->solo_dev;
168 int ret = 0;
169
170 spin_lock(&solo_pcm->lock);
171
172 switch (cmd) {
173 case SNDRV_PCM_TRIGGER_START:
174 if (solo_pcm->on == 0) {
175 /* If this is the first user, switch on interrupts */
176 if (atomic_inc_return(&solo_dev->snd_users) == 1)
177 solo6010_irq_on(solo_dev, SOLO_IRQ_G723);
178 solo_pcm->on = 1;
179 }
180 break;
181 case SNDRV_PCM_TRIGGER_STOP:
182 if (solo_pcm->on) {
183 /* If this was our last user, switch them off */
184 if (atomic_dec_return(&solo_dev->snd_users) == 0)
185 solo6010_irq_off(solo_dev, SOLO_IRQ_G723);
186 solo_pcm->on = 0;
187 }
188 break;
189 default:
190 ret = -EINVAL;
191 }
192
193 spin_unlock(&solo_pcm->lock);
194
195 return ret;
196}
197
198static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
199{
200 return 0;
201}
202
203static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
204{
205 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
206 struct solo6010_dev *solo_dev = solo_pcm->solo_dev;
207 snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
208
209 return idx * G723_FRAMES_PER_PAGE;
210}
211
212static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
213 snd_pcm_uframes_t pos, void __user *dst,
214 snd_pcm_uframes_t count)
215{
216 struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
217 struct solo6010_dev *solo_dev = solo_pcm->solo_dev;
218 int err, i;
219
220 for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
221 int page = (pos / G723_FRAMES_PER_PAGE) + i;
222
223 err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0,
224 solo_pcm->g723_buf,
225 SOLO_G723_EXT_ADDR(solo_dev) +
226 (page * G723_PERIOD_BLOCK) +
227 (ss->number * G723_PERIOD_BYTES),
228 G723_PERIOD_BYTES);
229 if (err)
230 return err;
231
232 err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
233 solo_pcm->g723_buf, G723_PERIOD_BYTES);
234
235 if (err)
236 return err;
237 }
238
239 return 0;
240}
241
242static struct snd_pcm_ops snd_solo_pcm_ops = {
243 .open = snd_solo_pcm_open,
244 .close = snd_solo_pcm_close,
245 .ioctl = snd_pcm_lib_ioctl,
246 .hw_params = snd_solo_hw_params,
247 .hw_free = snd_solo_hw_free,
248 .prepare = snd_solo_pcm_prepare,
249 .trigger = snd_solo_pcm_trigger,
250 .pointer = snd_solo_pcm_pointer,
251 .copy = snd_solo_pcm_copy,
252};
253
254static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
255 struct snd_ctl_elem_info *info)
256{
257 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
258 info->count = 1;
259 info->value.integer.min = 0;
260 info->value.integer.max = 15;
261 info->value.integer.step = 1;
262
263 return 0;
264}
265
266static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
267 struct snd_ctl_elem_value *value)
268{
269 struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol);
270 u8 ch = value->id.numid - 1;
271
272 value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
273
274 return 0;
275}
276
277static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
278 struct snd_ctl_elem_value *value)
279{
280 struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol);
281 u8 ch = value->id.numid - 1;
282 u8 old_val;
283
284 old_val = tw28_get_audio_gain(solo_dev, ch);
285 if (old_val == value->value.integer.value[0])
286 return 0;
287
288 tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
289
290 return 1;
291}
292
293static struct snd_kcontrol_new snd_solo_capture_volume = {
294 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
295 .name = "Capture Volume",
296 .info = snd_solo_capture_volume_info,
297 .get = snd_solo_capture_volume_get,
298 .put = snd_solo_capture_volume_put,
299};
300
301static int solo_snd_pcm_init(struct solo6010_dev *solo_dev)
302{
303 struct snd_card *card = solo_dev->snd_card;
304 struct snd_pcm *pcm;
305 struct snd_pcm_substream *ss;
306 int ret;
307 int i;
308
309 ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
310 &pcm);
311 if (ret < 0)
312 return ret;
313
314 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
315 &snd_solo_pcm_ops);
316
317 snd_pcm_chip(pcm) = solo_dev;
318 pcm->info_flags = 0;
319 strcpy(pcm->name, card->shortname);
320
321 for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
322 ss; ss = ss->next, i++)
323 sprintf(ss->name, "Camera #%d Audio", i);
324
325 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
326 SNDRV_DMA_TYPE_CONTINUOUS,
327 snd_dma_continuous_data(GFP_KERNEL),
328 MAX_BUFFER, MAX_BUFFER);
329 if (ret < 0)
330 return ret;
331
332 solo_dev->snd_pcm = pcm;
333
334 return 0;
335}
336
337int solo_g723_init(struct solo6010_dev *solo_dev)
338{
339 static struct snd_device_ops ops = { NULL };
340 struct snd_card *card;
341 struct snd_kcontrol_new kctl;
342 char name[32];
343 int ret;
344
345 atomic_set(&solo_dev->snd_users, 0);
346
347 /* Allows for easier mapping between video and audio */
348 sprintf(name, "Softlogic%d", solo_dev->vfd->num);
349
350 ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
351 &solo_dev->snd_card);
352 if (ret < 0)
353 return ret;
354
355 card = solo_dev->snd_card;
356
357 strcpy(card->driver, SOLO6010_NAME);
358 strcpy(card->shortname, "SOLO-6010 Audio");
359 sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
360 pci_name(solo_dev->pdev), solo_dev->pdev->irq);
361 snd_card_set_dev(card, &solo_dev->pdev->dev);
362
363 ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
364 if (ret < 0)
365 goto snd_error;
366
367 /* Mixer controls */
368 strcpy(card->mixername, "SOLO-6010");
369 kctl = snd_solo_capture_volume;
370 kctl.count = solo_dev->nr_chans;
371 ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
372 if (ret < 0)
373 return ret;
374
375 if ((ret = solo_snd_pcm_init(solo_dev)) < 0)
376 goto snd_error;
377
378 if ((ret = snd_card_register(card)) < 0)
379 goto snd_error;
380
381 solo_g723_config(solo_dev);
382
383 dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
384
385 return 0;
386
387snd_error:
388 snd_card_free(card);
389 return ret;
390}
391
392void solo_g723_exit(struct solo6010_dev *solo_dev)
393{
394 solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
395 solo6010_irq_off(solo_dev, SOLO_IRQ_G723);
396
397 snd_card_free(solo_dev->snd_card);
398}
diff --git a/drivers/staging/solo6x10/solo6010-gpio.c b/drivers/staging/solo6x10/solo6010-gpio.c
new file mode 100644
index 00000000000..46f7a71edab
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-gpio.c
@@ -0,0 +1,103 @@
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
24#include "solo6010.h"
25
26static void solo_gpio_mode(struct solo6010_dev *solo_dev,
27 unsigned int port_mask, unsigned int mode)
28{
29 int port;
30 unsigned int ret;
31
32 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
33
34 /* To set gpio */
35 for (port = 0; port < 16; port++) {
36 if (!((1 << port) & port_mask))
37 continue;
38
39 ret &= (~(3 << (port << 1)));
40 ret |= ((mode & 3) << (port << 1));
41 }
42
43 solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
44
45 /* To set extended gpio - sensor */
46 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
47
48 for (port = 0; port < 16; port++) {
49 if (!((1 << (port + 16)) & port_mask))
50 continue;
51
52 if (!mode)
53 ret &= ~(1 << port);
54 else
55 ret |= 1 << port;
56 }
57
58 solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
59}
60
61static void solo_gpio_set(struct solo6010_dev *solo_dev, unsigned int value)
62{
63 solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
64 solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
65}
66
67static void solo_gpio_clear(struct solo6010_dev *solo_dev, unsigned int value)
68{
69 solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
70 solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
71}
72
73static void solo_gpio_config(struct solo6010_dev *solo_dev)
74{
75 /* Video reset */
76 solo_gpio_mode(solo_dev, 0x30, 1);
77 solo_gpio_clear(solo_dev, 0x30);
78 udelay(100);
79 solo_gpio_set(solo_dev, 0x30);
80 udelay(100);
81
82 /* Warning: Don't touch the next line unless you're sure of what
83 * you're doing: first four gpio [0-3] are used for video. */
84 solo_gpio_mode(solo_dev, 0x0f, 2);
85
86 /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
87 solo_gpio_mode(solo_dev, 0xff00, 1);
88
89 /* Initially set relay status to 0 */
90 solo_gpio_clear(solo_dev, 0xff00);
91}
92
93int solo_gpio_init(struct solo6010_dev *solo_dev)
94{
95 solo_gpio_config(solo_dev);
96 return 0;
97}
98
99void solo_gpio_exit(struct solo6010_dev *solo_dev)
100{
101 solo_gpio_clear(solo_dev, 0x30);
102 solo_gpio_config(solo_dev);
103}
diff --git a/drivers/staging/solo6x10/solo6010-i2c.c b/drivers/staging/solo6x10/solo6010-i2c.c
new file mode 100644
index 00000000000..2bb86fa9e9e
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-i2c.c
@@ -0,0 +1,331 @@
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 SOLO6010 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
30#include "solo6010.h"
31
32u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off)
33{
34 struct i2c_msg msgs[2];
35 u8 data;
36
37 msgs[0].flags = 0;
38 msgs[0].addr = addr;
39 msgs[0].len = 1;
40 msgs[0].buf = &off;
41
42 msgs[1].flags = I2C_M_RD;
43 msgs[1].addr = addr;
44 msgs[1].len = 1;
45 msgs[1].buf = &data;
46
47 i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
48
49 return data;
50}
51
52void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr,
53 u8 off, u8 data)
54{
55 struct i2c_msg msgs;
56 u8 buf[2];
57
58 buf[0] = off;
59 buf[1] = data;
60 msgs.flags = 0;
61 msgs.addr = addr;
62 msgs.len = 2;
63 msgs.buf = buf;
64
65 i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
66}
67
68static void solo_i2c_flush(struct solo6010_dev *solo_dev, int wr)
69{
70 u32 ctrl;
71
72 ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
73
74 if (solo_dev->i2c_state == IIC_STATE_START)
75 ctrl |= SOLO_IIC_START;
76
77 if (wr) {
78 ctrl |= SOLO_IIC_WRITE;
79 } else {
80 ctrl |= SOLO_IIC_READ;
81 if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
82 ctrl |= SOLO_IIC_ACK_EN;
83 }
84
85 if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
86 ctrl |= SOLO_IIC_STOP;
87
88 solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
89}
90
91static void solo_i2c_start(struct solo6010_dev *solo_dev)
92{
93 u32 addr = solo_dev->i2c_msg->addr << 1;
94
95 if (solo_dev->i2c_msg->flags & I2C_M_RD)
96 addr |= 1;
97
98 solo_dev->i2c_state = IIC_STATE_START;
99 solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
100 solo_i2c_flush(solo_dev, 1);
101}
102
103static void solo_i2c_stop(struct solo6010_dev *solo_dev)
104{
105 solo6010_irq_off(solo_dev, SOLO_IRQ_IIC);
106 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
107 solo_dev->i2c_state = IIC_STATE_STOP;
108 wake_up(&solo_dev->i2c_wait);
109}
110
111static int solo_i2c_handle_read(struct solo6010_dev *solo_dev)
112{
113prepare_read:
114 if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
115 solo_i2c_flush(solo_dev, 0);
116 return 0;
117 }
118
119 solo_dev->i2c_msg_ptr = 0;
120 solo_dev->i2c_msg++;
121 solo_dev->i2c_msg_num--;
122
123 if (solo_dev->i2c_msg_num == 0) {
124 solo_i2c_stop(solo_dev);
125 return 0;
126 }
127
128 if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
129 solo_i2c_start(solo_dev);
130 } else {
131 if (solo_dev->i2c_msg->flags & I2C_M_RD)
132 goto prepare_read;
133 else
134 solo_i2c_stop(solo_dev);
135 }
136
137 return 0;
138}
139
140static int solo_i2c_handle_write(struct solo6010_dev *solo_dev)
141{
142retry_write:
143 if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
144 solo_reg_write(solo_dev, SOLO_IIC_TXD,
145 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
146 solo_dev->i2c_msg_ptr++;
147 solo_i2c_flush(solo_dev, 1);
148 return 0;
149 }
150
151 solo_dev->i2c_msg_ptr = 0;
152 solo_dev->i2c_msg++;
153 solo_dev->i2c_msg_num--;
154
155 if (solo_dev->i2c_msg_num == 0) {
156 solo_i2c_stop(solo_dev);
157 return 0;
158 }
159
160 if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
161 solo_i2c_start(solo_dev);
162 } else {
163 if (solo_dev->i2c_msg->flags & I2C_M_RD)
164 solo_i2c_stop(solo_dev);
165 else
166 goto retry_write;
167 }
168
169 return 0;
170}
171
172int solo_i2c_isr(struct solo6010_dev *solo_dev)
173{
174 u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
175 int ret = -EINVAL;
176
177 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
178
179 if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
180 solo_dev->i2c_id < 0) {
181 solo_i2c_stop(solo_dev);
182 return -ENXIO;
183 }
184
185 switch (solo_dev->i2c_state) {
186 case IIC_STATE_START:
187 if (solo_dev->i2c_msg->flags & I2C_M_RD) {
188 solo_dev->i2c_state = IIC_STATE_READ;
189 ret = solo_i2c_handle_read(solo_dev);
190 break;
191 }
192
193 solo_dev->i2c_state = IIC_STATE_WRITE;
194 case IIC_STATE_WRITE:
195 ret = solo_i2c_handle_write(solo_dev);
196 break;
197
198 case IIC_STATE_READ:
199 solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
200 solo_reg_read(solo_dev, SOLO_IIC_RXD);
201 solo_dev->i2c_msg_ptr++;
202
203 ret = solo_i2c_handle_read(solo_dev);
204 break;
205
206 default:
207 solo_i2c_stop(solo_dev);
208 }
209
210 return ret;
211}
212
213static int solo_i2c_master_xfer(struct i2c_adapter *adap,
214 struct i2c_msg msgs[], int num)
215{
216 struct solo6010_dev *solo_dev = adap->algo_data;
217 unsigned long timeout;
218 int ret;
219 int i;
220 DEFINE_WAIT(wait);
221
222 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
223 if (&solo_dev->i2c_adap[i] == adap)
224 break;
225 }
226
227 if (i == SOLO_I2C_ADAPTERS)
228 return num; // XXX Right return value for failure?
229
230 down(&solo_dev->i2c_sem);
231 solo_dev->i2c_id = i;
232 solo_dev->i2c_msg = msgs;
233 solo_dev->i2c_msg_num = num;
234 solo_dev->i2c_msg_ptr = 0;
235
236 solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
237 solo6010_irq_on(solo_dev, SOLO_IRQ_IIC);
238 solo_i2c_start(solo_dev);
239
240 timeout = HZ / 2;
241
242 for (;;) {
243 prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
244
245 if (solo_dev->i2c_state == IIC_STATE_STOP)
246 break;
247
248 timeout = schedule_timeout(timeout);
249 if (!timeout)
250 break;
251
252 if (signal_pending(current))
253 break;
254 }
255
256 finish_wait(&solo_dev->i2c_wait, &wait);
257 ret = num - solo_dev->i2c_msg_num;
258 solo_dev->i2c_state = IIC_STATE_IDLE;
259 solo_dev->i2c_id = -1;
260
261 up(&solo_dev->i2c_sem);
262
263 return ret;
264}
265
266static u32 solo_i2c_functionality(struct i2c_adapter *adap)
267{
268 return I2C_FUNC_I2C;
269}
270
271static struct i2c_algorithm solo_i2c_algo = {
272 .master_xfer = solo_i2c_master_xfer,
273 .functionality = solo_i2c_functionality,
274};
275
276int solo_i2c_init(struct solo6010_dev *solo_dev)
277{
278 int i;
279 int ret;
280
281 solo_reg_write(solo_dev, SOLO_IIC_CFG,
282 SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
283
284 solo_dev->i2c_id = -1;
285 solo_dev->i2c_state = IIC_STATE_IDLE;
286 init_waitqueue_head(&solo_dev->i2c_wait);
287 init_MUTEX(&solo_dev->i2c_sem);
288
289 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
290 struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
291
292 snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
293 SOLO6010_NAME, i);
294 adap->algo = &solo_i2c_algo;
295 adap->algo_data = solo_dev;
296 adap->retries = 1;
297 adap->dev.parent = &solo_dev->pdev->dev;
298
299 if ((ret = i2c_add_adapter(adap))) {
300 adap->algo_data = NULL;
301 break;
302 }
303 }
304
305 if (ret) {
306 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
307 if (!solo_dev->i2c_adap[i].algo_data)
308 break;
309 i2c_del_adapter(&solo_dev->i2c_adap[i]);
310 solo_dev->i2c_adap[i].algo_data = NULL;
311 }
312 return ret;
313 }
314
315 dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
316 SOLO_I2C_ADAPTERS);
317
318 return 0;
319}
320
321void solo_i2c_exit(struct solo6010_dev *solo_dev)
322{
323 int i;
324
325 for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
326 if (!solo_dev->i2c_adap[i].algo_data)
327 continue;
328 i2c_del_adapter(&solo_dev->i2c_adap[i]);
329 solo_dev->i2c_adap[i].algo_data = NULL;
330 }
331}
diff --git a/drivers/staging/solo6x10/solo6010-jpeg.h b/drivers/staging/solo6x10/solo6010-jpeg.h
new file mode 100644
index 00000000000..fb0507ecb30
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-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 __SOLO6010_JPEG_H
21#define __SOLO6010_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 /* __SOLO6010_JPEG_H */
diff --git a/drivers/staging/solo6x10/solo6010-offsets.h b/drivers/staging/solo6x10/solo6010-offsets.h
new file mode 100644
index 00000000000..2431de989c0
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-offsets.h
@@ -0,0 +1,78 @@
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 __SOLO6010_OFFSETS_H
21#define __SOLO6010_OFFSETS_H
22
23/* Offsets and sizes of the external address */
24#define SOLO_DISP_EXT_ADDR(__solo) 0x00000000
25#define SOLO_DISP_EXT_SIZE 0x00480000
26
27#define SOLO_DEC2LIVE_EXT_ADDR(__solo) \
28 (SOLO_DISP_EXT_ADDR(__solo) + SOLO_DISP_EXT_SIZE)
29#define SOLO_DEC2LIVE_EXT_SIZE 0x00240000
30
31#define SOLO_OSG_EXT_ADDR(__solo) \
32 (SOLO_DEC2LIVE_EXT_ADDR(__solo) + SOLO_DEC2LIVE_EXT_SIZE)
33#define SOLO_OSG_EXT_SIZE 0x00120000
34
35#define SOLO_EOSD_EXT_ADDR(__solo) \
36 (SOLO_OSG_EXT_ADDR(__solo) + SOLO_OSG_EXT_SIZE)
37#define SOLO_EOSD_EXT_SIZE 0x00010000
38
39#define SOLO_MOTION_EXT_ADDR(__solo) \
40 (SOLO_EOSD_EXT_ADDR(__solo) + \
41 (SOLO_EOSD_EXT_SIZE * __solo->nr_chans))
42#define SOLO_MOTION_EXT_SIZE 0x00080000
43
44#define SOLO_G723_EXT_ADDR(__solo) \
45 (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
46#define SOLO_G723_EXT_SIZE 0x00010000
47
48#define SOLO_CAP_EXT_ADDR(__solo) \
49 (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
50#define SOLO_CAP_EXT_MAX_PAGE (18 + 15)
51#define SOLO_CAP_EXT_SIZE (SOLO_CAP_EXT_MAX_PAGE * 65536)
52
53/* This +1 is very important -- Why?! -- BenC */
54#define SOLO_EREF_EXT_ADDR(__solo) \
55 (SOLO_CAP_EXT_ADDR(__solo) + \
56 (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
57#define SOLO_EREF_EXT_SIZE 0x00140000
58
59#define SOLO_MP4E_EXT_ADDR(__solo) \
60 (SOLO_EREF_EXT_ADDR(__solo) + \
61 (SOLO_EREF_EXT_SIZE * __solo->nr_chans))
62#define SOLO_MP4E_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
63
64#define SOLO_DREF_EXT_ADDR(__solo) \
65 (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
66#define SOLO_DREF_EXT_SIZE 0x00140000
67
68#define SOLO_MP4D_EXT_ADDR(__solo) \
69 (SOLO_DREF_EXT_ADDR(__solo) + \
70 (SOLO_DREF_EXT_SIZE * __solo->nr_chans))
71#define SOLO_MP4D_EXT_SIZE 0x00080000
72
73#define SOLO_JPEG_EXT_ADDR(__solo) \
74 (SOLO_MP4D_EXT_ADDR(__solo) + \
75 (SOLO_MP4D_EXT_SIZE * __solo->nr_chans))
76#define SOLO_JPEG_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
77
78#endif /* __SOLO6010_OFFSETS_H */
diff --git a/drivers/staging/solo6x10/solo6010-osd-font.h b/drivers/staging/solo6x10/solo6010-osd-font.h
new file mode 100644
index 00000000000..d6f565bd76c
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-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 __SOLO6010_OSD_FONT_H
21#define __SOLO6010_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 /* __SOLO6010_OSD_FONT_H */
diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c
new file mode 100644
index 00000000000..1b81f069c7f
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-p2m.c
@@ -0,0 +1,208 @@
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
22#include "solo6010.h"
23
24// #define SOLO_TEST_P2M
25
26int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
27 void *sys_addr, u32 ext_addr, u32 size)
28{
29 dma_addr_t dma_addr;
30 int ret;
31
32 WARN_ON(!size);
33 WARN_ON(id >= SOLO_NR_P2M);
34 if (!size || id >= SOLO_NR_P2M)
35 return -EINVAL;
36
37 dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
38 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
39
40 ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
41
42 pci_unmap_single(solo_dev->pdev, dma_addr, size,
43 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
44
45 return ret;
46}
47
48int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
49 dma_addr_t dma_addr, u32 ext_addr, u32 size)
50{
51 struct solo_p2m_dev *p2m_dev;
52 unsigned int timeout = 0;
53
54 WARN_ON(!size);
55 WARN_ON(id >= SOLO_NR_P2M);
56 if (!size || id >= SOLO_NR_P2M)
57 return -EINVAL;
58
59 p2m_dev = &solo_dev->p2m_dev[id];
60
61 down(&p2m_dev->sem);
62
63start_dma:
64 INIT_COMPLETION(p2m_dev->completion);
65 p2m_dev->error = 0;
66 solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr);
67 solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr);
68 solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id),
69 SOLO_P2M_COPY_SIZE(size >> 2));
70 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id),
71 SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
72 (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
73
74 timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
75
76 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
77
78 /* XXX Really looks to me like we will get stuck here if a
79 * real PCI P2M error occurs */
80 if (p2m_dev->error)
81 goto start_dma;
82
83 up(&p2m_dev->sem);
84
85 return (timeout == 0) ? -EAGAIN : 0;
86}
87
88#ifdef SOLO_TEST_P2M
89
90#define P2M_TEST_CHAR 0xbe
91
92static unsigned long long p2m_test(struct solo6010_dev *solo_dev, u8 id,
93 u32 base, int size)
94{
95 u8 *wr_buf;
96 u8 *rd_buf;
97 int i;
98 unsigned long long err_cnt = 0;
99
100 wr_buf = kmalloc(size, GFP_KERNEL);
101 if (!wr_buf) {
102 printk(SOLO6010_NAME ": Failed to malloc for p2m_test\n");
103 return size;
104 }
105
106 rd_buf = kmalloc(size, GFP_KERNEL);
107 if (!rd_buf) {
108 printk(SOLO6010_NAME ": Failed to malloc for p2m_test\n");
109 kfree(wr_buf);
110 return size;
111 }
112
113 memset(wr_buf, P2M_TEST_CHAR, size);
114 memset(rd_buf, P2M_TEST_CHAR + 1, size);
115
116 solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
117 solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
118
119 for (i = 0; i < size; i++)
120 if (wr_buf[i] != rd_buf[i])
121 err_cnt++;
122
123 kfree(wr_buf);
124 kfree(rd_buf);
125
126 return err_cnt;
127}
128
129#define TEST_CHUNK_SIZE (8 * 1024)
130
131static void run_p2m_test(struct solo6010_dev *solo_dev)
132{
133 unsigned long long errs = 0;
134 u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
135 int i, d;
136
137 printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
138 SOLO6010_NAME, size);
139
140 for (i = 0; i < size; i += TEST_CHUNK_SIZE)
141 for (d = 0; d < 4; d++)
142 errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
143
144 printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
145 SOLO6010_NAME, errs);
146
147 return;
148}
149#else
150#define run_p2m_test(__solo) do{}while(0)
151#endif
152
153void solo_p2m_isr(struct solo6010_dev *solo_dev, int id)
154{
155 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
156 complete(&solo_dev->p2m_dev[id].completion);
157}
158
159void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status)
160{
161 struct solo_p2m_dev *p2m_dev;
162 int i;
163
164 if (!(status & SOLO_PCI_ERR_P2M))
165 return;
166
167 for (i = 0; i < SOLO_NR_P2M; i++) {
168 p2m_dev = &solo_dev->p2m_dev[i];
169 p2m_dev->error = 1;
170 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
171 complete(&p2m_dev->completion);
172 }
173}
174
175void solo_p2m_exit(struct solo6010_dev *solo_dev)
176{
177 int i;
178
179 for (i = 0; i < SOLO_NR_P2M; i++)
180 solo6010_irq_off(solo_dev, SOLO_IRQ_P2M(i));
181}
182
183int solo_p2m_init(struct solo6010_dev *solo_dev)
184{
185 struct solo_p2m_dev *p2m_dev;
186 int i;
187
188 for (i = 0; i < SOLO_NR_P2M; i++) {
189 p2m_dev = &solo_dev->p2m_dev[i];
190
191 init_MUTEX(&p2m_dev->sem);
192 init_completion(&p2m_dev->completion);
193
194 solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i),
195 __pa(p2m_dev->desc));
196
197 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
198 solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
199 SOLO_P2M_CSC_16BIT_565 |
200 SOLO_P2M_DMA_INTERVAL(0) |
201 SOLO_P2M_PCI_MASTER_MODE);
202 solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i));
203 }
204
205 run_p2m_test(solo_dev);
206
207 return 0;
208}
diff --git a/drivers/staging/solo6x10/solo6010-registers.h b/drivers/staging/solo6x10/solo6010-registers.h
new file mode 100644
index 00000000000..d39d3c636f5
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-registers.h
@@ -0,0 +1,657 @@
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 __SOLO6010_REGISTERS_H
21#define __SOLO6010_REGISTERS_H
22
23#include "solo6010-offsets.h"
24
25/* Global 6010 system configuration */
26#define SOLO_SYS_CFG 0x0000
27#define SOLO_SYS_CFG_FOUT_EN 0x00000001
28#define SOLO_SYS_CFG_PLL_BYPASS 0x00000002
29#define SOLO_SYS_CFG_PLL_PWDN 0x00000004
30#define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3)
31#define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5)
32#define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14)
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
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
49#define SOLO_SYS_VCLK 0x000C
50#define SOLO_VCLK_INVERT (1<<22)
51/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
52#define SOLO_VCLK_SELECT(n) ((n)<<20)
53#define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14)
54#define SOLO_VCLK_VIN1213_DELAY(n) ((n)<<12)
55#define SOLO_VCLK_VIN1011_DELAY(n) ((n)<<10)
56#define SOLO_VCLK_VIN0809_DELAY(n) ((n)<<8)
57#define SOLO_VCLK_VIN0607_DELAY(n) ((n)<<6)
58#define SOLO_VCLK_VIN0405_DELAY(n) ((n)<<4)
59#define SOLO_VCLK_VIN0203_DELAY(n) ((n)<<2)
60#define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0)
61
62#define SOLO_IRQ_STAT 0x0010
63#define SOLO_IRQ_ENABLE 0x0014
64#define SOLO_IRQ_P2M(n) (1<<((n)+17))
65#define SOLO_IRQ_GPIO (1<<16)
66#define SOLO_IRQ_VIDEO_LOSS (1<<15)
67#define SOLO_IRQ_VIDEO_IN (1<<14)
68#define SOLO_IRQ_MOTION (1<<13)
69#define SOLO_IRQ_ATA_CMD (1<<12)
70#define SOLO_IRQ_ATA_DIR (1<<11)
71#define SOLO_IRQ_PCI_ERR (1<<10)
72#define SOLO_IRQ_PS2_1 (1<<9)
73#define SOLO_IRQ_PS2_0 (1<<8)
74#define SOLO_IRQ_SPI (1<<7)
75#define SOLO_IRQ_IIC (1<<6)
76#define SOLO_IRQ_UART(n) (1<<((n) + 4))
77#define SOLO_IRQ_G723 (1<<3)
78#define SOLO_IRQ_DECODER (1<<1)
79#define SOLO_IRQ_ENCODER (1<<0)
80
81#define SOLO_CHIP_OPTION 0x001C
82#define SOLO_CHIP_ID_MASK 0x00000007
83
84#define SOLO_EEPROM_CTRL 0x0060
85#define SOLO_EEPROM_ACCESS_EN (1<<7)
86#define SOLO_EEPROM_CS (1<<3)
87#define SOLO_EEPROM_CLK (1<<2)
88#define SOLO_EEPROM_DO (1<<1)
89#define SOLO_EEPROM_DI (1<<0)
90#define SOLO_EEPROM_ENABLE (EEPROM_ACCESS_EN | EEPROM_CS)
91
92#define SOLO_PCI_ERR 0x0070
93#define SOLO_PCI_ERR_FATAL 0x00000001
94#define SOLO_PCI_ERR_PARITY 0x00000002
95#define SOLO_PCI_ERR_TARGET 0x00000004
96#define SOLO_PCI_ERR_TIMEOUT 0x00000008
97#define SOLO_PCI_ERR_P2M 0x00000010
98#define SOLO_PCI_ERR_ATA 0x00000020
99#define SOLO_PCI_ERR_P2M_DESC 0x00000040
100#define SOLO_PCI_ERR_FSM0(__s) (((__s) >> 16) & 0x0f)
101#define SOLO_PCI_ERR_FSM1(__s) (((__s) >> 20) & 0x0f)
102#define SOLO_PCI_ERR_FSM2(__s) (((__s) >> 24) & 0x1f)
103
104#define SOLO_P2M_BASE 0x0080
105
106#define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20))
107#define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */
108#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */
109/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
110#define SOLO_P2M_CSC_16BIT_565 (1<<4)
111#define SOLO_P2M_UV_SWAP (1<<3)
112#define SOLO_P2M_PCI_MASTER_MODE (1<<2)
113#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */
114#define SOLO_P2M_DESC_MODE (1<<0)
115
116#define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20))
117
118#define SOLO_P2M_DESC_ID(n) (0x0088 + ((n)*0x20))
119#define SOLO_P2M_UPDATE_ID(n) ((n)<<0)
120
121#define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20))
122#define SOLO_P2M_COMMAND_DONE (1<<8)
123#define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat))
124
125#define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20))
126#define SOLO_P2M_PCI_INC(n) ((n)<<20)
127#define SOLO_P2M_REPEAT(n) ((n)<<10)
128/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
129#define SOLO_P2M_BURST_SIZE(n) ((n)<<7)
130#define SOLO_P2M_BURST_512 0
131#define SOLO_P2M_BURST_256 1
132#define SOLO_P2M_BURST_128 2
133#define SOLO_P2M_BURST_64 3
134#define SOLO_P2M_BURST_32 4
135#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */
136/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
137#define SOLO_P2M_ALPHA_MODE(n) ((n)<<4)
138#define SOLO_P2M_CSC_ON (1<<3)
139#define SOLO_P2M_INTERRUPT_REQ (1<<2)
140#define SOLO_P2M_WRITE (1<<1)
141#define SOLO_P2M_TRANS_ON (1<<0)
142
143#define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20))
144#define SOLO_P2M_EXT_INC(n) ((n)<<20)
145#define SOLO_P2M_COPY_SIZE(n) ((n)<<0)
146
147#define SOLO_P2M_TAR_ADR(n) (0x0098 + ((n)*0x20))
148
149#define SOLO_P2M_EXT_ADR(n) (0x009C + ((n)*0x20))
150
151#define SOLO_P2M_BUFFER(i) (0x2000 + ((i)*4))
152
153#define SOLO_VI_CH_SWITCH_0 0x0100
154#define SOLO_VI_CH_SWITCH_1 0x0104
155#define SOLO_VI_CH_SWITCH_2 0x0108
156
157#define SOLO_VI_CH_ENA 0x010C
158#define SOLO_VI_CH_FORMAT 0x0110
159#define SOLO_VI_FD_SEL_MASK(n) ((n)<<16)
160#define SOLO_VI_PROG_MASK(n) ((n)<<0)
161
162#define SOLO_VI_FMT_CFG 0x0114
163#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31)
164#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30)
165#define SOLO_VI_FMT_TEST_SIGNAL (1<<28)
166
167#define SOLO_VI_PAGE_SW 0x0118
168#define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8)
169#define SOLO_FI_INV_DISP_OUT(n) ((n)<<7)
170#define SOLO_DISP_SYNC_FI(n) ((n)<<6)
171#define SOLO_PIP_PAGE_ADD(n) ((n)<<3)
172#define SOLO_NORMAL_PAGE_ADD(n) ((n)<<0)
173
174#define SOLO_VI_ACT_I_P 0x011C
175#define SOLO_VI_ACT_I_S 0x0120
176#define SOLO_VI_ACT_P 0x0124
177#define SOLO_VI_FI_INVERT (1<<31)
178#define SOLO_VI_H_START(n) ((n)<<21)
179#define SOLO_VI_V_START(n) ((n)<<11)
180#define SOLO_VI_V_STOP(n) ((n)<<0)
181
182#define SOLO_VI_STATUS0 0x0128
183#define SOLO_VI_STATUS0_PAGE(__n) ((__n) & 0x07)
184#define SOLO_VI_STATUS1 0x012C
185
186/* XXX: Might be better off in kernel level disp.h */
187#define DISP_PAGE(stat) ((stat) & 0x07)
188
189#define SOLO_VI_PB_CONFIG 0x0130
190#define SOLO_VI_PB_USER_MODE (1<<1)
191#define SOLO_VI_PB_PAL (1<<0)
192#define SOLO_VI_PB_RANGE_HV 0x0134
193#define SOLO_VI_PB_HSIZE(h) ((h)<<12)
194#define SOLO_VI_PB_VSIZE(v) ((v)<<0)
195#define SOLO_VI_PB_ACT_H 0x0138
196#define SOLO_VI_PB_HSTART(n) ((n)<<12)
197#define SOLO_VI_PB_HSTOP(n) ((n)<<0)
198#define SOLO_VI_PB_ACT_V 0x013C
199#define SOLO_VI_PB_VSTART(n) ((n)<<12)
200#define SOLO_VI_PB_VSTOP(n) ((n)<<0)
201
202#define SOLO_VI_MOSAIC(ch) (0x0140 + ((ch)*4))
203#define SOLO_VI_MOSAIC_SX(x) ((x)<<24)
204#define SOLO_VI_MOSAIC_EX(x) ((x)<<16)
205#define SOLO_VI_MOSAIC_SY(x) ((x)<<8)
206#define SOLO_VI_MOSAIC_EY(x) ((x)<<0)
207
208#define SOLO_VI_WIN_CTRL0(ch) (0x0180 + ((ch)*4))
209#define SOLO_VI_WIN_CTRL1(ch) (0x01C0 + ((ch)*4))
210
211#define SOLO_VI_WIN_CHANNEL(n) ((n)<<28)
212
213#define SOLO_VI_WIN_PIP(n) ((n)<<27)
214#define SOLO_VI_WIN_SCALE(n) ((n)<<24)
215
216#define SOLO_VI_WIN_SX(x) ((x)<<12)
217#define SOLO_VI_WIN_EX(x) ((x)<<0)
218
219#define SOLO_VI_WIN_SY(x) ((x)<<12)
220#define SOLO_VI_WIN_EY(x) ((x)<<0)
221
222#define SOLO_VI_WIN_ON(ch) (0x0200 + ((ch)*4))
223
224#define SOLO_VI_WIN_SW 0x0240
225#define SOLO_VI_WIN_LIVE_AUTO_MUTE 0x0244
226
227#define SOLO_VI_MOT_ADR 0x0260
228#define SOLO_VI_MOTION_EN(mask) ((mask)<<16)
229#define SOLO_VI_MOT_CTRL 0x0264
230#define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24)
231#define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16)
232#define SOLO_VI_MOTION_INTR_START_STOP (1<<15)
233#define SOLO_VI_MOTION_FREEZE_DATA (1<<14)
234#define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0)
235#define SOLO_VI_MOT_CLEAR 0x0268
236#define SOLO_VI_MOT_STATUS 0x026C
237#define SOLO_VI_MOTION_CNT(n) ((n)<<0)
238#define SOLO_VI_MOTION_BORDER 0x0270
239#define SOLO_VI_MOTION_BAR 0x0274
240#define SOLO_VI_MOTION_Y_SET (1<<29)
241#define SOLO_VI_MOTION_Y_ADD (1<<28)
242#define SOLO_VI_MOTION_CB_SET (1<<27)
243#define SOLO_VI_MOTION_CB_ADD (1<<26)
244#define SOLO_VI_MOTION_CR_SET (1<<25)
245#define SOLO_VI_MOTION_CR_ADD (1<<24)
246#define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16)
247#define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8)
248#define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0)
249
250#define SOLO_VO_FMT_ENC 0x0300
251#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31)
252#define SOLO_VO_FMT_TYPE_PAL (1<<30)
253#define SOLO_VO_FMT_TYPE_NTSC 0
254#define SOLO_VO_USER_SET (1<<29)
255
256#define SOLO_VO_FI_CHANGE (1<<20)
257#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19)
258#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18)
259#define SOLO_VO_USER_COLOR_SET_NAV (1<<17)
260#define SOLO_VO_USER_COLOR_SET_NAH (1<<16)
261#define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8)
262#define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4)
263#define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0)
264
265#define SOLO_VO_ACT_H 0x0304
266#define SOLO_VO_H_BLANK(n) ((n)<<22)
267#define SOLO_VO_H_START(n) ((n)<<11)
268#define SOLO_VO_H_STOP(n) ((n)<<0)
269
270#define SOLO_VO_ACT_V 0x0308
271#define SOLO_VO_V_BLANK(n) ((n)<<22)
272#define SOLO_VO_V_START(n) ((n)<<11)
273#define SOLO_VO_V_STOP(n) ((n)<<0)
274
275#define SOLO_VO_RANGE_HV 0x030C
276#define SOLO_VO_SYNC_INVERT (1<<24)
277#define SOLO_VO_HSYNC_INVERT (1<<23)
278#define SOLO_VO_VSYNC_INVERT (1<<22)
279#define SOLO_VO_H_LEN(n) ((n)<<11)
280#define SOLO_VO_V_LEN(n) ((n)<<0)
281
282#define SOLO_VO_DISP_CTRL 0x0310
283#define SOLO_VO_DISP_ON (1<<31)
284#define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24)
285#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22)
286#define SOLO_VO_DISP_SINGLE_PAGE (1<<21)
287#define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff)
288
289#define SOLO_VO_DISP_ERASE 0x0314
290#define SOLO_VO_DISP_ERASE_ON (1<<0)
291
292#define SOLO_VO_ZOOM_CTRL 0x0318
293#define SOLO_VO_ZOOM_VER_ON (1<<24)
294#define SOLO_VO_ZOOM_HOR_ON (1<<23)
295#define SOLO_VO_ZOOM_V_COMP (1<<22)
296#define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11)
297#define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0)
298
299#define SOLO_VO_FREEZE_CTRL 0x031C
300#define SOLO_VO_FREEZE_ON (1<<1)
301#define SOLO_VO_FREEZE_INTERPOLATION (1<<0)
302
303#define SOLO_VO_BKG_COLOR 0x0320
304#define SOLO_BG_Y(y) ((y)<<16)
305#define SOLO_BG_U(u) ((u)<<8)
306#define SOLO_BG_V(v) ((v)<<0)
307
308#define SOLO_VO_DEINTERLACE 0x0324
309#define SOLO_VO_DEINTERLACE_THRESHOLD(n) ((n)<<8)
310#define SOLO_VO_DEINTERLACE_EDGE_VALUE(n) ((n)<<0)
311
312#define SOLO_VO_BORDER_LINE_COLOR 0x0330
313#define SOLO_VO_BORDER_FILL_COLOR 0x0334
314#define SOLO_VO_BORDER_LINE_MASK 0x0338
315#define SOLO_VO_BORDER_FILL_MASK 0x033c
316
317#define SOLO_VO_BORDER_X(n) (0x0340+((n)*4))
318#define SOLO_VO_BORDER_Y(n) (0x0354+((n)*4))
319
320#define SOLO_VO_CELL_EXT_SET 0x0368
321#define SOLO_VO_CELL_EXT_START 0x036c
322#define SOLO_VO_CELL_EXT_STOP 0x0370
323
324#define SOLO_VO_CELL_EXT_SET2 0x0374
325#define SOLO_VO_CELL_EXT_START2 0x0378
326#define SOLO_VO_CELL_EXT_STOP2 0x037c
327
328#define SOLO_VO_RECTANGLE_CTRL(n) (0x0368+((n)*12))
329#define SOLO_VO_RECTANGLE_START(n) (0x036c+((n)*12))
330#define SOLO_VO_RECTANGLE_STOP(n) (0x0370+((n)*12))
331
332#define SOLO_VO_CURSOR_POS (0x0380)
333#define SOLO_VO_CURSOR_CLR (0x0384)
334#define SOLO_VO_CURSOR_CLR2 (0x0388)
335#define SOLO_VO_CURSOR_MASK(id) (0x0390+((id)*4))
336
337#define SOLO_VO_EXPANSION(id) (0x0250+((id)*4))
338
339#define SOLO_OSG_CONFIG 0x03E0
340#define SOLO_VO_OSG_ON (1<<31)
341#define SOLO_VO_OSG_COLOR_MUTE (1<<28)
342#define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22)
343#define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16)
344#define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff)
345
346#define SOLO_OSG_ERASE 0x03E4
347#define SOLO_OSG_ERASE_ON (0x80)
348#define SOLO_OSG_ERASE_OFF (0x00)
349
350#define SOLO_VO_OSG_BLINK 0x03E8
351#define SOLO_VO_OSG_BLINK_ON (1<<1)
352#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0)
353
354#define SOLO_CAP_BASE 0x0400
355#define SOLO_CAP_MAX_PAGE(n) ((n)<<16)
356#define SOLO_CAP_BASE_ADDR(n) ((n)<<0)
357#define SOLO_CAP_BTW 0x0404
358#define SOLO_CAP_PROG_BANDWIDTH(n) ((n)<<8)
359#define SOLO_CAP_MAX_BANDWIDTH(n) ((n)<<0)
360
361#define SOLO_DIM_SCALE1 0x0408
362#define SOLO_DIM_SCALE2 0x040C
363#define SOLO_DIM_SCALE3 0x0410
364#define SOLO_DIM_SCALE4 0x0414
365#define SOLO_DIM_SCALE5 0x0418
366#define SOLO_DIM_V_MB_NUM_FRAME(n) ((n)<<16)
367#define SOLO_DIM_V_MB_NUM_FIELD(n) ((n)<<8)
368#define SOLO_DIM_H_MB_NUM(n) ((n)<<0)
369
370#define SOLO_DIM_PROG 0x041C
371#define SOLO_CAP_STATUS 0x0420
372
373#define SOLO_CAP_CH_SCALE(ch) (0x0440+((ch)*4))
374#define SOLO_CAP_CH_COMP_ENA_E(ch) (0x0480+((ch)*4))
375#define SOLO_CAP_CH_INTV(ch) (0x04C0+((ch)*4))
376#define SOLO_CAP_CH_INTV_E(ch) (0x0500+((ch)*4))
377
378
379#define SOLO_VE_CFG0 0x0610
380#define SOLO_VE_TWO_PAGE_MODE (1<<31)
381#define SOLO_VE_INTR_CTRL(n) ((n)<<24)
382#define SOLO_VE_BLOCK_SIZE(n) ((n)<<16)
383#define SOLO_VE_BLOCK_BASE(n) ((n)<<0)
384
385#define SOLO_VE_CFG1 0x0614
386#define SOLO_VE_BYTE_ALIGN(n) ((n)<<24)
387#define SOLO_VE_INSERT_INDEX (1<<18)
388#define SOLO_VE_MOTION_MODE(n) ((n)<<16)
389#define SOLO_VE_MOTION_BASE(n) ((n)<<0)
390
391#define SOLO_VE_WMRK_POLY 0x061C
392#define SOLO_VE_VMRK_INIT_KEY 0x0620
393#define SOLO_VE_WMRK_STRL 0x0624
394#define SOLO_VE_ENCRYP_POLY 0x0628
395#define SOLO_VE_ENCRYP_INIT 0x062C
396#define SOLO_VE_ATTR 0x0630
397#define SOLO_VE_LITTLE_ENDIAN (1<<31)
398#define SOLO_COMP_ATTR_RN (1<<30)
399#define SOLO_COMP_ATTR_FCODE(n) ((n)<<27)
400#define SOLO_COMP_TIME_INC(n) ((n)<<25)
401#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21)
402#define SOLO_DCT_INTERVAL(n) ((n)<<16)
403
404#define SOLO_VE_STATE(n) (0x0640+((n)*4))
405struct videnc_status {
406 union {
407 u32 status0;
408 struct {
409 u32 mp4_enc_code_size:20, sad_motion:1, vid_motion:1,
410 vop_type:2, video_channel:5, source_field_idx:1,
411 interlace:1, progressive:1;
412 } status0_st;
413 };
414 union {
415 u32 status1;
416 struct {
417 u32 vsize:8, hsize:8, last_queue:4, foo1:8, scale:4;
418 } status1_st;
419 };
420 union {
421 u32 status4;
422 struct {
423 u32 jpeg_code_size:20, interval:10, foo1:2;
424 } status4_st;
425 };
426 union {
427 u32 status9;
428 struct {
429 u32 channel:5, foo1:27;
430 } status9_st;
431 };
432 union {
433 u32 status10;
434 struct {
435 u32 mp4_code_size:20, foo:12;
436 } status10_st;
437 };
438 union {
439 u32 status11;
440 struct {
441 u32 last_queue:8, foo1:24;
442 } status11_st;
443 };
444};
445
446#define SOLO_VE_JPEG_QP_TBL 0x0670
447#define SOLO_VE_JPEG_QP_CH_L 0x0674
448#define SOLO_VE_JPEG_QP_CH_H 0x0678
449#define SOLO_VE_JPEG_CFG 0x067C
450#define SOLO_VE_JPEG_CTRL 0x0680
451
452#define SOLO_VE_OSD_CH 0x0690
453#define SOLO_VE_OSD_BASE 0x0694
454#define SOLO_VE_OSD_CLR 0x0698
455#define SOLO_VE_OSD_OPT 0x069C
456
457#define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4))
458#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4))
459#define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4))
460#define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4))
461#define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4))
462#define SOLO_VE_CH_GOP_E(ch) (0x0840+((ch)*4))
463#define SOLO_VE_CH_REF_BASE(ch) (0x0880+((ch)*4))
464#define SOLO_VE_CH_REF_BASE_E(ch) (0x08C0+((ch)*4))
465
466#define SOLO_VE_MPEG4_QUE(n) (0x0A00+((n)*8))
467#define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8))
468
469#define SOLO_VD_CFG0 0x0900
470#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24)
471#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23)
472#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22)
473#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21)
474#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20)
475#define SOLO_VD_CFG_SINGLE_MODE (1<<18)
476#define SOLO_VD_CFG_SCAL_MANUAL (1<<17)
477#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16)
478#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15)
479#define SOLO_VD_CFG_START_FI (1<<14)
480#define SOLO_VD_CFG_ERR_LOCK (1<<13)
481#define SOLO_VD_CFG_ERR_INT_ENA (1<<12)
482#define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8)
483#define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0)
484
485#define SOLO_VD_CFG1 0x0904
486
487#define SOLO_VD_DEINTERLACE 0x0908
488#define SOLO_VD_DEINTERLACE_THRESHOLD(n) ((n)<<8)
489#define SOLO_VD_DEINTERLACE_EDGE_VALUE(n) ((n)<<0)
490
491#define SOLO_VD_CODE_ADR 0x090C
492
493#define SOLO_VD_CTRL 0x0910
494#define SOLO_VD_OPER_ON (1<<31)
495#define SOLO_VD_MAX_ITEM(n) ((n)<<0)
496
497#define SOLO_VD_STATUS0 0x0920
498#define SOLO_VD_STATUS0_INTR_ACK (1<<22)
499#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21)
500#define SOLO_VD_STATUS0_INTR_ERR (1<<20)
501
502#define SOLO_VD_STATUS1 0x0924
503
504#define SOLO_VD_IDX0 0x0930
505#define SOLO_VD_IDX_INTERLACE (1<<30)
506#define SOLO_VD_IDX_CHANNEL(n) ((n)<<24)
507#define SOLO_VD_IDX_SIZE(n) ((n)<<0)
508
509#define SOLO_VD_IDX1 0x0934
510#define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28)
511#define SOLO_VD_IDX_WINDOW(n) ((n)<<24)
512#define SOLO_VD_IDX_DEINTERLACE (1<<16)
513#define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8)
514#define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0)
515
516#define SOLO_VD_IDX2 0x0938
517#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31)
518#define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff)
519
520#define SOLO_VD_IDX3 0x093C
521#define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28)
522#define SOLO_VD_IDX_INTERLACE_WR (1<<27)
523#define SOLO_VD_IDX_INTERPOL (1<<26)
524#define SOLO_VD_IDX_HOR2X (1<<25)
525#define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12)
526#define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0)
527
528#define SOLO_VD_IDX4 0x0940
529#define SOLO_VD_IDX_DEC_WR_PAGE(n) ((n)<<8)
530#define SOLO_VD_IDX_DISP_RD_PAGE(n) ((n)<<0)
531
532#define SOLO_VD_WR_PAGE(n) (0x03F0 + ((n) * 4))
533
534
535#define SOLO_GPIO_CONFIG_0 0x0B00
536#define SOLO_GPIO_CONFIG_1 0x0B04
537#define SOLO_GPIO_DATA_OUT 0x0B08
538#define SOLO_GPIO_DATA_IN 0x0B0C
539#define SOLO_GPIO_INT_ACK_STA 0x0B10
540#define SOLO_GPIO_INT_ENA 0x0B14
541#define SOLO_GPIO_INT_CFG_0 0x0B18
542#define SOLO_GPIO_INT_CFG_1 0x0B1C
543
544
545#define SOLO_IIC_CFG 0x0B20
546#define SOLO_IIC_ENABLE (1<<8)
547#define SOLO_IIC_PRESCALE(n) ((n)<<0)
548
549#define SOLO_IIC_CTRL 0x0B24
550#define SOLO_IIC_AUTO_CLEAR (1<<20)
551#define SOLO_IIC_STATE_RX_ACK (1<<19)
552#define SOLO_IIC_STATE_BUSY (1<<18)
553#define SOLO_IIC_STATE_SIG_ERR (1<<17)
554#define SOLO_IIC_STATE_TRNS (1<<16)
555#define SOLO_IIC_CH_SET(n) ((n)<<5)
556#define SOLO_IIC_ACK_EN (1<<4)
557#define SOLO_IIC_START (1<<3)
558#define SOLO_IIC_STOP (1<<2)
559#define SOLO_IIC_READ (1<<1)
560#define SOLO_IIC_WRITE (1<<0)
561
562#define SOLO_IIC_TXD 0x0B28
563#define SOLO_IIC_RXD 0x0B2C
564
565/*
566 * UART REGISTER
567 */
568#define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20))
569#define SOLO_UART_CLK_DIV(n) ((n)<<24)
570#define SOLO_MODEM_CTRL_EN (1<<20)
571#define SOLO_PARITY_ERROR_DROP (1<<18)
572#define SOLO_IRQ_ERR_EN (1<<17)
573#define SOLO_IRQ_RX_EN (1<<16)
574#define SOLO_IRQ_TX_EN (1<<15)
575#define SOLO_RX_EN (1<<14)
576#define SOLO_TX_EN (1<<13)
577#define SOLO_UART_HALF_DUPLEX (1<<12)
578#define SOLO_UART_LOOPBACK (1<<11)
579
580#define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6))
581#define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6))
582#define SOLO_BAUDRATE_57600 ((0<<9)|(2<<6))
583#define SOLO_BAUDRATE_38400 ((0<<9)|(3<<6))
584#define SOLO_BAUDRATE_19200 ((0<<9)|(4<<6))
585#define SOLO_BAUDRATE_9600 ((0<<9)|(5<<6))
586#define SOLO_BAUDRATE_4800 ((0<<9)|(6<<6))
587#define SOLO_BAUDRATE_2400 ((1<<9)|(6<<6))
588#define SOLO_BAUDRATE_1200 ((2<<9)|(6<<6))
589#define SOLO_BAUDRATE_300 ((3<<9)|(6<<6))
590
591#define SOLO_UART_DATA_BIT_8 (3<<4)
592#define SOLO_UART_DATA_BIT_7 (2<<4)
593#define SOLO_UART_DATA_BIT_6 (1<<4)
594#define SOLO_UART_DATA_BIT_5 (0<<4)
595
596#define SOLO_UART_STOP_BIT_1 (0<<2)
597#define SOLO_UART_STOP_BIT_2 (1<<2)
598
599#define SOLO_UART_PARITY_NONE (0<<0)
600#define SOLO_UART_PARITY_EVEN (2<<0)
601#define SOLO_UART_PARITY_ODD (3<<0)
602
603#define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20))
604#define SOLO_UART_CTS (1<<15)
605#define SOLO_UART_RX_BUSY (1<<14)
606#define SOLO_UART_OVERRUN (1<<13)
607#define SOLO_UART_FRAME_ERR (1<<12)
608#define SOLO_UART_PARITY_ERR (1<<11)
609#define SOLO_UART_TX_BUSY (1<<5)
610
611#define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f)
612#define SOLO_UART_RX_BUFF_SIZE 8
613#define SOLO_UART_TX_BUFF_CNT(stat) (((stat)>>0) & 0x1f)
614#define SOLO_UART_TX_BUFF_SIZE 8
615
616#define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20))
617#define SOLO_UART_TX_DATA_PUSH (1<<8)
618#define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20))
619#define SOLO_UART_RX_DATA_POP (1<<8)
620
621#define SOLO_TIMER_CLOCK_NUM 0x0be0
622#define SOLO_TIMER_WATCHDOG 0x0be4
623#define SOLO_TIMER_USEC 0x0be8
624#define SOLO_TIMER_SEC 0x0bec
625
626#define SOLO_AUDIO_CONTROL 0x0D00
627#define SOLO_AUDIO_ENABLE (1<<31)
628#define SOLO_AUDIO_MASTER_MODE (1<<30)
629#define SOLO_AUDIO_I2S_MODE (1<<29)
630#define SOLO_AUDIO_I2S_LR_SWAP (1<<27)
631#define SOLO_AUDIO_I2S_8BIT (1<<26)
632#define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24)
633#define SOLO_AUDIO_MIX_9TO0 (1<<23)
634#define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20)
635#define SOLO_AUDIO_MIX_19TO10 (1<<19)
636#define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16)
637#define SOLO_AUDIO_MODE(n) ((n)<<0)
638#define SOLO_AUDIO_SAMPLE 0x0D04
639#define SOLO_AUDIO_EE_MODE_ON (1<<30)
640#define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25)
641#define SOLO_AUDIO_BITRATE(n) ((n)<<16)
642#define SOLO_AUDIO_CLK_DIV(n) ((n)<<0)
643#define SOLO_AUDIO_FDMA_INTR 0x0D08
644#define SOLO_AUDIO_FDMA_INTERVAL(n) ((n)<<19)
645#define SOLO_AUDIO_INTR_ORDER(n) ((n)<<16)
646#define SOLO_AUDIO_FDMA_BASE(n) ((n)<<0)
647#define SOLO_AUDIO_EVOL_0 0x0D0C
648#define SOLO_AUDIO_EVOL_1 0x0D10
649#define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10))
650#define SOLO_AUDIO_STA 0x0D14
651
652
653#define SOLO_WATCHDOG 0x0BE4
654#define WATCHDOG_STAT(status) (status<<8)
655#define WATCHDOG_TIME(sec) (sec&0xff)
656
657#endif /* __SOLO6010_REGISTERS_H */
diff --git a/drivers/staging/solo6x10/solo6010-tw28.c b/drivers/staging/solo6x10/solo6010-tw28.c
new file mode 100644
index 00000000000..b4446b910e3
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-tw28.c
@@ -0,0 +1,678 @@
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
22#include "solo6010.h"
23#include "solo6010-tw28.h"
24
25/* XXX: Some of these values are masked into an 8-bit regs, and shifted
26 * around for other 8-bit regs. What are the magic bits in these values? */
27#define DEFAULT_HDELAY_NTSC (32 - 4)
28#define DEFAULT_HACTIVE_NTSC (720 + 16)
29#define DEFAULT_VDELAY_NTSC (7 - 2)
30#define DEFAULT_VACTIVE_NTSC (240 + 4)
31
32#define DEFAULT_HDELAY_PAL (32 + 4)
33#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL)
34#define DEFAULT_VDELAY_PAL (6)
35#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
36
37static u8 tbl_tw2864_template[] = {
38 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x00
39 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
40 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x10
41 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
42 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x20
43 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
44 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x30
45 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
54 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, // 0x80
55 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
56 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, // 0x90
57 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
58 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, // 0xa0
59 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
60 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, // 0xb0
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
63 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
64 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, // 0xd0
65 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
66 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, // 0xe0
67 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
68 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
69 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
70};
71
72#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
73
74static u8 tw_readbyte(struct solo6010_dev *solo_dev, int chip_id, u8 tw6x_off,
75 u8 tw_off)
76{
77 if (is_tw286x(solo_dev, chip_id))
78 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
79 TW_CHIP_OFFSET_ADDR(chip_id),
80 tw6x_off);
81 else
82 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
83 TW_CHIP_OFFSET_ADDR(chip_id),
84 tw_off);
85}
86
87static void tw_writebyte(struct solo6010_dev *solo_dev, int chip_id,
88 u8 tw6x_off, u8 tw_off, u8 val)
89{
90 if (is_tw286x(solo_dev, chip_id))
91 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
92 TW_CHIP_OFFSET_ADDR(chip_id),
93 tw6x_off, val);
94 else
95 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
96 TW_CHIP_OFFSET_ADDR(chip_id),
97 tw_off, val);
98}
99
100static void tw_write_and_verify(struct solo6010_dev *solo_dev, u8 addr, u8 off,
101 u8 val)
102{
103 int i;
104
105 for (i = 0; i < 5; i++) {
106 u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
107 if (rval == val)
108 return;
109
110 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
111 msleep_interruptible(1);
112 }
113
114 printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
115 addr, off, val);
116}
117
118static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
119{
120 u8 tbl_tw2864_common[256];
121 int i;
122
123 memcpy(tbl_tw2864_common, tbl_tw2864_template,
124 sizeof(tbl_tw2864_common));
125
126 /* IRQ Mode */
127 if (solo_dev->nr_chans == 4) {
128 tbl_tw2864_common[0xd2] = 0x01;
129 tbl_tw2864_common[0xcf] = 0x00;
130 } else if (solo_dev->nr_chans == 8) {
131 tbl_tw2864_common[0xd2] = 0x02;
132 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
133 tbl_tw2864_common[0xcf] = 0x43;
134 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
135 tbl_tw2864_common[0xcf] = 0x40;
136 } else if (solo_dev->nr_chans == 16) {
137 tbl_tw2864_common[0xd2] = 0x03;
138 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
139 tbl_tw2864_common[0xcf] = 0x43;
140 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
141 tbl_tw2864_common[0xcf] = 0x43;
142 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
143 tbl_tw2864_common[0xcf] = 0x43;
144 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
145 tbl_tw2864_common[0xcf] = 0x40;
146 }
147
148 /* NTSC or PAL */
149 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
150 for (i = 0; i < 4; i++) {
151 tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
152 tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
153 tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
154 tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
155 tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
156 }
157 tbl_tw2864_common[0x9d] = 0x90;
158 tbl_tw2864_common[0xf3] = 0x00;
159 tbl_tw2864_common[0xf4] = 0xa0;
160 }
161
162 for (i = 0; i < 0xff; i++) {
163 /* Skip read only registers */
164 if (i >= 0xb8 && i <= 0xc1 )
165 continue;
166 if ((i & ~0x30) == 0x00 ||
167 (i & ~0x30) == 0x0c ||
168 (i & ~0x30) == 0x0d)
169 continue;
170 if (i == 0x74 || i == 0x77 || i == 0x78 ||
171 i == 0x79 || i == 0x7a)
172 continue;
173 if (i == 0xfd)
174 continue;
175
176 tw_write_and_verify(solo_dev, dev_addr, i,
177 tbl_tw2864_common[i]);
178 }
179
180 return 0;
181}
182
183static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
184{
185 u8 tbl_ntsc_tw2815_common[] = {
186 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
187 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
188 };
189
190 u8 tbl_pal_tw2815_common[] = {
191 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
192 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
193 };
194
195 u8 tbl_tw2815_sfr[] = {
196 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, // 0x00
197 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
198 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, // 0x10
199 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
200 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, // 0x20
201 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
202 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, // 0x30
203 };
204 u8 *tbl_tw2815_common;
205 int i;
206 int ch;
207
208 tbl_ntsc_tw2815_common[0x06] = 0;
209
210 /* Horizontal Delay Control */
211 tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
212 tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
213
214 /* Horizontal Active Control */
215 tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
216 tbl_ntsc_tw2815_common[0x06] |=
217 ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
218
219 /* Vertical Delay Control */
220 tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
221 tbl_ntsc_tw2815_common[0x06] |=
222 ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
223
224 /* Vertical Active Control */
225 tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
226 tbl_ntsc_tw2815_common[0x06] |=
227 ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
228
229 tbl_pal_tw2815_common[0x06] = 0;
230
231 /* Horizontal Delay Control */
232 tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
233 tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
234
235 /* Horizontal Active Control */
236 tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
237 tbl_pal_tw2815_common[0x06] |=
238 ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
239
240 /* Vertical Delay Control */
241 tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
242 tbl_pal_tw2815_common[0x06] |=
243 ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
244
245 /* Vertical Active Control */
246 tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
247 tbl_pal_tw2815_common[0x06] |=
248 ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
249
250 tbl_tw2815_common =
251 (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
252 tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
253
254 /* Dual ITU-R BT.656 format */
255 tbl_tw2815_common[0x0d] |= 0x04;
256
257 /* Audio configuration */
258 tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
259
260 if (solo_dev->nr_chans == 4) {
261 tbl_tw2815_sfr[0x63 - 0x40] |= 1;
262 tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
263 } else if (solo_dev->nr_chans == 8) {
264 tbl_tw2815_sfr[0x63 - 0x40] |= 2;
265 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
266 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
267 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
268 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
269 } else if (solo_dev->nr_chans == 16) {
270 tbl_tw2815_sfr[0x63 - 0x40] |= 3;
271 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
272 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
273 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
274 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
275 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
276 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
277 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
278 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
279 }
280
281 /* Output mode of R_ADATM pin (0 mixing, 1 record) */
282 /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
283
284 /* 8KHz, used to be 16KHz, but changed for remote client compat */
285 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
286 tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
287
288 /* Playback of right channel */
289 tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
290
291 /* Reserved value (XXX ??) */
292 tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
293
294 /* Analog output gain and mix ratio playback on full */
295 tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
296 /* Select playback audio and mute all except */
297 tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
298 tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
299
300 /* End of audio configuration */
301
302 for (ch = 0; ch < 4; ch++) {
303 tbl_tw2815_common[0x0d] &= ~3;
304 switch (ch) {
305 case 0:
306 tbl_tw2815_common[0x0d] |= 0x21;
307 break;
308 case 1:
309 tbl_tw2815_common[0x0d] |= 0x20;
310 break;
311 case 2:
312 tbl_tw2815_common[0x0d] |= 0x23;
313 break;
314 case 3:
315 tbl_tw2815_common[0x0d] |= 0x22;
316 break;
317 }
318
319 for (i = 0; i < 0x0f; i++) {
320 if (i == 0x00)
321 continue; // read-only
322 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
323 dev_addr, (ch * 0x10) + i,
324 tbl_tw2815_common[i]);
325 }
326 }
327
328 for (i = 0x40; i < 0x76; i++) {
329 /* Skip read-only and nop registers */
330 if (i == 0x40 || i == 0x59 || i == 0x5a ||
331 i == 0x5d || i == 0x5e || i == 0x5f)
332 continue;
333
334 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
335 tbl_tw2815_sfr[i - 0x40]);
336 }
337
338 return 0;
339}
340
341#define FIRST_ACTIVE_LINE 0x0008
342#define LAST_ACTIVE_LINE 0x0102
343
344static void saa7128_setup(struct solo6010_dev *solo_dev)
345{
346 int i;
347 unsigned char regs[128] = {
348 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
353 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
354 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
355 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
357 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
358 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
359 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
360 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
361 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
362 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
363 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
364 };
365
366 regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
367 regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
368 regs[0x7C] = ((1 << 7) |
369 (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
370 (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
371
372 /* PAL: XXX: We could do a second set of regs to avoid this */
373 if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
374 regs[0x28] = 0xE1;
375
376 regs[0x5A] = 0x0F;
377 regs[0x61] = 0x02;
378 regs[0x62] = 0x35;
379 regs[0x63] = 0xCB;
380 regs[0x64] = 0x8A;
381 regs[0x65] = 0x09;
382 regs[0x66] = 0x2A;
383
384 regs[0x6C] = 0xf1;
385 regs[0x6E] = 0x20;
386
387 regs[0x7A] = 0x06 + 12;
388 regs[0x7b] = 0x24 + 12;
389 regs[0x7c] |= 1 << 6;
390 }
391
392 /* First 0x25 bytes are read-only? */
393 for (i = 0x26; i < 128; i++) {
394 if (i == 0x60 || i == 0x7D)
395 continue;
396 solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
397 }
398
399 return;
400}
401
402int solo_tw28_init(struct solo6010_dev *solo_dev)
403{
404 int i;
405 u8 value;
406
407 /* Detect techwell chip type */
408 for (i = 0; i < TW_NUM_CHIP; i++) {
409 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
410 TW_CHIP_OFFSET_ADDR(i), 0xFF);
411
412 switch (value >> 3) {
413 case 0x18:
414 printk("solo6010: 2865 support not enabled\n");
415 return -EINVAL;
416 break;
417 case 0x0c:
418 solo_dev->tw2864 |= 1 << i;
419 solo_dev->tw28_cnt++;
420 break;
421 default:
422 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
423 TW_CHIP_OFFSET_ADDR(i), 0x59);
424 if ((value >> 3) == 0x04) {
425 solo_dev->tw2815 |= 1 << i;
426 solo_dev->tw28_cnt++;
427 }
428 }
429 }
430
431 if (!solo_dev->tw28_cnt)
432 return -EINVAL;
433
434 saa7128_setup(solo_dev);
435
436 for (i = 0; i < solo_dev->tw28_cnt; i++) {
437 if ((solo_dev->tw2864 & (1 << i)))
438 tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
439 else
440 tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
441 }
442
443 dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
444 solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
445
446 if (solo_dev->tw2864)
447 printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
448 if (solo_dev->tw2815)
449 printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
450 printk("\n");
451
452 return 0;
453}
454
455/*
456 * We accessed the video status signal in the Techwell chip through
457 * iic/i2c because the video status reported by register REG_VI_STATUS1
458 * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
459 * status signal values.
460 */
461int tw28_get_video_status(struct solo6010_dev *solo_dev, u8 ch)
462{
463 u8 val, chip_num;
464
465 /* Get the right chip and on-chip channel */
466 chip_num = ch / 4;
467 ch %= 4;
468
469 val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
470 TW_AV_STAT_ADDR) & 0x0f;
471
472 return val & (1 << ch) ? 1 : 0;
473}
474
475#if 0
476/* Status of audio from up to 4 techwell chips are combined into 1 variable.
477 * See techwell datasheet for details. */
478u16 tw28_get_audio_status(struct solo6010_dev *solo_dev)
479{
480 u8 val;
481 u16 status = 0;
482 int i;
483
484 for (i = 0; i < solo_dev->tw28_cnt; i++) {
485 val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
486 TW_AV_STAT_ADDR) & 0xf0) >> 4;
487 status |= val << (i * 4);
488 }
489
490 return status;
491}
492#endif
493
494int tw28_set_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
495 s32 val)
496{
497 char sval;
498 u8 chip_num;
499
500 /* Get the right chip and on-chip channel */
501 chip_num = ch / 4;
502 ch %= 4;
503
504 if (val > 255 || val < 0)
505 return -ERANGE;
506
507 switch (ctrl) {
508 case V4L2_CID_SHARPNESS:
509 /* Only 286x has sharpness */
510 if (val > 0x0f || val < 0)
511 return -ERANGE;
512 if (is_tw286x(solo_dev, chip_num)) {
513 u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
514 TW_CHIP_OFFSET_ADDR(chip_num),
515 TW286x_SHARPNESS(chip_num));
516 v &= 0xf0;
517 v |= val;
518 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
519 TW_CHIP_OFFSET_ADDR(chip_num),
520 TW286x_SHARPNESS(chip_num), v);
521 } else if (val != 0)
522 return -ERANGE;
523 break;
524
525 case V4L2_CID_HUE:
526 if (is_tw286x(solo_dev, chip_num))
527 sval = val - 128;
528 else
529 sval = (char)val;
530 tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
531 TW_HUE_ADDR(ch), sval);
532
533 break;
534
535 case V4L2_CID_SATURATION:
536 if (is_tw286x(solo_dev, chip_num)) {
537 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
538 TW_CHIP_OFFSET_ADDR(chip_num),
539 TW286x_SATURATIONU_ADDR(ch), val);
540 }
541 tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
542 TW_SATURATION_ADDR(ch), val);
543
544 break;
545
546 case V4L2_CID_CONTRAST:
547 tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
548 TW_CONTRAST_ADDR(ch), val);
549 break;
550
551 case V4L2_CID_BRIGHTNESS:
552 if (is_tw286x(solo_dev, chip_num))
553 sval = val - 128;
554 else
555 sval = (char)val;
556 tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
557 TW_BRIGHTNESS_ADDR(ch), sval);
558
559 break;
560 default:
561 return -EINVAL;
562 }
563
564 return 0;
565}
566
567int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
568 s32 *val)
569{
570 u8 rval, chip_num;
571
572 /* Get the right chip and on-chip channel */
573 chip_num = ch / 4;
574 ch %= 4;
575
576 switch (ctrl) {
577 case V4L2_CID_SHARPNESS:
578 /* Only 286x has sharpness */
579 if (is_tw286x(solo_dev, chip_num)) {
580 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
581 TW_CHIP_OFFSET_ADDR(chip_num),
582 TW286x_SHARPNESS(chip_num));
583 *val = rval & 0x0f;
584 } else
585 *val = 0;
586 break;
587 case V4L2_CID_HUE:
588 rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
589 TW_HUE_ADDR(ch));
590 if (is_tw286x(solo_dev, chip_num))
591 *val = (s32)((char)rval) + 128;
592 else
593 *val = rval;
594 break;
595 case V4L2_CID_SATURATION:
596 *val = tw_readbyte(solo_dev, chip_num,
597 TW286x_SATURATIONU_ADDR(ch),
598 TW_SATURATION_ADDR(ch));
599 break;
600 case V4L2_CID_CONTRAST:
601 *val = tw_readbyte(solo_dev, chip_num,
602 TW286x_CONTRAST_ADDR(ch),
603 TW_CONTRAST_ADDR(ch));
604 break;
605 case V4L2_CID_BRIGHTNESS:
606 rval = tw_readbyte(solo_dev, chip_num,
607 TW286x_BRIGHTNESS_ADDR(ch),
608 TW_BRIGHTNESS_ADDR(ch));
609 if (is_tw286x(solo_dev, chip_num))
610 *val = (s32)((char)rval) + 128;
611 else
612 *val = rval;
613 break;
614 default:
615 return -EINVAL;
616 }
617
618 return 0;
619}
620
621#if 0
622/*
623 * For audio output volume, the output channel is only 1. In this case we
624 * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
625 * is the base address of the techwell chip.
626 */
627void tw2815_Set_AudioOutVol(struct solo6010_dev *solo_dev, unsigned int u_val)
628{
629 unsigned int val;
630 unsigned int chip_num;
631
632 chip_num = (solo_dev->nr_chans - 1) / 4;
633
634 val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
635 TW_AUDIO_OUTPUT_VOL_ADDR);
636
637 u_val = (val & 0x0f) | (u_val << 4);
638
639 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
640 TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
641}
642#endif
643
644u8 tw28_get_audio_gain(struct solo6010_dev *solo_dev, u8 ch)
645{
646 u8 val;
647 u8 chip_num;
648
649 /* Get the right chip and on-chip channel */
650 chip_num = ch / 4;
651 ch %= 4;
652
653 val = tw_readbyte(solo_dev, chip_num,
654 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
655 TW_AUDIO_INPUT_GAIN_ADDR(ch));
656
657 return (ch % 2) ? (val >> 4) : (val & 0x0f);
658}
659
660void tw28_set_audio_gain(struct solo6010_dev *solo_dev, u8 ch, u8 val)
661{
662 u8 old_val;
663 u8 chip_num;
664
665 /* Get the right chip and on-chip channel */
666 chip_num = ch / 4;
667 ch %= 4;
668
669 old_val = tw_readbyte(solo_dev, chip_num,
670 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
671 TW_AUDIO_INPUT_GAIN_ADDR(ch));
672
673 val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
674 ((ch % 2) ? (val << 4) : val);
675
676 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
677 TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
678}
diff --git a/drivers/staging/solo6x10/solo6010-tw28.h b/drivers/staging/solo6x10/solo6010-tw28.h
new file mode 100644
index 00000000000..a7eecfa1a81
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-tw28.h
@@ -0,0 +1,65 @@
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 __SOLO6010_TW28_H
21#define __SOLO6010_TW28_H
22
23#include "solo6010.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 solo6010_dev *solo_dev);
50
51int tw28_set_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
52 s32 val);
53int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
54 s32 *val);
55
56u8 tw28_get_audio_gain(struct solo6010_dev *solo_dev, u8 ch);
57void tw28_set_audio_gain(struct solo6010_dev *solo_dev, u8 ch, u8 val);
58int tw28_get_video_status(struct solo6010_dev *solo_dev, u8 ch);
59
60#if 0
61unsigned int tw2815_get_audio_status(struct SOLO6010 *solo6010);
62void tw2815_Set_AudioOutVol(struct SOLO6010 *solo6010, unsigned int u_val);
63#endif
64
65#endif /* __SOLO6010_TW28_H */
diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c
new file mode 100644
index 00000000000..f114b4b7d8e
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c
@@ -0,0 +1,1564 @@
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
25#include <media/v4l2-ioctl.h>
26#include <media/v4l2-common.h>
27#include <media/videobuf-dma-contig.h>
28
29#include "solo6010.h"
30#include "solo6010-tw28.h"
31#include "solo6010-jpeg.h"
32
33#define MIN_VID_BUFFERS 4
34#define FRAME_BUF_SIZE (128 * 1024)
35#define MP4_QS 16
36
37static int solo_enc_thread(void *data);
38
39extern unsigned video_nr;
40
41struct solo_enc_fh {
42 struct solo_enc_dev *enc;
43 u32 fmt;
44 u16 rd_idx;
45 u8 enc_on;
46 enum solo_enc_types type;
47 struct videobuf_queue vidq;
48 struct list_head vidq_active;
49 struct task_struct *kthread;
50};
51
52static unsigned char vid_vop_header[] = {
53 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
54 0x02, 0x48, 0x05, 0xc0, 0x00, 0x40, 0x00, 0x40,
55 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
56 0x1f, 0x4c, 0x58, 0x10, 0x78, 0x51, 0x18, 0x3e,
57};
58
59/*
60 * Things we can change around:
61 *
62 * byte 10, 4-bits 01111000 aspect
63 * bytes 21,22,23 16-bits 000x1111 11111111 1111x000 fps/res
64 * bytes 23,24,25 15-bits 00000n11 11111111 11111x00 interval
65 * bytes 25,26,27 13-bits 00000x11 11111111 111x0000 width
66 * bytes 27,28,29 13-bits 000x1111 11111111 1x000000 height
67 * byte 29 1-bit 0x100000 interlace
68 */
69
70/* For aspect */
71#define XVID_PAR_43_PAL 2
72#define XVID_PAR_43_NTSC 3
73
74static const u32 solo_user_ctrls[] = {
75 V4L2_CID_BRIGHTNESS,
76 V4L2_CID_CONTRAST,
77 V4L2_CID_SATURATION,
78 V4L2_CID_HUE,
79 V4L2_CID_SHARPNESS,
80 0
81};
82
83static const u32 solo_mpeg_ctrls[] = {
84 V4L2_CID_MPEG_VIDEO_ENCODING,
85 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
86 0
87};
88
89static const u32 solo_private_ctrls[] = {
90 V4L2_CID_MOTION_ENABLE,
91 V4L2_CID_MOTION_THRESHOLD,
92 0
93};
94
95static const u32 solo_fmtx_ctrls[] = {
96 V4L2_CID_RDS_TX_RADIO_TEXT,
97 0
98};
99
100static const u32 *solo_ctrl_classes[] = {
101 solo_user_ctrls,
102 solo_mpeg_ctrls,
103 solo_fmtx_ctrls,
104 solo_private_ctrls,
105 NULL
106};
107
108struct vop_header {
109 /* VD_IDX0 */
110 u32 size:20, sync_start:1, page_stop:1, vop_type:2, channel:4,
111 nop0:1, source_fl:1, interlace:1, progressive:1;
112
113 /* VD_IDX1 */
114 u32 vsize:8, hsize:8, frame_interop:1, nop1:7, win_id:4, scale:4;
115
116 /* VD_IDX2 */
117 u32 base_addr:16, nop2:15, hoff:1;
118
119 /* VD_IDX3 - User set macros */
120 u32 sy:12, sx:12, nop3:1, hzoom:1, read_interop:1, write_interlace:1,
121 scale_mode:4;
122
123 /* VD_IDX4 - User set macros continued */
124 u32 write_page:8, nop4:24;
125
126 /* VD_IDX5 */
127 u32 next_code_addr;
128
129 u32 end_nops[10];
130} __attribute__((packed));
131
132static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
133{
134 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
135 u8 ch = solo_enc->ch;
136
137 if (solo_dev->motion_mask & (1 << ch))
138 return 1;
139 return 0;
140}
141
142static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
143{
144 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
145 u8 ch = solo_enc->ch;
146
147 spin_lock(&solo_enc->lock);
148
149 if (on)
150 solo_dev->motion_mask |= (1 << ch);
151 else
152 solo_dev->motion_mask &= ~(1 << ch);
153
154 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
155 SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
156 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
157
158 if (solo_dev->motion_mask)
159 solo6010_irq_on(solo_dev, SOLO_IRQ_MOTION);
160 else
161 solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
162
163 spin_unlock(&solo_enc->lock);
164}
165
166/* Should be called with solo_enc->lock held */
167static void solo_update_mode(struct solo_enc_dev *solo_enc)
168{
169 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
170
171 assert_spin_locked(&solo_enc->lock);
172
173 solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
174 solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
175
176 switch (solo_enc->mode) {
177 case SOLO_ENC_MODE_CIF:
178 solo_enc->width = solo_dev->video_hsize >> 1;
179 solo_enc->height = solo_dev->video_vsize;
180 break;
181 case SOLO_ENC_MODE_D1:
182 solo_enc->width = solo_dev->video_hsize;
183 solo_enc->height = solo_dev->video_vsize << 1;
184 solo_enc->bw_weight <<= 2;
185 break;
186 default:
187 WARN(1, "mode is unknown");
188 }
189}
190
191/* Should be called with solo_enc->lock held */
192static int solo_enc_on(struct solo_enc_fh *fh)
193{
194 struct solo_enc_dev *solo_enc = fh->enc;
195 u8 ch = solo_enc->ch;
196 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
197 u8 interval;
198
199 assert_spin_locked(&solo_enc->lock);
200
201 if (fh->enc_on)
202 return 0;
203
204 solo_update_mode(solo_enc);
205
206 /* Make sure to bw check on first reader */
207 if (!atomic_read(&solo_enc->readers)) {
208 if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
209 return -EBUSY;
210 else
211 solo_dev->enc_bw_remain -= solo_enc->bw_weight;
212 }
213
214 fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6010_NAME "_enc");
215
216 if (IS_ERR(fh->kthread))
217 return PTR_ERR(fh->kthread);
218
219 fh->enc_on = 1;
220 fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
221
222 if (fh->type == SOLO_ENC_TYPE_EXT)
223 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
224
225 if (atomic_inc_return(&solo_enc->readers) > 1)
226 return 0;
227
228 /* Disable all encoding for this channel */
229 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
230
231 /* Common for both std and ext encoding */
232 solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
233 solo_enc->interlaced ? 1 : 0);
234
235 if (solo_enc->interlaced)
236 interval = solo_enc->interval - 1;
237 else
238 interval = solo_enc->interval;
239
240 /* Standard encoding only */
241 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
242 solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
243 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
244
245 /* Extended encoding only */
246 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
247 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
248 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
249
250 /* Enables the standard encoder */
251 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
252
253 /* Settle down Beavis... */
254 mdelay(10);
255
256 return 0;
257}
258
259static void solo_enc_off(struct solo_enc_fh *fh)
260{
261 struct solo_enc_dev *solo_enc = fh->enc;
262 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
263
264 if (!fh->enc_on)
265 return;
266
267 if (fh->kthread) {
268 kthread_stop(fh->kthread);
269 fh->kthread = NULL;
270 }
271
272 solo_dev->enc_bw_remain += solo_enc->bw_weight;
273 fh->enc_on = 0;
274
275 if (atomic_dec_return(&solo_enc->readers) > 0)
276 return;
277
278 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
279 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
280}
281
282static void enc_reset_gop(struct solo6010_dev *solo_dev, u8 ch)
283{
284 BUG_ON(ch >= solo_dev->nr_chans);
285 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1);
286 solo_dev->v4l2_enc[ch]->reset_gop = 1;
287}
288
289static int enc_gop_reset(struct solo6010_dev *solo_dev, u8 ch, u8 vop)
290{
291 BUG_ON(ch >= solo_dev->nr_chans);
292 if (!solo_dev->v4l2_enc[ch]->reset_gop)
293 return 0;
294 if (vop)
295 return 1;
296 solo_dev->v4l2_enc[ch]->reset_gop = 0;
297 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch),
298 solo_dev->v4l2_enc[ch]->gop);
299 return 0;
300}
301
302static int enc_get_mpeg_dma_t(struct solo6010_dev *solo_dev, dma_addr_t buf,
303 unsigned int off, unsigned int size)
304{
305 int ret;
306
307 if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
308 return -EINVAL;
309
310 if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev))
311 return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
312 SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
313
314 /* Buffer wrap */
315 ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
316 SOLO_MP4E_EXT_ADDR(solo_dev) + off,
317 SOLO_MP4E_EXT_SIZE(solo_dev) - off);
318
319 ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0,
320 buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
321 SOLO_MP4E_EXT_ADDR(solo_dev),
322 size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
323
324 return ret;
325}
326
327static int enc_get_mpeg_dma(struct solo6010_dev *solo_dev, void *buf,
328 unsigned int off, unsigned int size)
329{
330 int ret;
331
332 dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size,
333 PCI_DMA_FROMDEVICE);
334 ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size);
335 pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE);
336
337 return ret;
338}
339
340static int enc_get_jpeg_dma(struct solo6010_dev *solo_dev, dma_addr_t buf,
341 unsigned int off, unsigned int size)
342{
343 int ret;
344
345 if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
346 return -EINVAL;
347
348 if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev))
349 return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf,
350 SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
351
352 /* Buffer wrap */
353 ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf,
354 SOLO_JPEG_EXT_ADDR(solo_dev) + off,
355 SOLO_JPEG_EXT_SIZE(solo_dev) - off);
356
357 ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0,
358 buf + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
359 SOLO_JPEG_EXT_ADDR(solo_dev),
360 size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
361
362 return ret;
363}
364
365static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
366 struct videobuf_buffer *vb, dma_addr_t vbuf)
367{
368 struct solo_enc_dev *solo_enc = fh->enc;
369 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
370 u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
371
372 memcpy(p, jpeg_header, sizeof(jpeg_header));
373 p[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
374 p[SOF0_START + 6] = 0xff & solo_enc->height;
375 p[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
376 p[SOF0_START + 8] = 0xff & solo_enc->width;
377
378 vbuf += sizeof(jpeg_header);
379 vb->size = enc_buf->jpeg_size + sizeof(jpeg_header);
380
381 return enc_get_jpeg_dma(solo_dev, vbuf, enc_buf->jpeg_off,
382 enc_buf->jpeg_size);
383}
384
385static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
386 struct videobuf_buffer *vb, dma_addr_t vbuf)
387{
388 struct solo_enc_dev *solo_enc = fh->enc;
389 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
390 struct vop_header vh;
391 int ret;
392 int frame_size, frame_off;
393
394 if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
395 return -1;
396
397 /* First get the hardware vop header (not real mpeg) */
398 ret = enc_get_mpeg_dma(solo_dev, &vh, enc_buf->off, sizeof(vh));
399 if (ret)
400 return -1;
401
402 if (WARN_ON_ONCE(vh.size > enc_buf->size))
403 return -1;
404
405 vb->width = vh.hsize << 4;
406 vb->height = vh.vsize << 4;
407 vb->size = vh.size;
408
409 /* If this is a key frame, add extra m4v header */
410 if (!enc_buf->vop) {
411 u16 fps = solo_dev->fps * 1000;
412 u16 interval = solo_enc->interval * 1000;
413 u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
414
415 memcpy(p, vid_vop_header, sizeof(vid_vop_header));
416
417 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
418 p[10] |= ((XVID_PAR_43_NTSC << 3) & 0x78);
419 else
420 p[10] |= ((XVID_PAR_43_PAL << 3) & 0x78);
421
422 /* Frame rate and interval */
423 p[22] = fps >> 4;
424 p[23] = ((fps << 4) & 0xf0) | 0x0c | ((interval >> 13) & 0x3);
425 p[24] = (interval >> 5) & 0xff;
426 p[25] = ((interval << 3) & 0xf8) | 0x04;
427
428 /* Width and height */
429 p[26] = (vb->width >> 3) & 0xff;
430 p[27] = ((vb->height >> 9) & 0x0f) | 0x10;
431 p[28] = (vb->height >> 1) & 0xff;
432
433 /* Interlace */
434 if (vh.interlace)
435 p[29] |= 0x20;
436
437 /* Adjust the dma buffer past this header */
438 vb->size += sizeof(vid_vop_header);
439 vbuf += sizeof(vid_vop_header);
440 }
441
442 /* Now get the actual mpeg payload */
443 frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
444 frame_size = enc_buf->size - sizeof(vh);
445 ret = enc_get_mpeg_dma_t(solo_dev, vbuf, frame_off, frame_size);
446 if (WARN_ON_ONCE(ret))
447 return -1;
448
449 return 0;
450}
451
452/* On successful return (0), leaves solo_enc->lock unlocked */
453static int solo_enc_fillbuf(struct solo_enc_fh *fh,
454 struct videobuf_buffer *vb)
455{
456 struct solo_enc_dev *solo_enc = fh->enc;
457 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
458 struct solo_enc_buf *enc_buf = NULL;
459 dma_addr_t vbuf;
460 int ret;
461 u16 idx = fh->rd_idx;
462
463 while (idx != solo_dev->enc_wr_idx) {
464 struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx];
465 idx = (idx + 1) % SOLO_NR_RING_BUFS;
466 if (fh->fmt == V4L2_PIX_FMT_MPEG) {
467 if (fh->type != ebuf->type)
468 continue;
469 if (ebuf->ch == solo_enc->ch) {
470 enc_buf = ebuf;
471 break;
472 }
473 } else if (ebuf->ch == solo_enc->ch) {
474 /* For mjpeg, keep reading to the newest frame */
475 enc_buf = ebuf;
476 }
477 }
478
479 fh->rd_idx = idx;
480
481 if (!enc_buf)
482 return -1;
483
484 if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
485 vb->bsize < enc_buf->size) ||
486 (fh->fmt == V4L2_PIX_FMT_MJPEG &&
487 vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
488 return -1;
489 }
490
491 if (!(vbuf = videobuf_to_dma_contig(vb)))
492 return -1;
493
494 /* Is it ok that we mess with this buffer out of lock? */
495 spin_unlock(&solo_enc->lock);
496
497 if (fh->fmt == V4L2_PIX_FMT_MPEG)
498 ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
499 else
500 ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
501
502 if (ret) // Ignore failures
503 return 0;
504
505 list_del(&vb->queue);
506 vb->field_count++;
507 vb->ts = enc_buf->ts;
508 vb->state = VIDEOBUF_DONE;
509
510 wake_up(&vb->done);
511
512 return 0;
513}
514
515static void solo_enc_thread_try(struct solo_enc_fh *fh)
516{
517 struct solo_enc_dev *solo_enc = fh->enc;
518 struct videobuf_buffer *vb;
519
520 for (;;) {
521 spin_lock(&solo_enc->lock);
522
523 if (list_empty(&fh->vidq_active))
524 break;
525
526 vb = list_first_entry(&fh->vidq_active,
527 struct videobuf_buffer, queue);
528
529 if (!waitqueue_active(&vb->done))
530 break;
531
532 /* On success, returns with solo_enc->lock unlocked */
533 if (solo_enc_fillbuf(fh, vb))
534 break;
535 }
536
537 assert_spin_locked(&solo_enc->lock);
538 spin_unlock(&solo_enc->lock);
539}
540
541static int solo_enc_thread(void *data)
542{
543 struct solo_enc_fh *fh = data;
544 struct solo_enc_dev *solo_enc = fh->enc;
545 DECLARE_WAITQUEUE(wait, current);
546
547 set_freezable();
548 add_wait_queue(&solo_enc->thread_wait, &wait);
549
550 for (;;) {
551 long timeout = schedule_timeout_interruptible(HZ);
552 if (timeout == -ERESTARTSYS || kthread_should_stop())
553 break;
554 solo_enc_thread_try(fh);
555 try_to_freeze();
556 }
557
558 remove_wait_queue(&solo_enc->thread_wait, &wait);
559
560 return 0;
561}
562
563void solo_motion_isr(struct solo6010_dev *solo_dev)
564{
565 u32 status;
566 int i;
567
568 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION);
569
570 status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS);
571
572 for (i = 0; i < solo_dev->nr_chans; i++) {
573 struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i];
574
575 BUG_ON(solo_enc == NULL);
576
577 if (solo_enc->motion_detected)
578 continue;
579 if (!(status & (1 << i)))
580 continue;
581
582 solo_enc->motion_detected = 1;
583 }
584}
585
586void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev)
587{
588 struct solo_enc_buf *enc_buf;
589 struct videnc_status vstatus;
590 u32 mpeg_current, mpeg_next, mpeg_size;
591 u32 jpeg_current, jpeg_next, jpeg_size;
592 u32 reg_mpeg_size;
593 u8 cur_q, vop_type;
594 u8 ch;
595 enum solo_enc_types enc_type;
596
597 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER);
598
599 vstatus.status11 = solo_reg_read(solo_dev, SOLO_VE_STATE(11));
600 cur_q = (vstatus.status11_st.last_queue + 1) % MP4_QS;
601
602 vstatus.status0 = solo_reg_read(solo_dev, SOLO_VE_STATE(0));
603 reg_mpeg_size = (vstatus.status0_st.mp4_enc_code_size + 64 + 32) &
604 (~31);
605
606 while (solo_dev->enc_idx != cur_q) {
607 mpeg_current = solo_reg_read(solo_dev,
608 SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
609 jpeg_current = solo_reg_read(solo_dev,
610 SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
611 solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
612 mpeg_next = solo_reg_read(solo_dev,
613 SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
614 jpeg_next = solo_reg_read(solo_dev,
615 SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
616
617 if ((ch = (mpeg_current >> 24) & 0x1f) >= SOLO_MAX_CHANNELS) {
618 ch -= SOLO_MAX_CHANNELS;
619 enc_type = SOLO_ENC_TYPE_EXT;
620 } else
621 enc_type = SOLO_ENC_TYPE_STD;
622
623 vop_type = (mpeg_current >> 29) & 3;
624
625 mpeg_current &= 0x00ffffff;
626 mpeg_next &= 0x00ffffff;
627 jpeg_current &= 0x00ffffff;
628 jpeg_next &= 0x00ffffff;
629
630 mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) +
631 mpeg_next - mpeg_current) %
632 SOLO_MP4E_EXT_SIZE(solo_dev);
633
634 jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) +
635 jpeg_next - jpeg_current) %
636 SOLO_JPEG_EXT_SIZE(solo_dev);
637
638 /* XXX I think this means we had a ring overflow? */
639 if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) {
640 enc_reset_gop(solo_dev, ch);
641 continue;
642 }
643
644 /* When resetting the GOP, skip frames until I-frame */
645 if (enc_gop_reset(solo_dev, ch, vop_type))
646 continue;
647
648 enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx];
649
650 enc_buf->vop = vop_type;
651 enc_buf->ch = ch;
652 enc_buf->off = mpeg_current;
653 enc_buf->size = mpeg_size;
654 enc_buf->jpeg_off = jpeg_current;
655 enc_buf->jpeg_size = jpeg_size;
656 enc_buf->type = enc_type;
657
658 do_gettimeofday(&enc_buf->ts);
659
660 solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) %
661 SOLO_NR_RING_BUFS;
662
663 wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait);
664 }
665
666 return;
667}
668
669static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
670 unsigned int *size)
671{
672 *size = FRAME_BUF_SIZE;
673
674 if (*count < MIN_VID_BUFFERS)
675 *count = MIN_VID_BUFFERS;
676
677 return 0;
678}
679
680static int solo_enc_buf_prepare(struct videobuf_queue *vq,
681 struct videobuf_buffer *vb,
682 enum v4l2_field field)
683{
684 struct solo_enc_fh *fh = vq->priv_data;
685 struct solo_enc_dev *solo_enc = fh->enc;
686
687 vb->size = FRAME_BUF_SIZE;
688 if (vb->baddr != 0 && vb->bsize < vb->size)
689 return -EINVAL;
690
691 /* These properties only change when queue is idle */
692 vb->width = solo_enc->width;
693 vb->height = solo_enc->height;
694 vb->field = field;
695
696 if (vb->state == VIDEOBUF_NEEDS_INIT) {
697 int rc = videobuf_iolock(vq, vb, NULL);
698 if (rc < 0) {
699 videobuf_dma_contig_free(vq, vb);
700 vb->state = VIDEOBUF_NEEDS_INIT;
701 return rc;
702 }
703 }
704 vb->state = VIDEOBUF_PREPARED;
705
706 return 0;
707}
708
709static void solo_enc_buf_queue(struct videobuf_queue *vq,
710 struct videobuf_buffer *vb)
711{
712 struct solo_enc_fh *fh = vq->priv_data;
713
714 vb->state = VIDEOBUF_QUEUED;
715 list_add_tail(&vb->queue, &fh->vidq_active);
716 wake_up_interruptible(&fh->enc->thread_wait);
717}
718
719static void solo_enc_buf_release(struct videobuf_queue *vq,
720 struct videobuf_buffer *vb)
721{
722 videobuf_dma_contig_free(vq, vb);
723 vb->state = VIDEOBUF_NEEDS_INIT;
724}
725
726static struct videobuf_queue_ops solo_enc_video_qops = {
727 .buf_setup = solo_enc_buf_setup,
728 .buf_prepare = solo_enc_buf_prepare,
729 .buf_queue = solo_enc_buf_queue,
730 .buf_release = solo_enc_buf_release,
731};
732
733static unsigned int solo_enc_poll(struct file *file,
734 struct poll_table_struct *wait)
735{
736 struct solo_enc_fh *fh = file->private_data;
737
738 return videobuf_poll_stream(file, &fh->vidq, wait);
739}
740
741static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
742{
743 struct solo_enc_fh *fh = file->private_data;
744
745 return videobuf_mmap_mapper(&fh->vidq, vma);
746}
747
748static int solo_enc_open(struct file *file)
749{
750 struct solo_enc_dev *solo_enc = video_drvdata(file);
751 struct solo_enc_fh *fh;
752
753 if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
754 return -ENOMEM;
755
756 spin_lock(&solo_enc->lock);
757
758 fh->enc = solo_enc;
759 file->private_data = fh;
760 INIT_LIST_HEAD(&fh->vidq_active);
761 fh->fmt = V4L2_PIX_FMT_MPEG;
762 fh->type = SOLO_ENC_TYPE_STD;
763
764 videobuf_queue_dma_contig_init(&fh->vidq, &solo_enc_video_qops,
765 &solo_enc->solo_dev->pdev->dev,
766 &solo_enc->lock,
767 V4L2_BUF_TYPE_VIDEO_CAPTURE,
768 V4L2_FIELD_INTERLACED,
769 sizeof(struct videobuf_buffer), fh);
770
771 spin_unlock(&solo_enc->lock);
772
773 return 0;
774}
775
776static ssize_t solo_enc_read(struct file *file, char __user *data,
777 size_t count, loff_t *ppos)
778{
779 struct solo_enc_fh *fh = file->private_data;
780 struct solo_enc_dev *solo_enc = fh->enc;
781
782 /* Make sure the encoder is on */
783 if (!fh->enc_on) {
784 int ret;
785
786 spin_lock(&solo_enc->lock);
787 ret = solo_enc_on(fh);
788 spin_unlock(&solo_enc->lock);
789 if (ret)
790 return ret;
791 }
792
793 return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
794 file->f_flags & O_NONBLOCK);
795}
796
797static int solo_enc_release(struct file *file)
798{
799 struct solo_enc_fh *fh = file->private_data;
800
801 videobuf_stop(&fh->vidq);
802 videobuf_mmap_free(&fh->vidq);
803 solo_enc_off(fh);
804 kfree(fh);
805
806 return 0;
807}
808
809static int solo_enc_querycap(struct file *file, void *priv,
810 struct v4l2_capability *cap)
811{
812 struct solo_enc_fh *fh = priv;
813 struct solo_enc_dev *solo_enc = fh->enc;
814 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
815
816 strcpy(cap->driver, SOLO6010_NAME);
817 snprintf(cap->card, sizeof(cap->card), "Softlogic 6010 Enc %d",
818 solo_enc->ch);
819 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
820 pci_name(solo_dev->pdev));
821 cap->version = SOLO6010_VER_NUM;
822 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
823 V4L2_CAP_READWRITE |
824 V4L2_CAP_STREAMING;
825 return 0;
826}
827
828static int solo_enc_enum_input(struct file *file, void *priv,
829 struct v4l2_input *input)
830{
831 struct solo_enc_fh *fh = priv;
832 struct solo_enc_dev *solo_enc = fh->enc;
833 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
834
835 if (input->index)
836 return -EINVAL;
837
838 snprintf(input->name, sizeof(input->name), "Encoder %d",
839 solo_enc->ch + 1);
840 input->type = V4L2_INPUT_TYPE_CAMERA;
841
842 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
843 input->std = V4L2_STD_NTSC_M;
844 else
845 input->std = V4L2_STD_PAL_M;
846
847 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
848 input->status = V4L2_IN_ST_NO_SIGNAL;
849
850 return 0;
851}
852
853static int solo_enc_set_input(struct file *file, void *priv, unsigned int index)
854{
855 if (index)
856 return -EINVAL;
857
858 return 0;
859}
860
861static int solo_enc_get_input(struct file *file, void *priv,
862 unsigned int *index)
863{
864 *index = 0;
865
866 return 0;
867}
868
869static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
870 struct v4l2_fmtdesc *f)
871{
872 switch (f->index) {
873 case 0:
874 f->pixelformat = V4L2_PIX_FMT_MPEG;
875 strcpy(f->description, "MPEG-4 AVC");
876 break;
877 case 1:
878 f->pixelformat = V4L2_PIX_FMT_MJPEG;
879 strcpy(f->description, "MJPEG");
880 break;
881 default:
882 return -EINVAL;
883 }
884
885 f->flags = V4L2_FMT_FLAG_COMPRESSED;
886
887 return 0;
888}
889
890static int solo_enc_try_fmt_cap(struct file *file, void *priv,
891 struct v4l2_format *f)
892{
893 struct solo_enc_fh *fh = priv;
894 struct solo_enc_dev *solo_enc = fh->enc;
895 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
896 struct v4l2_pix_format *pix = &f->fmt.pix;
897
898 if (pix->pixelformat != V4L2_PIX_FMT_MPEG &&
899 pix->pixelformat != V4L2_PIX_FMT_MJPEG)
900 return -EINVAL;
901
902 /* We cannot change width/height in mid read */
903 if (atomic_read(&solo_enc->readers) > 0) {
904 if (pix->width != solo_enc->width ||
905 pix->height != solo_enc->height)
906 return -EBUSY;
907 } else if (!(pix->width == solo_dev->video_hsize &&
908 pix->height == solo_dev->video_vsize << 1) &&
909 !(pix->width == solo_dev->video_hsize >> 1 &&
910 pix->height == solo_dev->video_vsize)) {
911 /* Default to CIF 1/2 size */
912 pix->width = solo_dev->video_hsize >> 1;
913 pix->height = solo_dev->video_vsize;
914 }
915
916 if (pix->field == V4L2_FIELD_ANY)
917 pix->field = V4L2_FIELD_INTERLACED;
918 else if (pix->field != V4L2_FIELD_INTERLACED) {
919 pix->field = V4L2_FIELD_INTERLACED;
920 }
921
922 /* Just set these */
923 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
924 pix->sizeimage = FRAME_BUF_SIZE;
925
926 return 0;
927}
928
929static int solo_enc_set_fmt_cap(struct file *file, void *priv,
930 struct v4l2_format *f)
931{
932 struct solo_enc_fh *fh = priv;
933 struct solo_enc_dev *solo_enc = fh->enc;
934 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
935 struct v4l2_pix_format *pix = &f->fmt.pix;
936 int ret;
937
938 spin_lock(&solo_enc->lock);
939
940 if ((ret = solo_enc_try_fmt_cap(file, priv, f))) {
941 spin_unlock(&solo_enc->lock);
942 return ret;
943 }
944
945 if (pix->width == solo_dev->video_hsize)
946 solo_enc->mode = SOLO_ENC_MODE_D1;
947 else
948 solo_enc->mode = SOLO_ENC_MODE_CIF;
949
950 /* This does not change the encoder at all */
951 fh->fmt = pix->pixelformat;
952
953 if (pix->priv)
954 fh->type = SOLO_ENC_TYPE_EXT;
955 ret = solo_enc_on(fh);
956
957 spin_unlock(&solo_enc->lock);
958
959 return ret;
960}
961
962static int solo_enc_get_fmt_cap(struct file *file, void *priv,
963 struct v4l2_format *f)
964{
965 struct solo_enc_fh *fh = priv;
966 struct solo_enc_dev *solo_enc = fh->enc;
967 struct v4l2_pix_format *pix = &f->fmt.pix;
968
969 pix->width = solo_enc->width;
970 pix->height = solo_enc->height;
971 pix->pixelformat = fh->fmt;
972 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
973 V4L2_FIELD_NONE;
974 pix->sizeimage = FRAME_BUF_SIZE;
975 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
976
977 return 0;
978}
979
980static int solo_enc_reqbufs(struct file *file, void *priv,
981 struct v4l2_requestbuffers *req)
982{
983 struct solo_enc_fh *fh = priv;
984
985 return videobuf_reqbufs(&fh->vidq, req);
986}
987
988static int solo_enc_querybuf(struct file *file, void *priv,
989 struct v4l2_buffer *buf)
990{
991 struct solo_enc_fh *fh = priv;
992
993 return videobuf_querybuf(&fh->vidq, buf);
994}
995
996static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
997{
998 struct solo_enc_fh *fh = priv;
999
1000 return videobuf_qbuf(&fh->vidq, buf);
1001}
1002
1003static int solo_enc_dqbuf(struct file *file, void *priv,
1004 struct v4l2_buffer *buf)
1005{
1006 struct solo_enc_fh *fh = priv;
1007 struct solo_enc_dev *solo_enc = fh->enc;
1008 int ret;
1009
1010 /* Make sure the encoder is on */
1011 if (!fh->enc_on) {
1012 spin_lock(&solo_enc->lock);
1013 ret = solo_enc_on(fh);
1014 spin_unlock(&solo_enc->lock);
1015 if (ret)
1016 return ret;
1017 }
1018
1019 ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
1020 if (ret)
1021 return ret;
1022
1023 /* Signal motion detection */
1024 if (solo_is_motion_on(solo_enc)) {
1025 buf->flags |= V4L2_BUF_FLAG_MOTION_ON;
1026 if (solo_enc->motion_detected) {
1027 buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
1028 solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
1029 1 << solo_enc->ch);
1030 solo_enc->motion_detected = 0;
1031 }
1032 }
1033
1034 /* Check for key frame on mpeg data */
1035 if (fh->fmt == V4L2_PIX_FMT_MPEG) {
1036 struct videobuf_buffer *vb = fh->vidq.bufs[buf->index];
1037 u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
1038 if (p[3] == 0x00)
1039 buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
1040 else
1041 buf->flags |= V4L2_BUF_FLAG_PFRAME;
1042 }
1043
1044 return 0;
1045}
1046
1047static int solo_enc_streamon(struct file *file, void *priv,
1048 enum v4l2_buf_type i)
1049{
1050 struct solo_enc_fh *fh = priv;
1051
1052 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1053 return -EINVAL;
1054
1055 return videobuf_streamon(&fh->vidq);
1056}
1057
1058static int solo_enc_streamoff(struct file *file, void *priv,
1059 enum v4l2_buf_type i)
1060{
1061 struct solo_enc_fh *fh = priv;
1062
1063 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1064 return -EINVAL;
1065
1066 return videobuf_streamoff(&fh->vidq);
1067}
1068
1069static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i)
1070{
1071 return 0;
1072}
1073
1074static int solo_enum_framesizes(struct file *file, void *priv,
1075 struct v4l2_frmsizeenum *fsize)
1076{
1077 struct solo_enc_fh *fh = priv;
1078 struct solo6010_dev *solo_dev = fh->enc->solo_dev;
1079
1080 if (fsize->pixel_format != V4L2_PIX_FMT_MPEG)
1081 return -EINVAL;
1082
1083 switch (fsize->index) {
1084 case 0:
1085 fsize->discrete.width = solo_dev->video_hsize >> 1;
1086 fsize->discrete.height = solo_dev->video_vsize;
1087 break;
1088 case 1:
1089 fsize->discrete.width = solo_dev->video_hsize;
1090 fsize->discrete.height = solo_dev->video_vsize << 1;
1091 break;
1092 default:
1093 return -EINVAL;
1094 }
1095
1096 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1097
1098 return 0;
1099}
1100
1101static int solo_enum_frameintervals(struct file *file, void *priv,
1102 struct v4l2_frmivalenum *fintv)
1103{
1104 struct solo_enc_fh *fh = priv;
1105 struct solo6010_dev *solo_dev = fh->enc->solo_dev;
1106
1107 if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index)
1108 return -EINVAL;
1109
1110 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1111
1112 fintv->stepwise.min.numerator = solo_dev->fps;
1113 fintv->stepwise.min.denominator = 1;
1114
1115 fintv->stepwise.max.numerator = solo_dev->fps;
1116 fintv->stepwise.max.denominator = 15;
1117
1118 fintv->stepwise.step.numerator = 1;
1119 fintv->stepwise.step.denominator = 1;
1120
1121 return 0;
1122}
1123
1124static int solo_g_parm(struct file *file, void *priv,
1125 struct v4l2_streamparm *sp)
1126{
1127 struct solo_enc_fh *fh = priv;
1128 struct solo_enc_dev *solo_enc = fh->enc;
1129 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
1130 struct v4l2_captureparm *cp = &sp->parm.capture;
1131
1132 cp->capability = V4L2_CAP_TIMEPERFRAME;
1133 cp->timeperframe.numerator = solo_enc->interval;
1134 cp->timeperframe.denominator = solo_dev->fps;
1135 cp->capturemode = 0;
1136 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1137 cp->readbuffers = 2;
1138
1139 return 0;
1140}
1141
1142static int solo_s_parm(struct file *file, void *priv,
1143 struct v4l2_streamparm *sp)
1144{
1145 struct solo_enc_fh *fh = priv;
1146 struct solo_enc_dev *solo_enc = fh->enc;
1147 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
1148 struct v4l2_captureparm *cp = &sp->parm.capture;
1149
1150 spin_lock(&solo_enc->lock);
1151
1152 if (atomic_read(&solo_enc->readers) > 0) {
1153 spin_unlock(&solo_enc->lock);
1154 return -EBUSY;
1155 }
1156
1157 if ((cp->timeperframe.numerator == 0) ||
1158 (cp->timeperframe.denominator == 0)) {
1159 /* reset framerate */
1160 cp->timeperframe.numerator = 1;
1161 cp->timeperframe.denominator = solo_dev->fps;
1162 }
1163
1164 if (cp->timeperframe.denominator != solo_dev->fps)
1165 cp->timeperframe.denominator = solo_dev->fps;
1166
1167 if (cp->timeperframe.numerator > 15)
1168 cp->timeperframe.numerator = 15;
1169
1170 solo_enc->interval = cp->timeperframe.numerator;
1171
1172 cp->capability = V4L2_CAP_TIMEPERFRAME;
1173
1174 solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1);
1175 solo_update_mode(solo_enc);
1176
1177 spin_unlock(&solo_enc->lock);
1178
1179 return 0;
1180}
1181
1182static int solo_queryctrl(struct file *file, void *priv,
1183 struct v4l2_queryctrl *qc)
1184{
1185 struct solo_enc_fh *fh = priv;
1186 struct solo_enc_dev *solo_enc = fh->enc;
1187 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
1188
1189 qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
1190 if (!qc->id)
1191 return -EINVAL;
1192
1193 switch (qc->id) {
1194 case V4L2_CID_BRIGHTNESS:
1195 case V4L2_CID_CONTRAST:
1196 case V4L2_CID_SATURATION:
1197 case V4L2_CID_HUE:
1198 return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80);
1199 case V4L2_CID_SHARPNESS:
1200 return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00);
1201 case V4L2_CID_MPEG_VIDEO_ENCODING:
1202 return v4l2_ctrl_query_fill(
1203 qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
1204 V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
1205 V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
1206 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1207 return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps);
1208#ifdef PRIVATE_CIDS
1209 case V4L2_CID_MOTION_THRESHOLD:
1210 qc->flags |= V4L2_CTRL_FLAG_SLIDER;
1211 qc->type = V4L2_CTRL_TYPE_INTEGER;
1212 qc->minimum = 0;
1213 qc->maximum = 0xffff;
1214 qc->step = 1;
1215 qc->default_value = SOLO_DEF_MOT_THRESH;
1216 strlcpy(qc->name, "Motion Detection Threshold",
1217 sizeof(qc->name));
1218 return 0;
1219 case V4L2_CID_MOTION_ENABLE:
1220 qc->type = V4L2_CTRL_TYPE_BOOLEAN;
1221 qc->minimum = 0;
1222 qc->maximum = qc->step = 1;
1223 qc->default_value = 0;
1224 strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name));
1225 return 0;
1226#else
1227 case V4L2_CID_MOTION_THRESHOLD:
1228 return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1,
1229 SOLO_DEF_MOT_THRESH);
1230 case V4L2_CID_MOTION_ENABLE:
1231 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
1232#endif
1233 case V4L2_CID_RDS_TX_RADIO_TEXT:
1234 qc->type = V4L2_CTRL_TYPE_STRING;
1235 qc->minimum = 0;
1236 qc->maximum = OSD_TEXT_MAX;
1237 qc->step = 1;
1238 qc->default_value = 0;
1239 strlcpy(qc->name, "OSD Text", sizeof(qc->name));
1240 return 0;
1241 }
1242
1243 return -EINVAL;
1244}
1245
1246static int solo_querymenu(struct file *file, void *priv,
1247 struct v4l2_querymenu *qmenu)
1248{
1249 struct v4l2_queryctrl qctrl;
1250 int err;
1251
1252 qctrl.id = qmenu->id;
1253 if ((err = solo_queryctrl(file, priv, &qctrl)))
1254 return err;
1255
1256 return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
1257}
1258
1259static int solo_g_ctrl(struct file *file, void *priv,
1260 struct v4l2_control *ctrl)
1261{
1262 struct solo_enc_fh *fh = priv;
1263 struct solo_enc_dev *solo_enc = fh->enc;
1264 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
1265
1266 switch (ctrl->id) {
1267 case V4L2_CID_BRIGHTNESS:
1268 case V4L2_CID_CONTRAST:
1269 case V4L2_CID_SATURATION:
1270 case V4L2_CID_HUE:
1271 case V4L2_CID_SHARPNESS:
1272 return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
1273 &ctrl->value);
1274 case V4L2_CID_MPEG_VIDEO_ENCODING:
1275 ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
1276 break;
1277 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1278 ctrl->value = solo_enc->gop;
1279 break;
1280 case V4L2_CID_MOTION_THRESHOLD:
1281 ctrl->value = solo_enc->motion_thresh;
1282 break;
1283 case V4L2_CID_MOTION_ENABLE:
1284 ctrl->value = solo_is_motion_on(solo_enc);
1285 break;
1286 default:
1287 return -EINVAL;
1288 }
1289
1290 return 0;
1291}
1292
1293static int solo_s_ctrl(struct file *file, void *priv,
1294 struct v4l2_control *ctrl)
1295{
1296 struct solo_enc_fh *fh = priv;
1297 struct solo_enc_dev *solo_enc = fh->enc;
1298 struct solo6010_dev *solo_dev = solo_enc->solo_dev;
1299
1300 switch (ctrl->id) {
1301 case V4L2_CID_BRIGHTNESS:
1302 case V4L2_CID_CONTRAST:
1303 case V4L2_CID_SATURATION:
1304 case V4L2_CID_HUE:
1305 case V4L2_CID_SHARPNESS:
1306 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
1307 ctrl->value);
1308 case V4L2_CID_MPEG_VIDEO_ENCODING:
1309 if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
1310 return -ERANGE;
1311 break;
1312 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1313 if (ctrl->value < 1 || ctrl->value > 255)
1314 return -ERANGE;
1315 solo_enc->gop = ctrl->value;
1316 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch),
1317 solo_enc->gop);
1318 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch),
1319 solo_enc->gop);
1320 break;
1321 case V4L2_CID_MOTION_THRESHOLD:
1322 /* TODO accept value on lower 16-bits and use high
1323 * 16-bits to assign the value to a specific block */
1324 if (ctrl->value < 0 || ctrl->value > 0xffff)
1325 return -ERANGE;
1326 solo_enc->motion_thresh = ctrl->value;
1327 solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value);
1328 break;
1329 case V4L2_CID_MOTION_ENABLE:
1330 solo_motion_toggle(solo_enc, ctrl->value);
1331 break;
1332 default:
1333 return -EINVAL;
1334 }
1335
1336 return 0;
1337}
1338
1339static int solo_s_ext_ctrls(struct file *file, void *priv,
1340 struct v4l2_ext_controls *ctrls)
1341{
1342 struct solo_enc_fh *fh = priv;
1343 struct solo_enc_dev *solo_enc = fh->enc;
1344 int i;
1345
1346 for (i = 0; i < ctrls->count; i++) {
1347 struct v4l2_ext_control *ctrl = (ctrls->controls + i);
1348 int err;
1349
1350 switch (ctrl->id) {
1351 case V4L2_CID_RDS_TX_RADIO_TEXT:
1352 if (ctrl->size - 1 > OSD_TEXT_MAX)
1353 err = -ERANGE;
1354 else {
1355 err = copy_from_user(solo_enc->osd_text,
1356 ctrl->string,
1357 OSD_TEXT_MAX);
1358 solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
1359 if (!err)
1360 err = solo_osd_print(solo_enc);
1361 }
1362 break;
1363 default:
1364 err = -EINVAL;
1365 }
1366
1367 if (err < 0) {
1368 ctrls->error_idx = i;
1369 return err;
1370 }
1371 }
1372
1373 return 0;
1374}
1375
1376static int solo_g_ext_ctrls(struct file *file, void *priv,
1377 struct v4l2_ext_controls *ctrls)
1378{
1379 struct solo_enc_fh *fh = priv;
1380 struct solo_enc_dev *solo_enc = fh->enc;
1381 int i;
1382
1383 for (i = 0; i < ctrls->count; i++) {
1384 struct v4l2_ext_control *ctrl = (ctrls->controls + i);
1385 int err;
1386
1387 switch (ctrl->id) {
1388 case V4L2_CID_RDS_TX_RADIO_TEXT:
1389 if (ctrl->size < OSD_TEXT_MAX) {
1390 ctrl->size = OSD_TEXT_MAX;
1391 err = -ENOSPC;
1392 } else {
1393 err = copy_to_user(ctrl->string,
1394 solo_enc->osd_text,
1395 OSD_TEXT_MAX);
1396 }
1397 break;
1398 default:
1399 err = -EINVAL;
1400 }
1401
1402 if (err < 0) {
1403 ctrls->error_idx = i;
1404 return err;
1405 }
1406 }
1407
1408 return 0;
1409}
1410
1411static const struct v4l2_file_operations solo_enc_fops = {
1412 .owner = THIS_MODULE,
1413 .open = solo_enc_open,
1414 .release = solo_enc_release,
1415 .read = solo_enc_read,
1416 .poll = solo_enc_poll,
1417 .mmap = solo_enc_mmap,
1418 .ioctl = video_ioctl2,
1419};
1420
1421static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1422 .vidioc_querycap = solo_enc_querycap,
1423 .vidioc_s_std = solo_enc_s_std,
1424 /* Input callbacks */
1425 .vidioc_enum_input = solo_enc_enum_input,
1426 .vidioc_s_input = solo_enc_set_input,
1427 .vidioc_g_input = solo_enc_get_input,
1428 /* Video capture format callbacks */
1429 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1430 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1431 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1432 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1433 /* Streaming I/O */
1434 .vidioc_reqbufs = solo_enc_reqbufs,
1435 .vidioc_querybuf = solo_enc_querybuf,
1436 .vidioc_qbuf = solo_enc_qbuf,
1437 .vidioc_dqbuf = solo_enc_dqbuf,
1438 .vidioc_streamon = solo_enc_streamon,
1439 .vidioc_streamoff = solo_enc_streamoff,
1440 /* Frame size and interval */
1441 .vidioc_enum_framesizes = solo_enum_framesizes,
1442 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1443 /* Video capture parameters */
1444 .vidioc_s_parm = solo_s_parm,
1445 .vidioc_g_parm = solo_g_parm,
1446 /* Controls */
1447 .vidioc_queryctrl = solo_queryctrl,
1448 .vidioc_querymenu = solo_querymenu,
1449 .vidioc_g_ctrl = solo_g_ctrl,
1450 .vidioc_s_ctrl = solo_s_ctrl,
1451 .vidioc_g_ext_ctrls = solo_g_ext_ctrls,
1452 .vidioc_s_ext_ctrls = solo_s_ext_ctrls,
1453};
1454
1455static struct video_device solo_enc_template = {
1456 .name = SOLO6010_NAME,
1457 .fops = &solo_enc_fops,
1458 .ioctl_ops = &solo_enc_ioctl_ops,
1459 .minor = -1,
1460 .release = video_device_release,
1461
1462 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
1463 .current_norm = V4L2_STD_NTSC_M,
1464};
1465
1466static struct solo_enc_dev *solo_enc_alloc(struct solo6010_dev *solo_dev, u8 ch)
1467{
1468 struct solo_enc_dev *solo_enc;
1469 int ret;
1470
1471 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1472 if (!solo_enc)
1473 return ERR_PTR(-ENOMEM);
1474
1475 solo_enc->vfd = video_device_alloc();
1476 if (!solo_enc->vfd) {
1477 kfree(solo_enc);
1478 return ERR_PTR(-ENOMEM);
1479 }
1480
1481 solo_enc->solo_dev = solo_dev;
1482 solo_enc->ch = ch;
1483
1484 *solo_enc->vfd = solo_enc_template;
1485 solo_enc->vfd->parent = &solo_dev->pdev->dev;
1486 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER,
1487 video_nr);
1488 if (ret < 0) {
1489 video_device_release(solo_enc->vfd);
1490 kfree(solo_enc);
1491 return ERR_PTR(ret);
1492 }
1493
1494 video_set_drvdata(solo_enc->vfd, solo_enc);
1495
1496 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1497 "%s-enc (%i/%i)", SOLO6010_NAME, solo_dev->vfd->num,
1498 solo_enc->vfd->num);
1499
1500 if (video_nr >= 0)
1501 video_nr++;
1502
1503 spin_lock_init(&solo_enc->lock);
1504 init_waitqueue_head(&solo_enc->thread_wait);
1505 atomic_set(&solo_enc->readers, 0);
1506
1507 solo_enc->qp = SOLO_DEFAULT_QP;
1508 solo_enc->gop = solo_dev->fps;
1509 solo_enc->interval = 1;
1510 solo_enc->mode = SOLO_ENC_MODE_CIF;
1511 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
1512
1513 spin_lock(&solo_enc->lock);
1514 solo_update_mode(solo_enc);
1515 spin_unlock(&solo_enc->lock);
1516
1517 return solo_enc;
1518}
1519
1520static void solo_enc_free(struct solo_enc_dev *solo_enc)
1521{
1522 if (solo_enc == NULL)
1523 return;
1524
1525 video_unregister_device(solo_enc->vfd);
1526 kfree(solo_enc);
1527}
1528
1529int solo_enc_v4l2_init(struct solo6010_dev *solo_dev)
1530{
1531 int i;
1532
1533 for (i = 0; i < solo_dev->nr_chans; i++) {
1534 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i);
1535 if (IS_ERR(solo_dev->v4l2_enc[i]))
1536 break;
1537 }
1538
1539 if (i != solo_dev->nr_chans) {
1540 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
1541 while (i--)
1542 solo_enc_free(solo_dev->v4l2_enc[i]);
1543 return ret;
1544 }
1545
1546 /* D1@MAX-FPS * 4 */
1547 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1548
1549 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1550 solo_dev->v4l2_enc[0]->vfd->num,
1551 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1552
1553 return 0;
1554}
1555
1556void solo_enc_v4l2_exit(struct solo6010_dev *solo_dev)
1557{
1558 int i;
1559
1560 solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
1561
1562 for (i = 0; i < solo_dev->nr_chans; i++)
1563 solo_enc_free(solo_dev->v4l2_enc[i]);
1564}
diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c
new file mode 100644
index 00000000000..9537cc6ee3b
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-v4l2.c
@@ -0,0 +1,859 @@
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
25#include <media/v4l2-ioctl.h>
26#include <media/v4l2-common.h>
27#include <media/videobuf-dma-contig.h>
28
29#include "solo6010.h"
30#include "solo6010-tw28.h"
31
32#define SOLO_HW_BPL 2048
33#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
34#define SOLO_DISP_BUF_SIZE (64 * 1024) // 64k
35
36/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
37#define solo_vlines(__solo) (__solo->video_vsize * 2)
38#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
39 solo_vlines(__solo))
40#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
41
42#define MIN_VID_BUFFERS 4
43
44/* Simple file handle */
45struct solo_filehandle {
46 struct solo6010_dev *solo_dev;
47 struct videobuf_queue vidq;
48 struct task_struct *kthread;
49 spinlock_t slock;
50 int old_write;
51 struct list_head vidq_active;
52};
53
54unsigned video_nr = -1;
55module_param(video_nr, uint, 0644);
56MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
57
58static void erase_on(struct solo6010_dev *solo_dev)
59{
60 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
61 solo_dev->erasing = 1;
62 solo_dev->frame_blank = 0;
63}
64
65static int erase_off(struct solo6010_dev *solo_dev)
66{
67 if (!solo_dev->erasing)
68 return 0;
69
70 /* First time around, assert erase off */
71 if (!solo_dev->frame_blank)
72 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
73 /* Keep the erasing flag on for 8 frames minimum */
74 if (solo_dev->frame_blank++ >= 8)
75 solo_dev->erasing = 0;
76
77 return 1;
78}
79
80void solo_video_in_isr(struct solo6010_dev *solo_dev)
81{
82 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
83 wake_up_interruptible(&solo_dev->disp_thread_wait);
84}
85
86static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch,
87 int sx, int sy, int ex, int ey, int scale)
88{
89 if (ch >= solo_dev->nr_chans)
90 return;
91
92 /* Here, we just keep window/channel the same */
93 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
94 SOLO_VI_WIN_CHANNEL(ch) |
95 SOLO_VI_WIN_SX(sx) |
96 SOLO_VI_WIN_EX(ex) |
97 SOLO_VI_WIN_SCALE(scale));
98
99 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
100 SOLO_VI_WIN_SY(sy) |
101 SOLO_VI_WIN_EY(ey));
102}
103
104static int solo_v4l2_ch_ext_4up(struct solo6010_dev *solo_dev, u8 idx, int on)
105{
106 u8 ch = idx * 4;
107
108 if (ch >= solo_dev->nr_chans)
109 return -EINVAL;
110
111 if (!on) {
112 u8 i;
113 for (i = ch; i < ch + 4; i++)
114 solo_win_setup(solo_dev, i, solo_dev->video_hsize,
115 solo_vlines(solo_dev),
116 solo_dev->video_hsize,
117 solo_vlines(solo_dev), 0);
118 return 0;
119 }
120
121 /* Row 1 */
122 solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
123 solo_vlines(solo_dev) / 2, 3);
124 solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
125 solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
126 /* Row 2 */
127 solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
128 solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
129 solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
130 solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
131 solo_vlines(solo_dev), 3);
132
133 return 0;
134}
135
136static int solo_v4l2_ch_ext_16up(struct solo6010_dev *solo_dev, int on)
137{
138 int sy, ysize, hsize, i;
139
140 if (!on) {
141 for (i = 0; i < 16; i++)
142 solo_win_setup(solo_dev, i, solo_dev->video_hsize,
143 solo_vlines(solo_dev),
144 solo_dev->video_hsize,
145 solo_vlines(solo_dev), 0);
146 return 0;
147 }
148
149 ysize = solo_vlines(solo_dev) / 4;
150 hsize = solo_dev->video_hsize / 4;
151
152 for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
153 solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
154 sy + ysize, 5);
155 solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
156 hsize * 2, sy + ysize, 5);
157 solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
158 hsize * 3, sy + ysize, 5);
159 solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
160 solo_dev->video_hsize, sy + ysize, 5);
161 }
162
163 return 0;
164}
165
166static int solo_v4l2_ch(struct solo6010_dev *solo_dev, u8 ch, int on)
167{
168 u8 ext_ch;
169
170 if (ch < solo_dev->nr_chans) {
171 solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
172 on ? 0 : solo_vlines(solo_dev),
173 solo_dev->video_hsize, solo_vlines(solo_dev),
174 on ? 1 : 0);
175 return 0;
176 }
177
178 if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
179 return -EINVAL;
180
181 ext_ch = ch - solo_dev->nr_chans;
182
183 /* 4up's first */
184 if (ext_ch < 4)
185 return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
186
187 /* Remaining case is 16up for 16-port */
188 return solo_v4l2_ch_ext_16up(solo_dev, on);
189}
190
191static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch)
192{
193 if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
194 return -EINVAL;
195
196 erase_on(solo_dev);
197
198 solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
199 solo_v4l2_ch(solo_dev, ch, 1);
200
201 solo_dev->cur_disp_ch = ch;
202
203 return 0;
204}
205
206static void solo_fillbuf(struct solo_filehandle *fh,
207 struct videobuf_buffer *vb)
208{
209 struct solo6010_dev *solo_dev = fh->solo_dev;
210 dma_addr_t vbuf;
211 unsigned int fdma_addr;
212 int frame_size;
213 int error = 1;
214 int i;
215
216 if (!(vbuf = videobuf_to_dma_contig(vb)))
217 goto finish_buf;
218
219 if (erase_off(solo_dev)) {
220 void *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
221 int image_size = solo_image_size(solo_dev);
222 for (i = 0; i < image_size; i += 2) {
223 ((u8 *)p)[i] = 0x80;
224 ((u8 *)p)[i + 1] = 0x00;
225 }
226 error = 0;
227 goto finish_buf;
228 }
229
230 frame_size = SOLO_HW_BPL * solo_vlines(solo_dev);
231 fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * frame_size);
232
233 for (i = 0; i < frame_size / SOLO_DISP_BUF_SIZE; i++) {
234 int j;
235 for (j = 0; j < (SOLO_DISP_BUF_SIZE / SOLO_HW_BPL); j++) {
236 if (solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_DISP, 0,
237 vbuf, fdma_addr + (j * SOLO_HW_BPL),
238 solo_bytesperline(solo_dev)))
239 goto finish_buf;
240 vbuf += solo_bytesperline(solo_dev);
241 }
242 fdma_addr += SOLO_DISP_BUF_SIZE;
243 }
244 error = 0;
245
246finish_buf:
247 if (error) {
248 vb->state = VIDEOBUF_ERROR;
249 } else {
250 vb->state = VIDEOBUF_DONE;
251 vb->field_count++;
252 do_gettimeofday(&vb->ts);
253 }
254
255 wake_up(&vb->done);
256
257 return;
258}
259
260static void solo_thread_try(struct solo_filehandle *fh)
261{
262 struct videobuf_buffer *vb;
263 unsigned int cur_write;
264
265 for (;;) {
266 spin_lock(&fh->slock);
267
268 if (list_empty(&fh->vidq_active))
269 break;
270
271 vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
272 queue);
273
274 if (!waitqueue_active(&vb->done))
275 break;
276
277 cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
278 SOLO_VI_STATUS0));
279 if (cur_write == fh->old_write)
280 break;
281
282 fh->old_write = cur_write;
283 list_del(&vb->queue);
284
285 spin_unlock(&fh->slock);
286
287 solo_fillbuf(fh, vb);
288 }
289
290 assert_spin_locked(&fh->slock);
291 spin_unlock(&fh->slock);
292}
293
294static int solo_thread(void *data)
295{
296 struct solo_filehandle *fh = data;
297 struct solo6010_dev *solo_dev = fh->solo_dev;
298 DECLARE_WAITQUEUE(wait, current);
299
300 set_freezable();
301 add_wait_queue(&solo_dev->disp_thread_wait, &wait);
302
303 for (;;) {
304 long timeout = schedule_timeout_interruptible(HZ);
305 if (timeout == -ERESTARTSYS || kthread_should_stop())
306 break;
307 solo_thread_try(fh);
308 try_to_freeze();
309 }
310
311 remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
312
313 return 0;
314}
315
316static int solo_start_thread(struct solo_filehandle *fh)
317{
318 fh->kthread = kthread_run(solo_thread, fh, SOLO6010_NAME "_disp");
319
320 if (IS_ERR(fh->kthread))
321 return PTR_ERR(fh->kthread);
322
323 return 0;
324}
325
326static void solo_stop_thread(struct solo_filehandle *fh)
327{
328 if (fh->kthread) {
329 kthread_stop(fh->kthread);
330 fh->kthread = NULL;
331 }
332}
333
334static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
335 unsigned int *size)
336{
337 struct solo_filehandle *fh = vq->priv_data;
338 struct solo6010_dev *solo_dev = fh->solo_dev;
339
340 *size = solo_image_size(solo_dev);
341
342 if (*count < MIN_VID_BUFFERS)
343 *count = MIN_VID_BUFFERS;
344
345 return 0;
346}
347
348static int solo_buf_prepare(struct videobuf_queue *vq,
349 struct videobuf_buffer *vb, enum v4l2_field field)
350{
351 struct solo_filehandle *fh = vq->priv_data;
352 struct solo6010_dev *solo_dev = fh->solo_dev;
353
354 vb->size = solo_image_size(solo_dev);
355 if (vb->baddr != 0 && vb->bsize < vb->size)
356 return -EINVAL;
357
358 /* XXX: These properties only change when queue is idle */
359 vb->width = solo_dev->video_hsize;
360 vb->height = solo_vlines(solo_dev);
361 vb->bytesperline = solo_bytesperline(solo_dev);
362 vb->field = field;
363
364 if (vb->state == VIDEOBUF_NEEDS_INIT) {
365 int rc = videobuf_iolock(vq, vb, NULL);
366 if (rc < 0) {
367 videobuf_dma_contig_free(vq, vb);
368 vb->state = VIDEOBUF_NEEDS_INIT;
369 return rc;
370 }
371 }
372 vb->state = VIDEOBUF_PREPARED;
373
374 return 0;
375}
376
377static void solo_buf_queue(struct videobuf_queue *vq,
378 struct videobuf_buffer *vb)
379{
380 struct solo_filehandle *fh = vq->priv_data;
381 struct solo6010_dev *solo_dev = fh->solo_dev;
382
383 vb->state = VIDEOBUF_QUEUED;
384 list_add_tail(&vb->queue, &fh->vidq_active);
385 wake_up_interruptible(&solo_dev->disp_thread_wait);
386}
387
388static void solo_buf_release(struct videobuf_queue *vq,
389 struct videobuf_buffer *vb)
390{
391 videobuf_dma_contig_free(vq, vb);
392 vb->state = VIDEOBUF_NEEDS_INIT;
393}
394
395static struct videobuf_queue_ops solo_video_qops = {
396 .buf_setup = solo_buf_setup,
397 .buf_prepare = solo_buf_prepare,
398 .buf_queue = solo_buf_queue,
399 .buf_release = solo_buf_release,
400};
401
402static unsigned int solo_v4l2_poll(struct file *file,
403 struct poll_table_struct *wait)
404{
405 struct solo_filehandle *fh = file->private_data;
406
407 return videobuf_poll_stream(file, &fh->vidq, wait);
408}
409
410static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
411{
412 struct solo_filehandle *fh = file->private_data;
413
414 return videobuf_mmap_mapper(&fh->vidq, vma);
415}
416
417static int solo_v4l2_open(struct file *file)
418{
419 struct solo6010_dev *solo_dev = video_drvdata(file);
420 struct solo_filehandle *fh;
421 int ret;
422
423 if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
424 return -ENOMEM;
425
426 spin_lock_init(&fh->slock);
427 INIT_LIST_HEAD(&fh->vidq_active);
428 fh->solo_dev = solo_dev;
429 file->private_data = fh;
430
431 if ((ret = solo_start_thread(fh))) {
432 kfree(fh);
433 return ret;
434 }
435
436 videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops,
437 &solo_dev->pdev->dev, &fh->slock,
438 V4L2_BUF_TYPE_VIDEO_CAPTURE,
439 SOLO_DISP_PIX_FIELD,
440 sizeof(struct videobuf_buffer), fh);
441
442 return 0;
443}
444
445static ssize_t solo_v4l2_read(struct file *file, char __user *data,
446 size_t count, loff_t *ppos)
447{
448 struct solo_filehandle *fh = file->private_data;
449
450 return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
451 file->f_flags & O_NONBLOCK);
452}
453
454static int solo_v4l2_release(struct file *file)
455{
456 struct solo_filehandle *fh = file->private_data;
457
458 videobuf_stop(&fh->vidq);
459 videobuf_mmap_free(&fh->vidq);
460 solo_stop_thread(fh);
461 kfree(fh);
462
463 return 0;
464}
465
466static int solo_querycap(struct file *file, void *priv,
467 struct v4l2_capability *cap)
468{
469 struct solo_filehandle *fh = priv;
470 struct solo6010_dev *solo_dev = fh->solo_dev;
471
472 strcpy(cap->driver, SOLO6010_NAME);
473 strcpy(cap->card, "Softlogic 6010");
474 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
475 pci_name(solo_dev->pdev));
476 cap->version = SOLO6010_VER_NUM;
477 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
478 V4L2_CAP_READWRITE |
479 V4L2_CAP_STREAMING;
480 return 0;
481}
482
483static int solo_enum_ext_input(struct solo6010_dev *solo_dev,
484 struct v4l2_input *input)
485{
486 static const char *dispnames_1[] = { "4UP" };
487 static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
488 static const char *dispnames_5[] = {
489 "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
490 };
491 const char **dispnames;
492
493 if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
494 return -EINVAL;
495
496 if (solo_dev->nr_ext == 5)
497 dispnames = dispnames_5;
498 else if (solo_dev->nr_ext == 2)
499 dispnames = dispnames_2;
500 else
501 dispnames = dispnames_1;
502
503 snprintf(input->name, sizeof(input->name), "Multi %s",
504 dispnames[input->index - solo_dev->nr_chans]);
505
506 return 0;
507}
508
509static int solo_enum_input(struct file *file, void *priv,
510 struct v4l2_input *input)
511{
512 struct solo_filehandle *fh = priv;
513 struct solo6010_dev *solo_dev = fh->solo_dev;
514
515 if (input->index >= solo_dev->nr_chans) {
516 int ret = solo_enum_ext_input(solo_dev, input);
517 if (ret < 0)
518 return ret;
519 } else {
520 snprintf(input->name, sizeof(input->name), "Camera %d",
521 input->index + 1);
522
523 /* We can only check this for normal inputs */
524 if (!tw28_get_video_status(solo_dev, input->index))
525 input->status = V4L2_IN_ST_NO_SIGNAL;
526 }
527
528 input->type = V4L2_INPUT_TYPE_CAMERA;
529
530 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
531 input->std = V4L2_STD_NTSC_M;
532 else
533 input->std = V4L2_STD_PAL_M;
534
535 return 0;
536}
537
538static int solo_set_input(struct file *file, void *priv, unsigned int index)
539{
540 struct solo_filehandle *fh = priv;
541
542 return solo_v4l2_set_ch(fh->solo_dev, index);
543}
544
545static int solo_get_input(struct file *file, void *priv, unsigned int *index)
546{
547 struct solo_filehandle *fh = priv;
548
549 *index = fh->solo_dev->cur_disp_ch;
550
551 return 0;
552}
553
554static int solo_enum_fmt_cap(struct file *file, void *priv,
555 struct v4l2_fmtdesc *f)
556{
557 if (f->index)
558 return -EINVAL;
559
560 f->pixelformat = V4L2_PIX_FMT_UYVY;
561 strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
562
563 return 0;
564}
565
566static int solo_try_fmt_cap(struct file *file, void *priv,
567 struct v4l2_format *f)
568{
569 struct solo_filehandle *fh = priv;
570 struct solo6010_dev *solo_dev = fh->solo_dev;
571 struct v4l2_pix_format *pix = &f->fmt.pix;
572 int image_size = solo_image_size(solo_dev);
573
574 /* Check supported sizes */
575 if (pix->width != solo_dev->video_hsize)
576 pix->width = solo_dev->video_hsize;
577 if (pix->height != solo_vlines(solo_dev))
578 pix->height = solo_vlines(solo_dev);
579 if (pix->sizeimage != image_size)
580 pix->sizeimage = image_size;
581
582 /* Check formats */
583 if (pix->field == V4L2_FIELD_ANY)
584 pix->field = SOLO_DISP_PIX_FIELD;
585
586 if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
587 pix->field != SOLO_DISP_PIX_FIELD ||
588 pix->colorspace != V4L2_COLORSPACE_SMPTE170M)
589 return -EINVAL;
590
591 return 0;
592}
593
594static int solo_set_fmt_cap(struct file *file, void *priv,
595 struct v4l2_format *f)
596{
597 struct solo_filehandle *fh = priv;
598
599 if (videobuf_queue_is_busy(&fh->vidq))
600 return -EBUSY;
601
602 /* For right now, if it doesn't match our running config,
603 * then fail */
604 return solo_try_fmt_cap(file, priv, f);
605}
606
607static int solo_get_fmt_cap(struct file *file, void *priv,
608 struct v4l2_format *f)
609{
610 struct solo_filehandle *fh = priv;
611 struct solo6010_dev *solo_dev = fh->solo_dev;
612 struct v4l2_pix_format *pix = &f->fmt.pix;
613
614 pix->width = solo_dev->video_hsize;
615 pix->height = solo_vlines(solo_dev);
616 pix->pixelformat = V4L2_PIX_FMT_UYVY;
617 pix->field = SOLO_DISP_PIX_FIELD;
618 pix->sizeimage = solo_image_size(solo_dev);
619 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
620 pix->bytesperline = solo_bytesperline(solo_dev);
621
622 return 0;
623}
624
625static int solo_reqbufs(struct file *file, void *priv,
626 struct v4l2_requestbuffers *req)
627{
628 struct solo_filehandle *fh = priv;
629
630 return videobuf_reqbufs(&fh->vidq, req);
631}
632
633static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
634{
635 struct solo_filehandle *fh = priv;
636
637 return videobuf_querybuf(&fh->vidq, buf);
638}
639
640static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
641{
642 struct solo_filehandle *fh = priv;
643
644 return videobuf_qbuf(&fh->vidq, buf);
645}
646
647static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
648{
649 struct solo_filehandle *fh = priv;
650
651 return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
652}
653
654static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
655{
656 struct solo_filehandle *fh = priv;
657
658 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
659 return -EINVAL;
660
661 return videobuf_streamon(&fh->vidq);
662}
663
664static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
665{
666 struct solo_filehandle *fh = priv;
667
668 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
669 return -EINVAL;
670
671 return videobuf_streamoff(&fh->vidq);
672}
673
674static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
675{
676 return 0;
677}
678
679static const u32 solo_motion_ctrls[] = {
680 V4L2_CID_MOTION_TRACE,
681 0
682};
683
684static const u32 *solo_ctrl_classes[] = {
685 solo_motion_ctrls,
686 NULL
687};
688
689static int solo_disp_queryctrl(struct file *file, void *priv,
690 struct v4l2_queryctrl *qc)
691{
692 qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
693 if (!qc->id)
694 return -EINVAL;
695
696 switch (qc->id) {
697#ifdef PRIVATE_CIDS
698 case V4L2_CID_MOTION_TRACE:
699 qc->type = V4L2_CTRL_TYPE_BOOLEAN;
700 qc->minimum = 0;
701 qc->maximum = qc->step = 1;
702 qc->default_value = 0;
703 strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
704 return 0;
705#else
706 case V4L2_CID_MOTION_TRACE:
707 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
708#endif
709 }
710 return -EINVAL;
711}
712
713static int solo_disp_g_ctrl(struct file *file, void *priv,
714 struct v4l2_control *ctrl)
715{
716 struct solo_filehandle *fh = priv;
717 struct solo6010_dev *solo_dev = fh->solo_dev;
718
719 switch (ctrl->id) {
720 case V4L2_CID_MOTION_TRACE:
721 ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
722 ? 1 : 0;
723 return 0;
724 }
725 return -EINVAL;
726}
727
728static int solo_disp_s_ctrl(struct file *file, void *priv,
729 struct v4l2_control *ctrl)
730{
731 struct solo_filehandle *fh = priv;
732 struct solo6010_dev *solo_dev = fh->solo_dev;
733
734 switch (ctrl->id) {
735 case V4L2_CID_MOTION_TRACE:
736 if (ctrl->value) {
737 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
738 SOLO_VI_MOTION_Y_ADD |
739 SOLO_VI_MOTION_Y_VALUE(0x20) |
740 SOLO_VI_MOTION_CB_VALUE(0x10) |
741 SOLO_VI_MOTION_CR_VALUE(0x10));
742 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
743 SOLO_VI_MOTION_CR_ADD |
744 SOLO_VI_MOTION_Y_VALUE(0x10) |
745 SOLO_VI_MOTION_CB_VALUE(0x80) |
746 SOLO_VI_MOTION_CR_VALUE(0x10));
747 } else {
748 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
749 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
750 }
751 return 0;
752 }
753 return -EINVAL;
754}
755
756static const struct v4l2_file_operations solo_v4l2_fops = {
757 .owner = THIS_MODULE,
758 .open = solo_v4l2_open,
759 .release = solo_v4l2_release,
760 .read = solo_v4l2_read,
761 .poll = solo_v4l2_poll,
762 .mmap = solo_v4l2_mmap,
763 .ioctl = video_ioctl2,
764};
765
766static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
767 .vidioc_querycap = solo_querycap,
768 .vidioc_s_std = solo_s_std,
769 /* Input callbacks */
770 .vidioc_enum_input = solo_enum_input,
771 .vidioc_s_input = solo_set_input,
772 .vidioc_g_input = solo_get_input,
773 /* Video capture format callbacks */
774 .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap,
775 .vidioc_try_fmt_vid_cap = solo_try_fmt_cap,
776 .vidioc_s_fmt_vid_cap = solo_set_fmt_cap,
777 .vidioc_g_fmt_vid_cap = solo_get_fmt_cap,
778 /* Streaming I/O */
779 .vidioc_reqbufs = solo_reqbufs,
780 .vidioc_querybuf = solo_querybuf,
781 .vidioc_qbuf = solo_qbuf,
782 .vidioc_dqbuf = solo_dqbuf,
783 .vidioc_streamon = solo_streamon,
784 .vidioc_streamoff = solo_streamoff,
785 /* Controls */
786 .vidioc_queryctrl = solo_disp_queryctrl,
787 .vidioc_g_ctrl = solo_disp_g_ctrl,
788 .vidioc_s_ctrl = solo_disp_s_ctrl,
789};
790
791static struct video_device solo_v4l2_template = {
792 .name = SOLO6010_NAME,
793 .fops = &solo_v4l2_fops,
794 .ioctl_ops = &solo_v4l2_ioctl_ops,
795 .minor = -1,
796 .release = video_device_release,
797
798 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
799 .current_norm = V4L2_STD_NTSC_M,
800};
801
802int solo_v4l2_init(struct solo6010_dev *solo_dev)
803{
804 int ret;
805 int i;
806
807 init_waitqueue_head(&solo_dev->disp_thread_wait);
808
809 solo_dev->vfd = video_device_alloc();
810 if (!solo_dev->vfd)
811 return -ENOMEM;
812
813 *solo_dev->vfd = solo_v4l2_template;
814 solo_dev->vfd->parent = &solo_dev->pdev->dev;
815
816 ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
817 if (ret < 0) {
818 video_device_release(solo_dev->vfd);
819 solo_dev->vfd = NULL;
820 return ret;
821 }
822
823 video_set_drvdata(solo_dev->vfd, solo_dev);
824
825 snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
826 SOLO6010_NAME, solo_dev->vfd->num);
827
828 if (video_nr >= 0)
829 video_nr++;
830
831 dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
832 "%d inputs (%d extended)\n", solo_dev->vfd->num,
833 solo_dev->nr_chans, solo_dev->nr_ext);
834
835 /* Cycle all the channels and clear */
836 for (i = 0; i < solo_dev->nr_chans; i++) {
837 solo_v4l2_set_ch(solo_dev, i);
838 while (erase_off(solo_dev))
839 ;// Do nothing
840 }
841
842 /* Set the default display channel */
843 solo_v4l2_set_ch(solo_dev, 0);
844 while (erase_off(solo_dev))
845 ;// Do nothing
846
847 solo6010_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
848
849 return 0;
850}
851
852void solo_v4l2_exit(struct solo6010_dev *solo_dev)
853{
854 solo6010_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
855 if (solo_dev->vfd) {
856 video_unregister_device(solo_dev->vfd);
857 solo_dev->vfd = NULL;
858 }
859}
diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h
new file mode 100644
index 00000000000..1c913d590e5
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010.h
@@ -0,0 +1,316 @@
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 __SOLO6010_H
21#define __SOLO6010_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 <asm/io.h>
31#include <asm/atomic.h>
32
33#include <linux/videodev2.h>
34#include <media/v4l2-dev.h>
35#include <media/videobuf-core.h>
36
37#include "solo6010-registers.h"
38
39#ifndef PCI_VENDOR_ID_SOFTLOGIC
40#define PCI_VENDOR_ID_SOFTLOGIC 0x9413
41#define PCI_DEVICE_ID_SOLO6010 0x6010
42#endif
43
44#ifndef PCI_VENDOR_ID_BLUECHERRY
45#define PCI_VENDOR_ID_BLUECHERRY 0x1BB3
46/* Neugent Softlogic 6010 based cards */
47#define PCI_DEVICE_ID_NEUSOLO_4 0x4304
48#define PCI_DEVICE_ID_NEUSOLO_9 0x4309
49#define PCI_DEVICE_ID_NEUSOLO_16 0x4310
50/* Commell Softlogic 6010 based cards */
51#define PCI_DEVICE_ID_COMMSOLO_4 0x4E04
52#define PCI_DEVICE_ID_COMMSOLO_9 0x4E09
53#define PCI_DEVICE_ID_COMMSOLO_16 0x4E10
54#endif /* Bluecherry */
55
56#define SOLO6010_NAME "solo6010"
57
58#define SOLO_MAX_CHANNELS 16
59
60/* Make sure these two match */
61#define SOLO6010_VERSION "2.0.0"
62#define SOLO6010_VER_MAJOR 2
63#define SOLO6010_VER_MINOR 0
64#define SOLO6010_VER_SUB 0
65#define SOLO6010_VER_NUM \
66 KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB)
67
68/*
69 * The SOLO6010 actually has 8 i2c channels, but we only use 2.
70 * 0 - Techwell chip(s)
71 * 1 - SAA7128
72 */
73#define SOLO_I2C_ADAPTERS 2
74#define SOLO_I2C_TW 0
75#define SOLO_I2C_SAA 1
76
77/* DMA Engine setup */
78#define SOLO_NR_P2M 4
79#define SOLO_NR_P2M_DESC 256
80#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16)
81/* MPEG and JPEG share the same interrupt and locks so they must be together
82 * in the same dma channel. */
83#define SOLO_P2M_DMA_ID_MP4E 0
84#define SOLO_P2M_DMA_ID_JPEG 0
85#define SOLO_P2M_DMA_ID_MP4D 1
86#define SOLO_P2M_DMA_ID_G723D 1
87#define SOLO_P2M_DMA_ID_DISP 2
88#define SOLO_P2M_DMA_ID_OSG 2
89#define SOLO_P2M_DMA_ID_G723E 3
90#define SOLO_P2M_DMA_ID_VIN 3
91
92/* Encoder standard modes */
93#define SOLO_ENC_MODE_CIF 2
94#define SOLO_ENC_MODE_HD1 1
95#define SOLO_ENC_MODE_D1 9
96
97#define SOLO_DEFAULT_GOP 30
98#define SOLO_DEFAULT_QP 3
99
100/* There is 8MB memory available for solo to buffer MPEG4 frames.
101 * This gives us 512 * 16kbyte queues. */
102#define SOLO_NR_RING_BUFS 512
103
104#define SOLO_CLOCK_MHZ 108
105
106#ifndef V4L2_BUF_FLAG_MOTION_ON
107#define V4L2_BUF_FLAG_MOTION_ON 0x0400
108#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800
109#endif
110#ifndef V4L2_CID_MOTION_ENABLE
111#define PRIVATE_CIDS
112#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0)
113#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1)
114#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2)
115#endif
116
117enum SOLO_I2C_STATE {
118 IIC_STATE_IDLE,
119 IIC_STATE_START,
120 IIC_STATE_READ,
121 IIC_STATE_WRITE,
122 IIC_STATE_STOP
123};
124
125struct solo_p2m_dev {
126 struct semaphore sem;
127 struct completion completion;
128 int error;
129 u8 desc[SOLO_P2M_DESC_SIZE];
130};
131
132#define OSD_TEXT_MAX 30
133
134enum solo_enc_types {
135 SOLO_ENC_TYPE_STD,
136 SOLO_ENC_TYPE_EXT,
137};
138
139struct solo_enc_dev {
140 struct solo6010_dev *solo_dev;
141 /* V4L2 Items */
142 struct video_device *vfd;
143 /* General accounting */
144 wait_queue_head_t thread_wait;
145 spinlock_t lock;
146 atomic_t readers;
147 u8 ch;
148 u8 mode, gop, qp, interlaced, interval;
149 u8 reset_gop;
150 u8 bw_weight;
151 u8 motion_detected;
152 u16 motion_thresh;
153 u16 width;
154 u16 height;
155 char osd_text[OSD_TEXT_MAX + 1];
156};
157
158struct solo_enc_buf {
159 u8 vop;
160 u8 ch;
161 enum solo_enc_types type;
162 u32 off;
163 u32 size;
164 u32 jpeg_off;
165 u32 jpeg_size;
166 struct timeval ts;
167};
168
169/* The SOLO6010 PCI Device */
170struct solo6010_dev {
171 /* General stuff */
172 struct pci_dev *pdev;
173 u8 __iomem *reg_base;
174 int nr_chans;
175 int nr_ext;
176 u32 irq_mask;
177 u32 motion_mask;
178 spinlock_t reg_io_lock;
179
180 /* tw28xx accounting */
181 u8 tw2864, tw2815;
182 u8 tw28_cnt;
183
184 /* i2c related items */
185 struct i2c_adapter i2c_adap[SOLO_I2C_ADAPTERS];
186 enum SOLO_I2C_STATE i2c_state;
187 struct semaphore i2c_sem;
188 int i2c_id;
189 wait_queue_head_t i2c_wait;
190 struct i2c_msg *i2c_msg;
191 unsigned int i2c_msg_num;
192 unsigned int i2c_msg_ptr;
193
194 /* P2M DMA Engine */
195 struct solo_p2m_dev p2m_dev[SOLO_NR_P2M];
196
197 /* V4L2 Display items */
198 struct video_device *vfd;
199 unsigned int erasing;
200 unsigned int frame_blank;
201 u8 cur_disp_ch;
202 wait_queue_head_t disp_thread_wait;
203
204 /* V4L2 Encoder items */
205 struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS];
206 u16 enc_bw_remain;
207 /* IDX into hw mp4 encoder */
208 u8 enc_idx;
209 /* Our software ring of enc buf references */
210 u16 enc_wr_idx;
211 struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS];
212
213 /* Current video settings */
214 u32 video_type;
215 u16 video_hsize, video_vsize;
216 u16 vout_hstart, vout_vstart;
217 u16 vin_hstart, vin_vstart;
218 u8 fps;
219
220 /* Audio components */
221 struct snd_card *snd_card;
222 struct snd_pcm *snd_pcm;
223 atomic_t snd_users;
224 int g723_hw_idx;
225};
226
227static inline u32 solo_reg_read(struct solo6010_dev *solo_dev, int reg)
228{
229 unsigned long flags;
230 u32 ret;
231 u16 val;
232
233 spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
234
235 ret = readl(solo_dev->reg_base + reg);
236 rmb();
237 pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
238 rmb();
239
240 spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
241
242 return ret;
243}
244
245static inline void solo_reg_write(struct solo6010_dev *solo_dev, int reg,
246 u32 data)
247{
248 unsigned long flags;
249 u16 val;
250
251 spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
252
253 writel(data, solo_dev->reg_base + reg);
254 wmb();
255 pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
256 rmb();
257
258 spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
259}
260
261void solo6010_irq_on(struct solo6010_dev *solo_dev, u32 mask);
262void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask);
263
264/* Init/exit routeines for subsystems */
265int solo_disp_init(struct solo6010_dev *solo_dev);
266void solo_disp_exit(struct solo6010_dev *solo_dev);
267
268int solo_gpio_init(struct solo6010_dev *solo_dev);
269void solo_gpio_exit(struct solo6010_dev *solo_dev);
270
271int solo_i2c_init(struct solo6010_dev *solo_dev);
272void solo_i2c_exit(struct solo6010_dev *solo_dev);
273
274int solo_p2m_init(struct solo6010_dev *solo_dev);
275void solo_p2m_exit(struct solo6010_dev *solo_dev);
276
277int solo_v4l2_init(struct solo6010_dev *solo_dev);
278void solo_v4l2_exit(struct solo6010_dev *solo_dev);
279
280int solo_enc_init(struct solo6010_dev *solo_dev);
281void solo_enc_exit(struct solo6010_dev *solo_dev);
282
283int solo_enc_v4l2_init(struct solo6010_dev *solo_dev);
284void solo_enc_v4l2_exit(struct solo6010_dev *solo_dev);
285
286int solo_g723_init(struct solo6010_dev *solo_dev);
287void solo_g723_exit(struct solo6010_dev *solo_dev);
288
289/* ISR's */
290int solo_i2c_isr(struct solo6010_dev *solo_dev);
291void solo_p2m_isr(struct solo6010_dev *solo_dev, int id);
292void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status);
293void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev);
294void solo_g723_isr(struct solo6010_dev *solo_dev);
295void solo_motion_isr(struct solo6010_dev *solo_dev);
296void solo_video_in_isr(struct solo6010_dev *solo_dev);
297
298/* i2c read/write */
299u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off);
300void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off,
301 u8 data);
302
303/* P2M DMA */
304int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
305 dma_addr_t dma_addr, u32 ext_addr, u32 size);
306int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
307 void *sys_addr, u32 ext_addr, u32 size);
308
309/* Set the threshold for motion detection */
310void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val);
311#define SOLO_DEF_MOT_THRESH 0x0300
312
313/* Write text on OSD */
314int solo_osd_print(struct solo_enc_dev *solo_enc);
315
316#endif /* __SOLO6010_H */