diff options
author | Andy Walls <awalls@radix.net> | 2009-11-08 21:45:24 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-12-05 15:41:51 -0500 |
commit | 52fcb3ecc6707f52dfe4297f96b7609d4ba517fb (patch) | |
tree | fe8ecd66c20b10e8b2ba63c667a6afe78c23a2e1 /drivers/media/video/cx18/cx18-fileops.c | |
parent | fa655dda5ce6e5ac4a9b94fd451358edca2ddab8 (diff) |
V4L/DVB (13429): cx18: Add Memory Descriptor List (MDL) layer to buffer handling
Add a Memory Descriptor List (MDL) layer to buffer handling to implement
scatter-gather I/O. Currently there is still only 1 buffer per MDL.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-fileops.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 128 |
1 files changed, 96 insertions, 32 deletions
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index e4a3faebff46..4e278db31cc9 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -166,11 +166,12 @@ static void cx18_dualwatch(struct cx18 *cx) | |||
166 | } | 166 | } |
167 | 167 | ||
168 | 168 | ||
169 | static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err) | 169 | static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block, |
170 | int *err) | ||
170 | { | 171 | { |
171 | struct cx18 *cx = s->cx; | 172 | struct cx18 *cx = s->cx; |
172 | struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; | 173 | struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; |
173 | struct cx18_buffer *buf; | 174 | struct cx18_mdl *mdl; |
174 | DEFINE_WAIT(wait); | 175 | DEFINE_WAIT(wait); |
175 | 176 | ||
176 | *err = 0; | 177 | *err = 0; |
@@ -185,32 +186,33 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, | |||
185 | } | 186 | } |
186 | if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && | 187 | if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && |
187 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { | 188 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { |
188 | while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { | 189 | while ((mdl = cx18_dequeue(s_vbi, |
190 | &s_vbi->q_full))) { | ||
189 | /* byteswap and process VBI data */ | 191 | /* byteswap and process VBI data */ |
190 | cx18_process_vbi_data(cx, buf, | 192 | cx18_process_vbi_data(cx, mdl, |
191 | s_vbi->type); | 193 | s_vbi->type); |
192 | cx18_stream_put_buf_fw(s_vbi, buf); | 194 | cx18_stream_put_mdl_fw(s_vbi, mdl); |
193 | } | 195 | } |
194 | } | 196 | } |
195 | buf = &cx->vbi.sliced_mpeg_buf; | 197 | mdl = &cx->vbi.sliced_mpeg_mdl; |
196 | if (buf->readpos != buf->bytesused) | 198 | if (mdl->readpos != mdl->bytesused) |
197 | return buf; | 199 | return mdl; |
198 | } | 200 | } |
199 | 201 | ||
200 | /* do we have new data? */ | 202 | /* do we have new data? */ |
201 | buf = cx18_dequeue(s, &s->q_full); | 203 | mdl = cx18_dequeue(s, &s->q_full); |
202 | if (buf) { | 204 | if (mdl) { |
203 | if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP, | 205 | if (!test_and_clear_bit(CX18_F_M_NEED_SWAP, |
204 | &buf->b_flags)) | 206 | &mdl->m_flags)) |
205 | return buf; | 207 | return mdl; |
206 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) | 208 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) |
207 | /* byteswap MPG data */ | 209 | /* byteswap MPG data */ |
208 | cx18_buf_swap(buf); | 210 | cx18_mdl_swap(mdl); |
209 | else { | 211 | else { |
210 | /* byteswap and process VBI data */ | 212 | /* byteswap and process VBI data */ |
211 | cx18_process_vbi_data(cx, buf, s->type); | 213 | cx18_process_vbi_data(cx, mdl, s->type); |
212 | } | 214 | } |
213 | return buf; | 215 | return mdl; |
214 | } | 216 | } |
215 | 217 | ||
216 | /* return if end of stream */ | 218 | /* return if end of stream */ |
@@ -241,21 +243,28 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, | |||
241 | } | 243 | } |
242 | } | 244 | } |
243 | 245 | ||
244 | static void cx18_setup_sliced_vbi_buf(struct cx18 *cx) | 246 | static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx) |
245 | { | 247 | { |
248 | struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; | ||
249 | struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; | ||
246 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; | 250 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; |
247 | 251 | ||
248 | cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx]; | 252 | buf->buf = cx->vbi.sliced_mpeg_data[idx]; |
249 | cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx]; | 253 | buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; |
250 | cx->vbi.sliced_mpeg_buf.readpos = 0; | 254 | buf->readpos = 0; |
255 | |||
256 | mdl->curr_buf = NULL; | ||
257 | mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; | ||
258 | mdl->readpos = 0; | ||
251 | } | 259 | } |
252 | 260 | ||
253 | static size_t cx18_copy_buf_to_user(struct cx18_stream *s, | 261 | static size_t cx18_copy_buf_to_user(struct cx18_stream *s, |
254 | struct cx18_buffer *buf, char __user *ubuf, size_t ucount) | 262 | struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop) |
255 | { | 263 | { |
256 | struct cx18 *cx = s->cx; | 264 | struct cx18 *cx = s->cx; |
257 | size_t len = buf->bytesused - buf->readpos; | 265 | size_t len = buf->bytesused - buf->readpos; |
258 | 266 | ||
267 | *stop = false; | ||
259 | if (len > ucount) | 268 | if (len > ucount) |
260 | len = ucount; | 269 | len = ucount; |
261 | if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && | 270 | if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && |
@@ -335,7 +344,8 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, | |||
335 | /* We declare we actually found a Program Pack*/ | 344 | /* We declare we actually found a Program Pack*/ |
336 | cx->search_pack_header = 0; /* expect vid PES */ | 345 | cx->search_pack_header = 0; /* expect vid PES */ |
337 | len = (char *)q - start; | 346 | len = (char *)q - start; |
338 | cx18_setup_sliced_vbi_buf(cx); | 347 | cx18_setup_sliced_vbi_mdl(cx); |
348 | *stop = true; | ||
339 | break; | 349 | break; |
340 | } | 350 | } |
341 | } | 351 | } |
@@ -352,6 +362,60 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, | |||
352 | return len; | 362 | return len; |
353 | } | 363 | } |
354 | 364 | ||
365 | /** | ||
366 | * list_entry_is_past_end - check if a previous loop cursor is off list end | ||
367 | * @pos: the type * previously used as a loop cursor. | ||
368 | * @head: the head for your list. | ||
369 | * @member: the name of the list_struct within the struct. | ||
370 | * | ||
371 | * Check if the entry's list_head is the head of the list, thus it's not a | ||
372 | * real entry but was the loop cursor that walked past the end | ||
373 | */ | ||
374 | #define list_entry_is_past_end(pos, head, member) \ | ||
375 | (&pos->member == (head)) | ||
376 | |||
377 | static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, | ||
378 | struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) | ||
379 | { | ||
380 | size_t tot_written = 0; | ||
381 | int rc; | ||
382 | bool stop = false; | ||
383 | |||
384 | if (mdl->curr_buf == NULL) | ||
385 | mdl->curr_buf = list_first_entry(&mdl->buf_list, | ||
386 | struct cx18_buffer, list); | ||
387 | |||
388 | if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { | ||
389 | /* | ||
390 | * For some reason we've exhausted the buffers, but the MDL | ||
391 | * object still said some data was unread. | ||
392 | * Fix that and bail out. | ||
393 | */ | ||
394 | mdl->readpos = mdl->bytesused; | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { | ||
399 | |||
400 | if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) | ||
401 | continue; | ||
402 | |||
403 | rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, | ||
404 | ucount - tot_written, &stop); | ||
405 | if (rc < 0) | ||
406 | return rc; | ||
407 | mdl->readpos += rc; | ||
408 | tot_written += rc; | ||
409 | |||
410 | if (stop || /* Forced stopping point for VBI insertion */ | ||
411 | tot_written >= ucount || /* Reader request statisfied */ | ||
412 | mdl->curr_buf->readpos < mdl->curr_buf->bytesused || | ||
413 | mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ | ||
414 | break; | ||
415 | } | ||
416 | return tot_written; | ||
417 | } | ||
418 | |||
355 | static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | 419 | static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, |
356 | size_t tot_count, int non_block) | 420 | size_t tot_count, int non_block) |
357 | { | 421 | { |
@@ -373,12 +437,12 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | |||
373 | single_frame = 1; | 437 | single_frame = 1; |
374 | 438 | ||
375 | for (;;) { | 439 | for (;;) { |
376 | struct cx18_buffer *buf; | 440 | struct cx18_mdl *mdl; |
377 | int rc; | 441 | int rc; |
378 | 442 | ||
379 | buf = cx18_get_buffer(s, non_block, &rc); | 443 | mdl = cx18_get_mdl(s, non_block, &rc); |
380 | /* if there is no data available... */ | 444 | /* if there is no data available... */ |
381 | if (buf == NULL) { | 445 | if (mdl == NULL) { |
382 | /* if we got data, then return that regardless */ | 446 | /* if we got data, then return that regardless */ |
383 | if (tot_written) | 447 | if (tot_written) |
384 | break; | 448 | break; |
@@ -392,20 +456,20 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | |||
392 | return rc; | 456 | return rc; |
393 | } | 457 | } |
394 | 458 | ||
395 | rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written, | 459 | rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written, |
396 | tot_count - tot_written); | 460 | tot_count - tot_written); |
397 | 461 | ||
398 | if (buf != &cx->vbi.sliced_mpeg_buf) { | 462 | if (mdl != &cx->vbi.sliced_mpeg_mdl) { |
399 | if (buf->readpos == buf->bytesused) | 463 | if (mdl->readpos == mdl->bytesused) |
400 | cx18_stream_put_buf_fw(s, buf); | 464 | cx18_stream_put_mdl_fw(s, mdl); |
401 | else | 465 | else |
402 | cx18_push(s, buf, &s->q_full); | 466 | cx18_push(s, mdl, &s->q_full); |
403 | } else if (buf->readpos == buf->bytesused) { | 467 | } else if (mdl->readpos == mdl->bytesused) { |
404 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; | 468 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; |
405 | 469 | ||
406 | cx->vbi.sliced_mpeg_size[idx] = 0; | 470 | cx->vbi.sliced_mpeg_size[idx] = 0; |
407 | cx->vbi.inserted_frame++; | 471 | cx->vbi.inserted_frame++; |
408 | cx->vbi_data_inserted += buf->bytesused; | 472 | cx->vbi_data_inserted += mdl->bytesused; |
409 | } | 473 | } |
410 | if (rc < 0) | 474 | if (rc < 0) |
411 | return rc; | 475 | return rc; |