diff options
author | Mike Isely <isely@pobox.com> | 2008-02-06 04:59:48 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:46 -0400 |
commit | a36416d0a70899d3724d2e69e378062e06252a41 (patch) | |
tree | bdfa46e80e1d304f0817749a61d80e49f995ddbd /drivers | |
parent | ceb4340deb9bf5f8371d47ef906a83e6784345b0 (diff) |
V4L/DVB (7688): pvrusb2: Clean up dvb streaming start/stop
Eliminate the need for a separate pvr2_dvb_fh; since in the DVB
context there can only ever be a single instance then there is no need
for a separate instance to handle streaming state. This simplifies
the module. Also move streaming start/stop out of the feed thread and
into the driver's main context - which makes it possible for streaming
start up failures to be detected by the DVB core.
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-dvb.c | 306 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-dvb.h | 10 |
2 files changed, 148 insertions, 168 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index dd693a1980e8..ab608412b41e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c | |||
@@ -28,156 +28,39 @@ | |||
28 | 28 | ||
29 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 29 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
30 | 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_func(struct pvr2_dvb_adapter *adap) | 31 | static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) |
142 | { | 32 | { |
143 | struct pvr2_dvb_fh fh; | ||
144 | int ret; | 33 | int ret; |
145 | unsigned int count; | 34 | unsigned int count; |
146 | struct pvr2_buffer *bp; | 35 | struct pvr2_buffer *bp; |
36 | struct pvr2_stream *stream; | ||
147 | 37 | ||
148 | printk(KERN_DEBUG "dvb thread started\n"); | 38 | printk(KERN_DEBUG "dvb thread started\n"); |
149 | set_freezable(); | 39 | set_freezable(); |
150 | 40 | ||
151 | memset(&fh, 0, sizeof(fh)); | 41 | stream = adap->channel.stream->stream; |
152 | |||
153 | ret = pvr2_dvb_fh_init(&fh, adap); | ||
154 | if (ret != 0) | ||
155 | return ret; | ||
156 | 42 | ||
157 | for (;;) { | 43 | for (;;) { |
158 | if ((0 == adap->feedcount) || (kthread_should_stop())) | 44 | if (kthread_should_stop()) break; |
159 | break; | ||
160 | 45 | ||
161 | /* Not sure about this... */ | 46 | /* Not sure about this... */ |
162 | try_to_freeze(); | 47 | try_to_freeze(); |
163 | 48 | ||
164 | bp = pvr2_stream_get_ready_buffer(fh.stream); | 49 | bp = pvr2_stream_get_ready_buffer(stream); |
165 | if (bp != NULL) { | 50 | if (bp != NULL) { |
166 | count = pvr2_buffer_get_count(bp); | 51 | count = pvr2_buffer_get_count(bp); |
167 | if (count) { | 52 | if (count) { |
168 | dvb_dmx_swfilter( | 53 | dvb_dmx_swfilter( |
169 | &adap->demux, | 54 | &adap->demux, |
170 | fh.buffer_storage[ | 55 | adap->buffer_storage[ |
171 | pvr2_buffer_get_id(bp)], | 56 | pvr2_buffer_get_id(bp)], |
172 | count); | 57 | count); |
173 | } else { | 58 | } else { |
174 | ret = pvr2_buffer_get_status(bp); | 59 | ret = pvr2_buffer_get_status(bp); |
175 | if (ret < 0) | 60 | if (ret < 0) break; |
176 | break; | ||
177 | } | 61 | } |
178 | ret = pvr2_buffer_queue(bp); | 62 | ret = pvr2_buffer_queue(bp); |
179 | if (ret < 0) | 63 | if (ret < 0) break; |
180 | break; | ||
181 | 64 | ||
182 | /* Since we know we did something to a buffer, | 65 | /* Since we know we did something to a buffer, |
183 | just go back and try again. No point in | 66 | just go back and try again. No point in |
@@ -189,14 +72,11 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) | |||
189 | 72 | ||
190 | /* Wait until more buffers become available. */ | 73 | /* Wait until more buffers become available. */ |
191 | ret = wait_event_interruptible( | 74 | ret = wait_event_interruptible( |
192 | fh.wait_data, | 75 | adap->buffer_wait_data, |
193 | pvr2_stream_get_ready_count(fh.stream) > 0); | 76 | pvr2_stream_get_ready_count(stream) > 0); |
194 | if (ret < 0) | 77 | if (ret < 0) break; |
195 | break; | ||
196 | } | 78 | } |
197 | 79 | ||
198 | pvr2_dvb_fh_done(&fh); | ||
199 | |||
200 | /* If we get here and ret is < 0, then an error has occurred. | 80 | /* If we get here and ret is < 0, then an error has occurred. |
201 | Probably would be a good idea to communicate that to DVB core... */ | 81 | Probably would be a good idea to communicate that to DVB core... */ |
202 | 82 | ||
@@ -216,41 +96,131 @@ static int pvr2_dvb_feed_thread(void *data) | |||
216 | return stat; | 96 | return stat; |
217 | } | 97 | } |
218 | 98 | ||
219 | static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) | 99 | static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap) |
220 | { | 100 | { |
221 | struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; | 101 | wake_up(&adap->buffer_wait_data); |
222 | int newfeedcount, ret = 0; | 102 | } |
223 | 103 | ||
224 | if (adap == NULL) | 104 | static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) |
225 | return -ENODEV; | 105 | { |
106 | unsigned int idx; | ||
107 | struct pvr2_stream *stream; | ||
226 | 108 | ||
227 | mutex_lock(&adap->lock); | 109 | if (adap->thread) { |
228 | newfeedcount = adap->feedcount + (onoff ? 1 : -1); | 110 | kthread_stop(adap->thread); |
111 | adap->thread = NULL; | ||
112 | } | ||
113 | |||
114 | if (adap->channel.stream) { | ||
115 | stream = adap->channel.stream->stream; | ||
116 | } else { | ||
117 | stream = NULL; | ||
118 | } | ||
119 | if (stream) { | ||
120 | pvr2_hdw_set_streaming(adap->channel.hdw, 0); | ||
121 | pvr2_stream_set_callback(stream, NULL, NULL); | ||
122 | pvr2_stream_kill(stream); | ||
123 | pvr2_stream_set_buffer_count(stream, 0); | ||
124 | pvr2_channel_claim_stream(&adap->channel, NULL); | ||
125 | } | ||
126 | |||
127 | if (adap->stream_run) { | ||
128 | for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { | ||
129 | if (!(adap->buffer_storage[idx])) continue; | ||
130 | kfree(adap->buffer_storage[idx]); | ||
131 | adap->buffer_storage[idx] = 0; | ||
132 | } | ||
133 | adap->stream_run = 0; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) | ||
138 | { | ||
139 | struct pvr2_context *pvr = adap->channel.mc_head; | ||
140 | unsigned int idx; | ||
141 | int ret; | ||
142 | struct pvr2_buffer *bp; | ||
143 | struct pvr2_stream *stream = 0; | ||
144 | |||
145 | if (adap->stream_run) return -EIO; | ||
146 | |||
147 | ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream); | ||
148 | /* somebody else already has the stream */ | ||
149 | if (ret < 0) return ret; | ||
150 | |||
151 | stream = adap->channel.stream->stream; | ||
152 | |||
153 | for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { | ||
154 | adap->buffer_storage[idx] = kmalloc(PVR2_DVB_BUFFER_SIZE, | ||
155 | GFP_KERNEL); | ||
156 | if (!(adap->buffer_storage[idx])) return -ENOMEM; | ||
157 | } | ||
158 | |||
159 | pvr2_stream_set_callback(pvr->video_stream.stream, | ||
160 | (pvr2_stream_callback) pvr2_dvb_notify, adap); | ||
161 | |||
162 | ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT); | ||
163 | if (ret < 0) return ret; | ||
229 | 164 | ||
230 | if (newfeedcount == 0) { | 165 | for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { |
231 | printk(KERN_DEBUG "stop feeding\n"); | 166 | bp = pvr2_stream_get_buffer(stream, idx); |
167 | pvr2_buffer_set_buffer(bp, | ||
168 | adap->buffer_storage[idx], | ||
169 | PVR2_DVB_BUFFER_SIZE); | ||
170 | } | ||
171 | |||
172 | ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1); | ||
173 | if (ret < 0) return ret; | ||
174 | |||
175 | while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) { | ||
176 | ret = pvr2_buffer_queue(bp); | ||
177 | if (ret < 0) return ret; | ||
178 | } | ||
232 | 179 | ||
233 | ret = kthread_stop(adap->thread); | 180 | adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb"); |
181 | |||
182 | if (IS_ERR(adap->thread)) { | ||
183 | ret = PTR_ERR(adap->thread); | ||
234 | adap->thread = NULL; | 184 | adap->thread = NULL; |
185 | return ret; | ||
235 | } | 186 | } |
236 | 187 | ||
237 | adap->feedcount = newfeedcount; | 188 | adap->stream_run = !0; |
238 | 189 | ||
239 | if (adap->feedcount == onoff && adap->feedcount > 0) { | 190 | return 0; |
240 | if (NULL != adap->thread) | 191 | } |
241 | goto fail; | ||
242 | 192 | ||
243 | printk(KERN_DEBUG "start feeding\n"); | 193 | static int pvr2_dvb_stream_start(struct pvr2_dvb_adapter *adap) |
194 | { | ||
195 | int ret = pvr2_dvb_stream_do_start(adap); | ||
196 | if (ret < 0) pvr2_dvb_stream_end(adap); | ||
197 | return ret; | ||
198 | } | ||
244 | 199 | ||
245 | adap->thread = kthread_run(pvr2_dvb_feed_thread, | 200 | static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) |
246 | adap, "pvrusb2-dvb"); | 201 | { |
247 | if (IS_ERR(adap->thread)) { | 202 | struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; |
248 | ret = PTR_ERR(adap->thread); | 203 | int ret = 0; |
249 | adap->thread = NULL; | 204 | |
205 | if (adap == NULL) return -ENODEV; | ||
206 | |||
207 | mutex_lock(&adap->lock); | ||
208 | do { | ||
209 | if (onoff) { | ||
210 | if (!adap->feedcount) { | ||
211 | printk(KERN_DEBUG "start feeding\n"); | ||
212 | ret = pvr2_dvb_stream_start(adap); | ||
213 | if (ret < 0) break; | ||
214 | } | ||
215 | (adap->feedcount)++; | ||
216 | } else if (adap->feedcount > 0) { | ||
217 | (adap->feedcount)--; | ||
218 | if (!adap->feedcount) { | ||
219 | printk(KERN_DEBUG "stop feeding\n"); | ||
220 | pvr2_dvb_stream_end(adap); | ||
221 | } | ||
250 | } | 222 | } |
251 | //ret = newfeedcount; | 223 | } while (0); |
252 | } | ||
253 | fail: | ||
254 | mutex_unlock(&adap->lock); | 224 | mutex_unlock(&adap->lock); |
255 | 225 | ||
256 | return ret; | 226 | return ret; |
@@ -287,7 +257,7 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) | |||
287 | 257 | ||
288 | ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb", | 258 | ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb", |
289 | THIS_MODULE/*&hdw->usb_dev->owner*/, | 259 | THIS_MODULE/*&hdw->usb_dev->owner*/, |
290 | &adap->pvr->hdw->usb_dev->dev, | 260 | &adap->channel.hdw->usb_dev->dev, |
291 | adapter_nr); | 261 | adapter_nr); |
292 | if (ret < 0) { | 262 | if (ret < 0) { |
293 | err("dvb_register_adapter failed: error %d", ret); | 263 | err("dvb_register_adapter failed: error %d", ret); |
@@ -351,7 +321,7 @@ static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) | |||
351 | 321 | ||
352 | static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) | 322 | static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) |
353 | { | 323 | { |
354 | struct pvr2_hdw *hdw = adap->pvr->hdw; | 324 | struct pvr2_hdw *hdw = adap->channel.hdw; |
355 | struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; | 325 | struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; |
356 | int ret; | 326 | int ret; |
357 | 327 | ||
@@ -419,14 +389,14 @@ static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) | |||
419 | int pvr2_dvb_init(struct pvr2_context *pvr) | 389 | int pvr2_dvb_init(struct pvr2_context *pvr) |
420 | { | 390 | { |
421 | int ret = 0; | 391 | int ret = 0; |
422 | 392 | struct pvr2_dvb_adapter *adap; | |
423 | pvr->hdw->dvb.pvr = pvr; | 393 | adap = &pvr->hdw->dvb; |
394 | adap->init = !0; | ||
395 | pvr2_channel_init(&adap->channel, pvr); | ||
396 | init_waitqueue_head(&adap->buffer_wait_data); | ||
424 | mutex_init(&pvr->hdw->dvb.lock); | 397 | mutex_init(&pvr->hdw->dvb.lock); |
425 | |||
426 | ret = pvr2_dvb_adapter_init(&pvr->hdw->dvb); | 398 | ret = pvr2_dvb_adapter_init(&pvr->hdw->dvb); |
427 | if (ret < 0) | 399 | if (ret < 0) goto fail; |
428 | goto fail; | ||
429 | |||
430 | ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); | 400 | ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); |
431 | fail: | 401 | fail: |
432 | return ret; | 402 | return ret; |
@@ -434,10 +404,12 @@ fail: | |||
434 | 404 | ||
435 | int pvr2_dvb_exit(struct pvr2_context *pvr) | 405 | int pvr2_dvb_exit(struct pvr2_context *pvr) |
436 | { | 406 | { |
437 | pvr2_dvb_frontend_exit(&pvr->hdw->dvb); | 407 | struct pvr2_dvb_adapter *adap; |
438 | pvr2_dvb_adapter_exit(&pvr->hdw->dvb); | 408 | adap = &pvr->hdw->dvb; |
439 | 409 | if (!adap->init) return 0; | |
440 | pvr->hdw->dvb.pvr = NULL; | 410 | pvr2_dvb_stream_end(adap); |
441 | 411 | pvr2_dvb_frontend_exit(adap); | |
412 | pvr2_dvb_adapter_exit(adap); | ||
413 | pvr2_channel_done(&adap->channel); | ||
442 | return 0; | 414 | return 0; |
443 | } | 415 | } |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index 98728d44a4b6..651324ffab3d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h | |||
@@ -7,8 +7,11 @@ | |||
7 | #include "dmxdev.h" | 7 | #include "dmxdev.h" |
8 | #include "pvrusb2-context.h" | 8 | #include "pvrusb2-context.h" |
9 | 9 | ||
10 | #define PVR2_DVB_BUFFER_COUNT 32 | ||
11 | #define PVR2_DVB_BUFFER_SIZE PAGE_ALIGN(0x4000) | ||
12 | |||
10 | struct pvr2_dvb_adapter { | 13 | struct pvr2_dvb_adapter { |
11 | struct pvr2_context *pvr; | 14 | struct pvr2_channel channel; |
12 | 15 | ||
13 | struct dvb_adapter dvb_adap; | 16 | struct dvb_adapter dvb_adap; |
14 | struct dmxdev dmxdev; | 17 | struct dmxdev dmxdev; |
@@ -23,6 +26,11 @@ struct pvr2_dvb_adapter { | |||
23 | struct mutex lock; | 26 | struct mutex lock; |
24 | 27 | ||
25 | unsigned int digital_up:1; | 28 | unsigned int digital_up:1; |
29 | unsigned int stream_run:1; | ||
30 | unsigned int init:1; | ||
31 | |||
32 | wait_queue_head_t buffer_wait_data; | ||
33 | char *buffer_storage[PVR2_DVB_BUFFER_COUNT]; | ||
26 | }; | 34 | }; |
27 | 35 | ||
28 | struct pvr2_dvb_props { | 36 | struct pvr2_dvb_props { |