aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2008-02-03 22:00:19 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:09:46 -0400
commitbb8ce9d9143c0fe2b5cdf65fa41250446805a4be (patch)
treed406516b4eaed4de2c999cb804b0b8f17f3e7529
parentd8abe97d0063cf77e9bbbee076181e4657c7e09c (diff)
V4L/DVB (7682): pvrusb2-dvb: finish up stream & buffer handling
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-dvb.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
index c85477709e6e..bde85c973058 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -19,13 +19,198 @@
19 */ 19 */
20 20
21#include <linux/kthread.h> 21#include <linux/kthread.h>
22#include <linux/freezer.h>
22#include "dvbdev.h" 23#include "dvbdev.h"
23#include "pvrusb2-hdw-internal.h" 24#include "pvrusb2-hdw-internal.h"
24#include "pvrusb2-hdw.h" 25#include "pvrusb2-hdw.h"
26#include "pvrusb2-io.h"
25#include "pvrusb2-dvb.h" 27#include "pvrusb2-dvb.h"
26 28
27DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 29DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
28 30
31#define BUFFER_COUNT 32
32#define BUFFER_SIZE PAGE_ALIGN(0x4000)
33
34struct pvr2_dvb_fh {
35 struct pvr2_channel channel;
36 struct pvr2_stream *stream;
37 struct pvr2_dvb_adapter *adap;
38 wait_queue_head_t wait_data;
39 char *buffer_storage[BUFFER_COUNT];
40};
41
42static void pvr2_dvb_notify(struct pvr2_dvb_fh *fhp)
43{
44 wake_up(&fhp->wait_data);
45}
46
47static int pvr2_dvb_fh_init(struct pvr2_dvb_fh *fh,
48 struct pvr2_dvb_adapter *adap)
49{
50 struct pvr2_context *pvr = adap->pvr;
51 unsigned int idx;
52 int ret;
53 struct pvr2_buffer *bp;
54
55 init_waitqueue_head(&fh->wait_data);
56
57 fh->adap = adap;
58
59 pvr2_channel_init(&fh->channel, adap->pvr);
60
61 ret = pvr2_channel_claim_stream(&fh->channel, &pvr->video_stream);
62 /* somebody else already has the stream */
63 if (ret != 0)
64 return ret;
65
66 fh->stream = pvr->video_stream.stream;
67
68 for (idx = 0; idx < BUFFER_COUNT; idx++) {
69 fh->buffer_storage[idx] = kmalloc(BUFFER_SIZE, GFP_KERNEL);
70 if (!(fh->buffer_storage[idx]))
71 break;
72 }
73
74 if (idx < BUFFER_COUNT) {
75 /* An allocation appears to have failed */
76 ret = -ENOMEM;
77 goto cleanup;
78 }
79
80 pvr2_stream_set_callback(pvr->video_stream.stream,
81 (pvr2_stream_callback) pvr2_dvb_notify, fh);
82
83 ret = pvr2_stream_set_buffer_count(fh->stream, BUFFER_COUNT);
84 if (ret < 0)
85 return ret;
86
87 for (idx = 0; idx < BUFFER_COUNT; idx++) {
88 bp = pvr2_stream_get_buffer(fh->stream, idx);
89 pvr2_buffer_set_buffer(bp,
90 fh->buffer_storage[idx],
91 BUFFER_SIZE);
92 }
93
94 ret = pvr2_hdw_set_streaming(fh->channel.hdw, 1);
95 if (ret < 0)
96 goto cleanup;
97
98 while ((bp = pvr2_stream_get_idle_buffer(fh->stream)) != 0) {
99 ret = pvr2_buffer_queue(bp);
100 if (ret < 0)
101 goto cleanup;
102 }
103
104 return ret;
105
106cleanup:
107 if (fh->stream)
108 pvr2_stream_kill(fh->stream);
109
110 for (idx = 0; idx < BUFFER_COUNT; idx++) {
111 if (!(fh->buffer_storage[idx]))
112 continue;
113
114 kfree(fh->buffer_storage[idx]);
115 }
116 pvr2_channel_done(&fh->channel);
117
118 return ret;
119}
120
121static void pvr2_dvb_fh_done(struct pvr2_dvb_fh *fh)
122{
123 unsigned int idx;
124
125 pvr2_hdw_set_streaming(fh->channel.hdw, 0);
126
127 pvr2_stream_kill(fh->stream);
128
129// pvr2_channel_claim_stream(&fh->channel, NULL);
130
131 for (idx = 0; idx < BUFFER_COUNT; idx++) {
132 if (!(fh->buffer_storage[idx]))
133 continue;
134
135 kfree(fh->buffer_storage[idx]);
136 }
137
138 pvr2_channel_done(&fh->channel);
139}
140
141static int pvr2_dvb_feed_thread(void *data)
142{
143 struct pvr2_dvb_adapter *adap = data;
144 struct pvr2_dvb_fh fh;
145 int ret;
146 unsigned int count;
147 struct pvr2_buffer *bp;
148
149 printk(KERN_DEBUG "dvb thread started\n");
150 set_freezable();
151
152 memset(&fh, 0, sizeof(fh));
153
154 ret = pvr2_dvb_fh_init(&fh, adap);
155 if (ret != 0)
156 return ret;
157
158 for (;;) {
159 if ((0 == adap->feedcount) || (kthread_should_stop()))
160 break;
161
162 /* Not sure about this... */
163 try_to_freeze();
164
165 bp = pvr2_stream_get_ready_buffer(fh.stream);
166 if (bp != NULL) {
167 count = pvr2_buffer_get_count(bp);
168 if (count) {
169 dvb_dmx_swfilter(
170 &adap->demux,
171 fh.buffer_storage[
172 pvr2_buffer_get_id(bp)],
173 count);
174 } else {
175 ret = pvr2_buffer_get_status(bp);
176 if (ret < 0)
177 break;
178 }
179 ret = pvr2_buffer_queue(bp);
180 if (ret < 0)
181 break;
182
183 /* Since we know we did something to a buffer,
184 just go back and try again. No point in
185 blocking unless we really ran out of
186 buffers to process. */
187 continue;
188 }
189
190
191 /* Wait until more buffers become available. */
192 ret = wait_event_interruptible(
193 fh.wait_data,
194 pvr2_stream_get_ready_count(fh.stream) > 0);
195 if (ret < 0)
196 break;
197 }
198
199 pvr2_dvb_fh_done(&fh);
200
201 /* If we get here and ret is < 0, then an error has occurred.
202 Probably would be a good idea to communicate that to DVB core... */
203
204 printk(KERN_DEBUG "dvb thread stopped\n");
205
206 /* from videobuf-dvb.c: */
207 while (!kthread_should_stop()) {
208 set_current_state(TASK_INTERRUPTIBLE);
209 schedule();
210 }
211 return 0;
212}
213
29static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) 214static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
30{ 215{
31 struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; 216 struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv;
@@ -52,6 +237,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
52 237
53 printk(KERN_DEBUG "start feeding\n"); 238 printk(KERN_DEBUG "start feeding\n");
54 239
240 adap->thread = kthread_run(pvr2_dvb_feed_thread,
241 adap, "pvrusb2-dvb");
55 if (IS_ERR(adap->thread)) { 242 if (IS_ERR(adap->thread)) {
56 ret = PTR_ERR(adap->thread); 243 ret = PTR_ERR(adap->thread);
57 adap->thread = NULL; 244 adap->thread = NULL;