diff options
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 8 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 19 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.c | 25 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.h | 1 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-firmware.c | 5 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-io.c | 35 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-io.h | 7 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-irq.c | 133 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-irq.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 318 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.h | 16 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.c | 25 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-scb.h | 8 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 18 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.h | 1 |
16 files changed, 408 insertions, 215 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 8ef11d578b8d..434cc7fdee36 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -440,6 +440,8 @@ done: | |||
440 | */ | 440 | */ |
441 | static int __devinit cx18_init_struct1(struct cx18 *cx) | 441 | static int __devinit cx18_init_struct1(struct cx18 *cx) |
442 | { | 442 | { |
443 | int i; | ||
444 | |||
443 | cx->base_addr = pci_resource_start(cx->dev, 0); | 445 | cx->base_addr = pci_resource_start(cx->dev, 0); |
444 | 446 | ||
445 | mutex_init(&cx->serialize_lock); | 447 | mutex_init(&cx->serialize_lock); |
@@ -451,7 +453,11 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) | |||
451 | 453 | ||
452 | spin_lock_init(&cx->lock); | 454 | spin_lock_init(&cx->lock); |
453 | 455 | ||
454 | INIT_WORK(&cx->work, cx18_work_handler); | 456 | for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { |
457 | cx->epu_work_order[i].cx = cx; | ||
458 | cx->epu_work_order[i].str = cx->epu_debug_str; | ||
459 | INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler); | ||
460 | } | ||
455 | 461 | ||
456 | /* start counting open_id at 1 */ | 462 | /* start counting open_id at 1 */ |
457 | cx->open_id = 1; | 463 | cx->open_id = 1; |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index ce76806759ec..5ebf84b78ca8 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -203,8 +203,6 @@ struct cx18_options { | |||
203 | #define CX18_F_I_EOS 4 /* End of encoder stream */ | 203 | #define CX18_F_I_EOS 4 /* End of encoder stream */ |
204 | #define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ | 204 | #define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ |
205 | #define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ | 205 | #define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ |
206 | #define CX18_F_I_HAVE_WORK 15 /* there is work to be done */ | ||
207 | #define CX18_F_I_WORK_HANDLER_DVB 18 /* work to be done for DVB */ | ||
208 | #define CX18_F_I_INITED 21 /* set after first open */ | 206 | #define CX18_F_I_INITED 21 /* set after first open */ |
209 | #define CX18_F_I_FAILED 22 /* set if first open failed */ | 207 | #define CX18_F_I_FAILED 22 /* set if first open failed */ |
210 | 208 | ||
@@ -247,6 +245,19 @@ struct cx18_dvb { | |||
247 | struct cx18; /* forward reference */ | 245 | struct cx18; /* forward reference */ |
248 | struct cx18_scb; /* forward reference */ | 246 | struct cx18_scb; /* forward reference */ |
249 | 247 | ||
248 | #define CX18_MAX_MDL_ACKS 2 | ||
249 | #define CX18_MAX_EPU_WORK_ORDERS 70 /* CPU_DE_RELEASE_MDL bursts 63 commands */ | ||
250 | |||
251 | struct cx18_epu_work_order { | ||
252 | struct work_struct work; | ||
253 | atomic_t pending; | ||
254 | struct cx18 *cx; | ||
255 | int rpu; | ||
256 | struct cx18_mailbox mb; | ||
257 | struct cx18_mdl_ack mdl_ack[CX18_MAX_MDL_ACKS]; | ||
258 | char *str; | ||
259 | }; | ||
260 | |||
250 | #define CX18_INVALID_TASK_HANDLE 0xffffffff | 261 | #define CX18_INVALID_TASK_HANDLE 0xffffffff |
251 | 262 | ||
252 | struct cx18_stream { | 263 | struct cx18_stream { |
@@ -388,7 +399,6 @@ struct cx18 { | |||
388 | struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ | 399 | struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ |
389 | struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ | 400 | struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ |
390 | 401 | ||
391 | |||
392 | struct cx18_av_state av_state; | 402 | struct cx18_av_state av_state; |
393 | 403 | ||
394 | /* codec settings */ | 404 | /* codec settings */ |
@@ -441,7 +451,8 @@ struct cx18 { | |||
441 | /* when the current DMA is finished this queue is woken up */ | 451 | /* when the current DMA is finished this queue is woken up */ |
442 | wait_queue_head_t dma_waitq; | 452 | wait_queue_head_t dma_waitq; |
443 | 453 | ||
444 | struct work_struct work; | 454 | struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS]; |
455 | char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ | ||
445 | 456 | ||
446 | /* i2c */ | 457 | /* i2c */ |
447 | struct i2c_adapter i2c_adap[2]; | 458 | struct i2c_adapter i2c_adap[2]; |
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 4845f732ef48..b74253b1377e 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c | |||
@@ -23,8 +23,6 @@ | |||
23 | #include "cx18-dvb.h" | 23 | #include "cx18-dvb.h" |
24 | #include "cx18-io.h" | 24 | #include "cx18-io.h" |
25 | #include "cx18-streams.h" | 25 | #include "cx18-streams.h" |
26 | #include "cx18-queue.h" | ||
27 | #include "cx18-scb.h" | ||
28 | #include "cx18-cards.h" | 26 | #include "cx18-cards.h" |
29 | #include "s5h1409.h" | 27 | #include "s5h1409.h" |
30 | #include "mxl5005s.h" | 28 | #include "mxl5005s.h" |
@@ -305,26 +303,3 @@ static int dvb_register(struct cx18_stream *stream) | |||
305 | 303 | ||
306 | return ret; | 304 | return ret; |
307 | } | 305 | } |
308 | |||
309 | void cx18_dvb_work_handler(struct cx18 *cx) | ||
310 | { | ||
311 | struct cx18_buffer *buf; | ||
312 | struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS]; | ||
313 | |||
314 | while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) { | ||
315 | if (s->dvb.enabled) | ||
316 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, | ||
317 | buf->bytesused); | ||
318 | |||
319 | cx18_buf_sync_for_device(s, buf); | ||
320 | cx18_enqueue(s, buf, &s->q_free); | ||
321 | |||
322 | if (s->handle == CX18_INVALID_TASK_HANDLE || | ||
323 | !test_bit(CX18_F_S_STREAMING, &s->s_flags)) | ||
324 | continue; | ||
325 | |||
326 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
327 | (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
328 | 1, buf->id, s->buf_size); | ||
329 | } | ||
330 | } | ||
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h index bbdcefc87f28..bf8d8f6f5455 100644 --- a/drivers/media/video/cx18/cx18-dvb.h +++ b/drivers/media/video/cx18/cx18-dvb.h | |||
@@ -23,4 +23,3 @@ | |||
23 | 23 | ||
24 | int cx18_dvb_register(struct cx18_stream *stream); | 24 | int cx18_dvb_register(struct cx18_stream *stream); |
25 | void cx18_dvb_unregister(struct cx18_stream *stream); | 25 | void cx18_dvb_unregister(struct cx18_stream *stream); |
26 | void cx18_dvb_work_handler(struct cx18 *cx); | ||
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index d9c5f55ab17c..fdea4b75204d 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c | |||
@@ -121,6 +121,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) | |||
121 | if (cx18_raw_readl(cx, dst) != *src) { | 121 | if (cx18_raw_readl(cx, dst) != *src) { |
122 | CX18_ERR("Mismatch at offset %x\n", i); | 122 | CX18_ERR("Mismatch at offset %x\n", i); |
123 | release_firmware(fw); | 123 | release_firmware(fw); |
124 | cx18_setup_page(cx, 0); | ||
124 | return -EIO; | 125 | return -EIO; |
125 | } | 126 | } |
126 | dst++; | 127 | dst++; |
@@ -131,6 +132,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) | |||
131 | CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); | 132 | CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); |
132 | size = fw->size; | 133 | size = fw->size; |
133 | release_firmware(fw); | 134 | release_firmware(fw); |
135 | cx18_setup_page(cx, SCB_OFFSET); | ||
134 | return size; | 136 | return size; |
135 | } | 137 | } |
136 | 138 | ||
@@ -150,6 +152,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, | |||
150 | if (request_firmware(&fw, fn, &cx->dev->dev)) { | 152 | if (request_firmware(&fw, fn, &cx->dev->dev)) { |
151 | CX18_ERR("unable to open firmware %s\n", fn); | 153 | CX18_ERR("unable to open firmware %s\n", fn); |
152 | CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); | 154 | CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); |
155 | cx18_setup_page(cx, 0); | ||
153 | return -ENOMEM; | 156 | return -ENOMEM; |
154 | } | 157 | } |
155 | 158 | ||
@@ -185,6 +188,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, | |||
185 | CX18_ERR("Mismatch at offset %x\n", | 188 | CX18_ERR("Mismatch at offset %x\n", |
186 | offset + j); | 189 | offset + j); |
187 | release_firmware(fw); | 190 | release_firmware(fw); |
191 | cx18_setup_page(cx, 0); | ||
188 | return -EIO; | 192 | return -EIO; |
189 | } | 193 | } |
190 | } | 194 | } |
@@ -196,6 +200,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, | |||
196 | fn, apu_version, fw->size); | 200 | fn, apu_version, fw->size); |
197 | size = fw->size; | 201 | size = fw->size; |
198 | release_firmware(fw); | 202 | release_firmware(fw); |
203 | cx18_setup_page(cx, 0); | ||
199 | return size; | 204 | return size; |
200 | } | 205 | } |
201 | 206 | ||
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c index 3c6485fceea0..c67694f63d0e 100644 --- a/drivers/media/video/cx18/cx18-io.c +++ b/drivers/media/video/cx18/cx18-io.c | |||
@@ -166,41 +166,6 @@ u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr) | |||
166 | return val; | 166 | return val; |
167 | } | 167 | } |
168 | 168 | ||
169 | void cx18_memcpy_fromio(struct cx18 *cx, void *to, | ||
170 | const void __iomem *from, unsigned int len) | ||
171 | { | ||
172 | const u8 __iomem *src = from; | ||
173 | u8 *dst = to; | ||
174 | |||
175 | /* Align reads on the CX23418's addresses */ | ||
176 | if ((len > 0) && ((unsigned long) src & 1)) { | ||
177 | *dst = cx18_readb(cx, src); | ||
178 | len--; | ||
179 | dst++; | ||
180 | src++; | ||
181 | } | ||
182 | if ((len > 1) && ((unsigned long) src & 2)) { | ||
183 | *((u16 *)dst) = cx18_raw_readw(cx, src); | ||
184 | len -= 2; | ||
185 | dst += 2; | ||
186 | src += 2; | ||
187 | } | ||
188 | while (len > 3) { | ||
189 | *((u32 *)dst) = cx18_raw_readl(cx, src); | ||
190 | len -= 4; | ||
191 | dst += 4; | ||
192 | src += 4; | ||
193 | } | ||
194 | if (len > 1) { | ||
195 | *((u16 *)dst) = cx18_raw_readw(cx, src); | ||
196 | len -= 2; | ||
197 | dst += 2; | ||
198 | src += 2; | ||
199 | } | ||
200 | if (len > 0) | ||
201 | *dst = cx18_readb(cx, src); | ||
202 | } | ||
203 | |||
204 | void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) | 169 | void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) |
205 | { | 170 | { |
206 | u8 __iomem *dst = addr; | 171 | u8 __iomem *dst = addr; |
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h index 4486b73faf5b..fdc2bcc92fca 100644 --- a/drivers/media/video/cx18/cx18-io.h +++ b/drivers/media/video/cx18/cx18-io.h | |||
@@ -249,8 +249,13 @@ static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr) | |||
249 | } | 249 | } |
250 | 250 | ||
251 | 251 | ||
252 | static inline | ||
252 | void cx18_memcpy_fromio(struct cx18 *cx, void *to, | 253 | void cx18_memcpy_fromio(struct cx18 *cx, void *to, |
253 | const void __iomem *from, unsigned int len); | 254 | const void __iomem *from, unsigned int len) |
255 | { | ||
256 | memcpy_fromio(to, from, len); | ||
257 | } | ||
258 | |||
254 | void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); | 259 | void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); |
255 | 260 | ||
256 | 261 | ||
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index 4912b3c8e6a5..bc36a6b8f775 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c | |||
@@ -21,121 +21,9 @@ | |||
21 | 21 | ||
22 | #include "cx18-driver.h" | 22 | #include "cx18-driver.h" |
23 | #include "cx18-io.h" | 23 | #include "cx18-io.h" |
24 | #include "cx18-firmware.h" | ||
25 | #include "cx18-fileops.h" | ||
26 | #include "cx18-queue.h" | ||
27 | #include "cx18-irq.h" | 24 | #include "cx18-irq.h" |
28 | #include "cx18-ioctl.h" | ||
29 | #include "cx18-mailbox.h" | 25 | #include "cx18-mailbox.h" |
30 | #include "cx18-vbi.h" | ||
31 | #include "cx18-scb.h" | 26 | #include "cx18-scb.h" |
32 | #include "cx18-dvb.h" | ||
33 | |||
34 | void cx18_work_handler(struct work_struct *work) | ||
35 | { | ||
36 | struct cx18 *cx = container_of(work, struct cx18, work); | ||
37 | if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags)) | ||
38 | cx18_dvb_work_handler(cx); | ||
39 | } | ||
40 | |||
41 | static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) | ||
42 | { | ||
43 | u32 handle = mb->args[0]; | ||
44 | struct cx18_stream *s = NULL; | ||
45 | struct cx18_buffer *buf; | ||
46 | u32 off; | ||
47 | int i; | ||
48 | int id; | ||
49 | |||
50 | for (i = 0; i < CX18_MAX_STREAMS; i++) { | ||
51 | s = &cx->streams[i]; | ||
52 | if ((handle == s->handle) && (s->dvb.enabled)) | ||
53 | break; | ||
54 | if (s->v4l2dev && handle == s->handle) | ||
55 | break; | ||
56 | } | ||
57 | if (i == CX18_MAX_STREAMS) { | ||
58 | CX18_WARN("Got DMA done notification for unknown/inactive" | ||
59 | " handle %d\n", handle); | ||
60 | mb->error = CXERR_NOT_OPEN; | ||
61 | mb->cmd = 0; | ||
62 | cx18_mb_ack(cx, mb, rpu); | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | off = mb->args[1]; | ||
67 | if (mb->args[2] != 1) | ||
68 | CX18_WARN("Ack struct = %d for %s\n", | ||
69 | mb->args[2], s->name); | ||
70 | id = cx18_read_enc(cx, off); | ||
71 | buf = cx18_queue_get_buf_irq(s, id, cx18_read_enc(cx, off + 4)); | ||
72 | CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); | ||
73 | if (buf) { | ||
74 | cx18_buf_sync_for_cpu(s, buf); | ||
75 | if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { | ||
76 | CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", | ||
77 | buf->bytesused); | ||
78 | |||
79 | set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags); | ||
80 | set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags); | ||
81 | } else | ||
82 | set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); | ||
83 | } else { | ||
84 | CX18_WARN("Could not find buf %d for stream %s\n", | ||
85 | cx18_read_enc(cx, off), s->name); | ||
86 | } | ||
87 | mb->error = 0; | ||
88 | mb->cmd = 0; | ||
89 | cx18_mb_ack(cx, mb, rpu); | ||
90 | wake_up(&cx->dma_waitq); | ||
91 | if (s->id != -1) | ||
92 | wake_up(&s->waitq); | ||
93 | } | ||
94 | |||
95 | static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) | ||
96 | { | ||
97 | char str[256] = { 0 }; | ||
98 | char *p; | ||
99 | |||
100 | if (mb->args[1]) { | ||
101 | cx18_setup_page(cx, mb->args[1]); | ||
102 | cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252); | ||
103 | str[252] = 0; | ||
104 | } | ||
105 | cx18_mb_ack(cx, mb, rpu); | ||
106 | CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); | ||
107 | p = strchr(str, '.'); | ||
108 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) | ||
109 | CX18_INFO("FW version: %s\n", p - 1); | ||
110 | } | ||
111 | |||
112 | static void epu_cmd(struct cx18 *cx, u32 sw1) | ||
113 | { | ||
114 | struct cx18_mailbox mb; | ||
115 | |||
116 | if (sw1 & IRQ_CPU_TO_EPU) { | ||
117 | cx18_memcpy_fromio(cx, &mb, &cx->scb->cpu2epu_mb, sizeof(mb)); | ||
118 | mb.error = 0; | ||
119 | |||
120 | switch (mb.cmd) { | ||
121 | case CX18_EPU_DMA_DONE: | ||
122 | epu_dma_done(cx, &mb, CPU); | ||
123 | break; | ||
124 | case CX18_EPU_DEBUG: | ||
125 | epu_debug(cx, &mb, CPU); | ||
126 | break; | ||
127 | default: | ||
128 | CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n", | ||
129 | mb.cmd); | ||
130 | break; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | if (sw1 & IRQ_APU_TO_EPU) { | ||
135 | cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb)); | ||
136 | CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd); | ||
137 | } | ||
138 | } | ||
139 | 27 | ||
140 | static void xpu_ack(struct cx18 *cx, u32 sw2) | 28 | static void xpu_ack(struct cx18 *cx, u32 sw2) |
141 | { | 29 | { |
@@ -145,6 +33,14 @@ static void xpu_ack(struct cx18 *cx, u32 sw2) | |||
145 | wake_up(&cx->mb_apu_waitq); | 33 | wake_up(&cx->mb_apu_waitq); |
146 | } | 34 | } |
147 | 35 | ||
36 | static void epu_cmd(struct cx18 *cx, u32 sw1) | ||
37 | { | ||
38 | if (sw1 & IRQ_CPU_TO_EPU) | ||
39 | cx18_api_epu_cmd_irq(cx, CPU); | ||
40 | if (sw1 & IRQ_APU_TO_EPU) | ||
41 | cx18_api_epu_cmd_irq(cx, APU); | ||
42 | } | ||
43 | |||
148 | irqreturn_t cx18_irq_handler(int irq, void *dev_id) | 44 | irqreturn_t cx18_irq_handler(int irq, void *dev_id) |
149 | { | 45 | { |
150 | struct cx18 *cx = (struct cx18 *)dev_id; | 46 | struct cx18 *cx = (struct cx18 *)dev_id; |
@@ -170,6 +66,13 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) | |||
170 | CX18_DEBUG_HI_IRQ("received interrupts " | 66 | CX18_DEBUG_HI_IRQ("received interrupts " |
171 | "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); | 67 | "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); |
172 | 68 | ||
69 | /* | ||
70 | * SW1 responses have to happen first. The sending XPU times out the | ||
71 | * incoming mailboxes on us rather rapidly. | ||
72 | */ | ||
73 | if (sw1) | ||
74 | epu_cmd(cx, sw1); | ||
75 | |||
173 | /* To do: interrupt-based I2C handling | 76 | /* To do: interrupt-based I2C handling |
174 | if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { | 77 | if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { |
175 | } | 78 | } |
@@ -178,11 +81,5 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) | |||
178 | if (sw2) | 81 | if (sw2) |
179 | xpu_ack(cx, sw2); | 82 | xpu_ack(cx, sw2); |
180 | 83 | ||
181 | if (sw1) | ||
182 | epu_cmd(cx, sw1); | ||
183 | |||
184 | if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags)) | ||
185 | schedule_work(&cx->work); | ||
186 | |||
187 | return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; | 84 | return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; |
188 | } | 85 | } |
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h index 6f3ec8963762..cd8f548b7ee8 100644 --- a/drivers/media/video/cx18/cx18-irq.h +++ b/drivers/media/video/cx18/cx18-irq.h | |||
@@ -32,5 +32,3 @@ | |||
32 | #define SW2_INT_ENABLE_PCI 0xc7315c | 32 | #define SW2_INT_ENABLE_PCI 0xc7315c |
33 | 33 | ||
34 | irqreturn_t cx18_irq_handler(int irq, void *dev_id); | 34 | irqreturn_t cx18_irq_handler(int irq, void *dev_id); |
35 | |||
36 | void cx18_work_handler(struct work_struct *work); | ||
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 35f7188d4d3b..3d210d2ffdad 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -26,6 +26,10 @@ | |||
26 | #include "cx18-scb.h" | 26 | #include "cx18-scb.h" |
27 | #include "cx18-irq.h" | 27 | #include "cx18-irq.h" |
28 | #include "cx18-mailbox.h" | 28 | #include "cx18-mailbox.h" |
29 | #include "cx18-queue.h" | ||
30 | #include "cx18-streams.h" | ||
31 | |||
32 | static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" }; | ||
29 | 33 | ||
30 | #define API_FAST (1 << 2) /* Short timeout */ | 34 | #define API_FAST (1 << 2) /* Short timeout */ |
31 | #define API_SLOW (1 << 3) /* Additional 300ms timeout */ | 35 | #define API_SLOW (1 << 3) /* Additional 300ms timeout */ |
@@ -92,12 +96,149 @@ static const struct cx18_api_info *find_api_info(u32 cmd) | |||
92 | return NULL; | 96 | return NULL; |
93 | } | 97 | } |
94 | 98 | ||
95 | long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu) | 99 | static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) |
100 | { | ||
101 | char argstr[MAX_MB_ARGUMENTS*11+1]; | ||
102 | char *p; | ||
103 | int i; | ||
104 | |||
105 | if (!(cx18_debug & CX18_DBGFLG_API)) | ||
106 | return; | ||
107 | |||
108 | for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) { | ||
109 | /* kernel snprintf() appends '\0' always */ | ||
110 | snprintf(p, 12, " %#010x", mb->args[i]); | ||
111 | } | ||
112 | CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" | ||
113 | "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr); | ||
114 | } | ||
115 | |||
116 | |||
117 | /* | ||
118 | * Functions that run in a work_queue work handling context | ||
119 | */ | ||
120 | |||
121 | static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) | ||
122 | { | ||
123 | u32 handle, mdl_ack_count; | ||
124 | struct cx18_mailbox *mb; | ||
125 | struct cx18_mdl_ack *mdl_ack; | ||
126 | struct cx18_stream *s; | ||
127 | struct cx18_buffer *buf; | ||
128 | int i; | ||
129 | |||
130 | mb = &order->mb; | ||
131 | handle = mb->args[0]; | ||
132 | s = cx18_handle_to_stream(cx, handle); | ||
133 | |||
134 | if (s == NULL) { | ||
135 | CX18_WARN("Got DMA done notification for unknown/inactive" | ||
136 | " handle %d\n", handle); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | mdl_ack_count = mb->args[2]; | ||
141 | mdl_ack = order->mdl_ack; | ||
142 | for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { | ||
143 | buf = cx18_queue_get_buf(s, mdl_ack->id, mdl_ack->data_used); | ||
144 | CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, | ||
145 | mdl_ack->id); | ||
146 | if (buf == NULL) { | ||
147 | CX18_WARN("Could not find buf %d for stream %s\n", | ||
148 | mdl_ack->id, s->name); | ||
149 | continue; | ||
150 | } | ||
151 | |||
152 | cx18_buf_sync_for_cpu(s, buf); | ||
153 | if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { | ||
154 | CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", | ||
155 | buf->bytesused); | ||
156 | |||
157 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, | ||
158 | buf->bytesused); | ||
159 | |||
160 | cx18_buf_sync_for_device(s, buf); | ||
161 | |||
162 | if (s->handle != CX18_INVALID_TASK_HANDLE && | ||
163 | test_bit(CX18_F_S_STREAMING, &s->s_flags)) | ||
164 | cx18_vapi(cx, | ||
165 | CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
166 | (void __iomem *) | ||
167 | &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
168 | 1, buf->id, s->buf_size); | ||
169 | } else | ||
170 | set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); | ||
171 | } | ||
172 | wake_up(&cx->dma_waitq); | ||
173 | if (s->id != -1) | ||
174 | wake_up(&s->waitq); | ||
175 | } | ||
176 | |||
177 | static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order) | ||
178 | { | ||
179 | char *p; | ||
180 | char *str = order->str; | ||
181 | |||
182 | CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); | ||
183 | p = strchr(str, '.'); | ||
184 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) | ||
185 | CX18_INFO("FW version: %s\n", p - 1); | ||
186 | } | ||
187 | |||
188 | static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order) | ||
189 | { | ||
190 | switch (order->rpu) { | ||
191 | case CPU: | ||
192 | { | ||
193 | switch (order->mb.cmd) { | ||
194 | case CX18_EPU_DMA_DONE: | ||
195 | epu_dma_done(cx, order); | ||
196 | break; | ||
197 | case CX18_EPU_DEBUG: | ||
198 | epu_debug(cx, order); | ||
199 | break; | ||
200 | default: | ||
201 | CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", | ||
202 | order->mb.cmd); | ||
203 | break; | ||
204 | } | ||
205 | break; | ||
206 | } | ||
207 | case APU: | ||
208 | CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", | ||
209 | order->mb.cmd); | ||
210 | break; | ||
211 | default: | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static | ||
217 | void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order) | ||
218 | { | ||
219 | atomic_set(&order->pending, 0); | ||
220 | } | ||
221 | |||
222 | void cx18_epu_work_handler(struct work_struct *work) | ||
223 | { | ||
224 | struct cx18_epu_work_order *order = | ||
225 | container_of(work, struct cx18_epu_work_order, work); | ||
226 | struct cx18 *cx = order->cx; | ||
227 | epu_cmd(cx, order); | ||
228 | free_epu_work_order(cx, order); | ||
229 | } | ||
230 | |||
231 | |||
232 | /* | ||
233 | * Functions that run in an interrupt handling context | ||
234 | */ | ||
235 | |||
236 | static void mb_ack_irq(struct cx18 *cx, const struct cx18_epu_work_order *order) | ||
96 | { | 237 | { |
97 | struct cx18_mailbox __iomem *ack_mb; | 238 | struct cx18_mailbox __iomem *ack_mb; |
98 | u32 ack_irq; | 239 | u32 ack_irq, req; |
99 | 240 | ||
100 | switch (rpu) { | 241 | switch (order->rpu) { |
101 | case APU: | 242 | case APU: |
102 | ack_irq = IRQ_EPU_TO_APU_ACK; | 243 | ack_irq = IRQ_EPU_TO_APU_ACK; |
103 | ack_mb = &cx->scb->apu2epu_mb; | 244 | ack_mb = &cx->scb->apu2epu_mb; |
@@ -108,16 +249,175 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu) | |||
108 | break; | 249 | break; |
109 | default: | 250 | default: |
110 | CX18_WARN("Unhandled RPU (%d) for command %x ack\n", | 251 | CX18_WARN("Unhandled RPU (%d) for command %x ack\n", |
111 | rpu, mb->cmd); | 252 | order->rpu, order->mb.cmd); |
112 | return -EINVAL; | 253 | return; |
113 | } | 254 | } |
114 | 255 | ||
115 | cx18_setup_page(cx, SCB_OFFSET); | 256 | req = order->mb.request; |
116 | cx18_write_sync(cx, mb->request, &ack_mb->ack); | 257 | /* Don't ack if the RPU has gotten impatient and timed us out */ |
258 | if (req != cx18_readl(cx, &ack_mb->request) || | ||
259 | req == cx18_readl(cx, &ack_mb->ack)) | ||
260 | return; | ||
261 | cx18_writel(cx, req, &ack_mb->ack); | ||
117 | cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); | 262 | cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); |
118 | return 0; | 263 | return; |
264 | } | ||
265 | |||
266 | static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order, | ||
267 | int stale) | ||
268 | { | ||
269 | u32 handle, mdl_ack_offset, mdl_ack_count; | ||
270 | struct cx18_mailbox *mb; | ||
271 | |||
272 | mb = &order->mb; | ||
273 | handle = mb->args[0]; | ||
274 | mdl_ack_offset = mb->args[1]; | ||
275 | mdl_ack_count = mb->args[2]; | ||
276 | |||
277 | if (handle == CX18_INVALID_TASK_HANDLE || | ||
278 | mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) { | ||
279 | if (!stale) | ||
280 | mb_ack_irq(cx, order); | ||
281 | return -1; | ||
282 | } | ||
283 | |||
284 | cx18_memcpy_fromio(cx, order->mdl_ack, cx->enc_mem + mdl_ack_offset, | ||
285 | sizeof(struct cx18_mdl_ack) * mdl_ack_count); | ||
286 | if (!stale) | ||
287 | mb_ack_irq(cx, order); | ||
288 | return 1; | ||
289 | } | ||
290 | |||
291 | static | ||
292 | int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order, int stale) | ||
293 | { | ||
294 | u32 str_offset; | ||
295 | char *str = order->str; | ||
296 | |||
297 | str[0] = '\0'; | ||
298 | str_offset = order->mb.args[1]; | ||
299 | if (str_offset) { | ||
300 | cx18_setup_page(cx, str_offset); | ||
301 | cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); | ||
302 | str[252] = '\0'; | ||
303 | cx18_setup_page(cx, SCB_OFFSET); | ||
304 | } | ||
305 | |||
306 | if (!stale) | ||
307 | mb_ack_irq(cx, order); | ||
308 | |||
309 | return str_offset ? 1 : 0; | ||
310 | } | ||
311 | |||
312 | static inline | ||
313 | int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order, int stale) | ||
314 | { | ||
315 | int ret = -1; | ||
316 | |||
317 | switch (order->rpu) { | ||
318 | case CPU: | ||
319 | { | ||
320 | switch (order->mb.cmd) { | ||
321 | case CX18_EPU_DMA_DONE: | ||
322 | ret = epu_dma_done_irq(cx, order, stale); | ||
323 | break; | ||
324 | case CX18_EPU_DEBUG: | ||
325 | ret = epu_debug_irq(cx, order, stale); | ||
326 | break; | ||
327 | default: | ||
328 | CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", | ||
329 | order->mb.cmd); | ||
330 | break; | ||
331 | } | ||
332 | break; | ||
333 | } | ||
334 | case APU: | ||
335 | CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", | ||
336 | order->mb.cmd); | ||
337 | break; | ||
338 | default: | ||
339 | break; | ||
340 | } | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | static inline | ||
345 | struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx) | ||
346 | { | ||
347 | int i; | ||
348 | struct cx18_epu_work_order *order = NULL; | ||
349 | |||
350 | for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { | ||
351 | /* | ||
352 | * We only need "pending" atomic to inspect its contents, | ||
353 | * and need not do a check and set because: | ||
354 | * 1. Any work handler thread only clears "pending" and only | ||
355 | * on one, particular work order at a time, per handler thread. | ||
356 | * 2. "pending" is only set here, and we're serialized because | ||
357 | * we're called in an IRQ handler context. | ||
358 | */ | ||
359 | if (atomic_read(&cx->epu_work_order[i].pending) == 0) { | ||
360 | order = &cx->epu_work_order[i]; | ||
361 | atomic_set(&order->pending, 1); | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | return order; | ||
119 | } | 366 | } |
120 | 367 | ||
368 | void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) | ||
369 | { | ||
370 | struct cx18_mailbox __iomem *mb; | ||
371 | struct cx18_mailbox *order_mb; | ||
372 | struct cx18_epu_work_order *order; | ||
373 | int stale = 0; | ||
374 | int submit; | ||
375 | |||
376 | switch (rpu) { | ||
377 | case CPU: | ||
378 | mb = &cx->scb->cpu2epu_mb; | ||
379 | break; | ||
380 | case APU: | ||
381 | mb = &cx->scb->apu2epu_mb; | ||
382 | break; | ||
383 | default: | ||
384 | return; | ||
385 | } | ||
386 | |||
387 | order = alloc_epu_work_order_irq(cx); | ||
388 | if (order == NULL) { | ||
389 | CX18_WARN("Unable to find blank work order form to schedule " | ||
390 | "incoming mailbox command processing\n"); | ||
391 | return; | ||
392 | } | ||
393 | |||
394 | order->rpu = rpu; | ||
395 | order_mb = &order->mb; | ||
396 | cx18_memcpy_fromio(cx, order_mb, mb, sizeof(struct cx18_mailbox)); | ||
397 | |||
398 | if (order_mb->request == order_mb->ack) { | ||
399 | CX18_WARN("Possibly falling behind: %s self-ack'ed our incoming" | ||
400 | " %s to EPU mailbox (sequence no. %u)\n", | ||
401 | rpu_str[rpu], rpu_str[rpu], order_mb->request); | ||
402 | dump_mb(cx, order_mb, "incoming"); | ||
403 | stale = 1; | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | * Individual EPU command processing is responsible for ack-ing | ||
408 | * a non-stale mailbox as soon as possible | ||
409 | */ | ||
410 | submit = epu_cmd_irq(cx, order, stale); | ||
411 | if (submit > 0) { | ||
412 | schedule_work(&order->work); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | |||
417 | /* | ||
418 | * Functions called from a non-interrupt, non work_queue context | ||
419 | */ | ||
420 | |||
121 | static void cx18_api_log_ack_delay(struct cx18 *cx, int msecs) | 421 | static void cx18_api_log_ack_delay(struct cx18 *cx, int msecs) |
122 | { | 422 | { |
123 | if (msecs > CX18_MAX_MB_ACK_DELAY) | 423 | if (msecs > CX18_MAX_MB_ACK_DELAY) |
@@ -167,8 +467,6 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) | |||
167 | } | 467 | } |
168 | 468 | ||
169 | mutex_lock(mb_lock); | 469 | mutex_lock(mb_lock); |
170 | cx18_setup_page(cx, SCB_OFFSET); | ||
171 | |||
172 | /* | 470 | /* |
173 | * Wait for an in-use mailbox to complete | 471 | * Wait for an in-use mailbox to complete |
174 | * | 472 | * |
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 54758f32db1e..002c0526afa0 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h | |||
@@ -37,6 +37,17 @@ | |||
37 | 37 | ||
38 | struct cx18; | 38 | struct cx18; |
39 | 39 | ||
40 | /* | ||
41 | * This structure is used by CPU to provide completed buffers information | ||
42 | * Its structure is dictrated by the layout of the SCB, required by the | ||
43 | * firmware, but its defintion needs to be here, instead of in cx18-scb.h, | ||
44 | * for mailbox work order scheduling | ||
45 | */ | ||
46 | struct cx18_mdl_ack { | ||
47 | u32 id; /* ID of a completed MDL */ | ||
48 | u32 data_used; /* Total data filled in the MDL for buffer 'id' */ | ||
49 | }; | ||
50 | |||
40 | /* The cx18_mailbox struct is the mailbox structure which is used for passing | 51 | /* The cx18_mailbox struct is the mailbox structure which is used for passing |
41 | messages between processors */ | 52 | messages between processors */ |
42 | struct cx18_mailbox { | 53 | struct cx18_mailbox { |
@@ -73,6 +84,9 @@ int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, | |||
73 | int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); | 84 | int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); |
74 | int cx18_api_func(void *priv, u32 cmd, int in, int out, | 85 | int cx18_api_func(void *priv, u32 cmd, int in, int out, |
75 | u32 data[CX2341X_MBOX_MAX_DATA]); | 86 | u32 data[CX2341X_MBOX_MAX_DATA]); |
76 | long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu); | 87 | |
88 | void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu); | ||
89 | |||
90 | void cx18_epu_work_handler(struct work_struct *work); | ||
77 | 91 | ||
78 | #endif | 92 | #endif |
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index 174682c2582f..c5a81aed61bb 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c | |||
@@ -75,30 +75,37 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) | |||
75 | return buf; | 75 | return buf; |
76 | } | 76 | } |
77 | 77 | ||
78 | struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, | 78 | struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, |
79 | u32 bytesused) | 79 | u32 bytesused) |
80 | { | 80 | { |
81 | struct cx18 *cx = s->cx; | 81 | struct cx18 *cx = s->cx; |
82 | struct list_head *p; | 82 | struct list_head *p; |
83 | unsigned long flags = 0; | ||
83 | 84 | ||
84 | spin_lock(&s->qlock); | 85 | spin_lock_irqsave(&s->qlock, flags); |
85 | list_for_each(p, &s->q_free.list) { | 86 | list_for_each(p, &s->q_free.list) { |
86 | struct cx18_buffer *buf = | 87 | struct cx18_buffer *buf = |
87 | list_entry(p, struct cx18_buffer, list); | 88 | list_entry(p, struct cx18_buffer, list); |
88 | 89 | ||
89 | if (buf->id != id) | 90 | if (buf->id != id) { |
91 | CX18_DEBUG_HI_DMA("Skipping buffer %d searching for %d " | ||
92 | "in stream %s q_free\n", buf->id, id, | ||
93 | s->name); | ||
90 | continue; | 94 | continue; |
95 | } | ||
91 | 96 | ||
92 | buf->bytesused = bytesused; | 97 | buf->bytesused = bytesused; |
93 | atomic_dec(&s->q_free.buffers); | 98 | if (s->type != CX18_ENC_STREAM_TYPE_TS) { |
94 | atomic_inc(&s->q_full.buffers); | 99 | atomic_dec(&s->q_free.buffers); |
95 | s->q_full.bytesused += buf->bytesused; | 100 | atomic_inc(&s->q_full.buffers); |
96 | list_move_tail(&buf->list, &s->q_full.list); | 101 | s->q_full.bytesused += buf->bytesused; |
102 | list_move_tail(&buf->list, &s->q_full.list); | ||
103 | } | ||
97 | 104 | ||
98 | spin_unlock(&s->qlock); | 105 | spin_unlock_irqrestore(&s->qlock, flags); |
99 | return buf; | 106 | return buf; |
100 | } | 107 | } |
101 | spin_unlock(&s->qlock); | 108 | spin_unlock_irqrestore(&s->qlock, flags); |
102 | CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); | 109 | CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); |
103 | return NULL; | 110 | return NULL; |
104 | } | 111 | } |
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index 7f93bb13c09f..92edb5e3a627 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h | |||
@@ -46,7 +46,7 @@ void cx18_queue_init(struct cx18_queue *q); | |||
46 | void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 46 | void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, |
47 | struct cx18_queue *q); | 47 | struct cx18_queue *q); |
48 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); | 48 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); |
49 | struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, | 49 | struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, |
50 | u32 bytesused); | 50 | u32 bytesused); |
51 | void cx18_flush_queues(struct cx18_stream *s); | 51 | void cx18_flush_queues(struct cx18_stream *s); |
52 | 52 | ||
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h index 594713bbed68..29866f02f018 100644 --- a/drivers/media/video/cx18/cx18-scb.h +++ b/drivers/media/video/cx18/cx18-scb.h | |||
@@ -85,12 +85,6 @@ struct cx18_mdl { | |||
85 | u32 length; /* Length of the buffer segment */ | 85 | u32 length; /* Length of the buffer segment */ |
86 | }; | 86 | }; |
87 | 87 | ||
88 | /* This structure is used by CPU to provide completed buffers information */ | ||
89 | struct cx18_mdl_ack { | ||
90 | u32 id; /* ID of a completed MDL */ | ||
91 | u32 data_used; /* Total data filled in the MDL for buffer 'id' */ | ||
92 | }; | ||
93 | |||
94 | struct cx18_scb { | 88 | struct cx18_scb { |
95 | /* These fields form the System Control Block which is used at boot time | 89 | /* These fields form the System Control Block which is used at boot time |
96 | for localizing the IPC data as well as the code positions for all | 90 | for localizing the IPC data as well as the code positions for all |
@@ -276,7 +270,7 @@ struct cx18_scb { | |||
276 | struct cx18_mailbox hpu2epu_mb; | 270 | struct cx18_mailbox hpu2epu_mb; |
277 | struct cx18_mailbox ppu2epu_mb; | 271 | struct cx18_mailbox ppu2epu_mb; |
278 | 272 | ||
279 | struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2]; | 273 | struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; |
280 | struct cx18_mdl cpu_mdl[1]; | 274 | struct cx18_mdl cpu_mdl[1]; |
281 | }; | 275 | }; |
282 | 276 | ||
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c7d431f49238..e6d808f7cc8f 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -595,3 +595,21 @@ u32 cx18_find_handle(struct cx18 *cx) | |||
595 | } | 595 | } |
596 | return CX18_INVALID_TASK_HANDLE; | 596 | return CX18_INVALID_TASK_HANDLE; |
597 | } | 597 | } |
598 | |||
599 | struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) | ||
600 | { | ||
601 | int i; | ||
602 | struct cx18_stream *s; | ||
603 | |||
604 | if (handle == CX18_INVALID_TASK_HANDLE) | ||
605 | return NULL; | ||
606 | |||
607 | for (i = 0; i < CX18_MAX_STREAMS; i++) { | ||
608 | s = &cx->streams[i]; | ||
609 | if (s->handle != handle) | ||
610 | continue; | ||
611 | if (s->v4l2dev || s->dvb.enabled) | ||
612 | return s; | ||
613 | } | ||
614 | return NULL; | ||
615 | } | ||
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index f327e947b24f..3fd578d0e6ce 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | u32 cx18_find_handle(struct cx18 *cx); | 24 | u32 cx18_find_handle(struct cx18 *cx); |
25 | struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle); | ||
25 | int cx18_streams_setup(struct cx18 *cx); | 26 | int cx18_streams_setup(struct cx18 *cx); |
26 | int cx18_streams_register(struct cx18 *cx); | 27 | int cx18_streams_register(struct cx18 *cx); |
27 | void cx18_streams_cleanup(struct cx18 *cx, int unregister); | 28 | void cx18_streams_cleanup(struct cx18 *cx, int unregister); |