diff options
author | Mike Isely <isely@pobox.com> | 2008-02-03 22:00:19 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:46 -0400 |
commit | bb8ce9d9143c0fe2b5cdf65fa41250446805a4be (patch) | |
tree | d406516b4eaed4de2c999cb804b0b8f17f3e7529 | |
parent | d8abe97d0063cf77e9bbbee076181e4657c7e09c (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.c | 187 |
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 | ||
27 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 29 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
28 | 30 | ||
31 | #define BUFFER_COUNT 32 | ||
32 | #define BUFFER_SIZE PAGE_ALIGN(0x4000) | ||
33 | |||
34 | struct 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 | |||
42 | static void pvr2_dvb_notify(struct pvr2_dvb_fh *fhp) | ||
43 | { | ||
44 | wake_up(&fhp->wait_data); | ||
45 | } | ||
46 | |||
47 | static 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 | |||
106 | cleanup: | ||
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 | |||
121 | static 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 | |||
141 | static 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 | |||
29 | static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) | 214 | static 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; |