aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-fileops.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-11-08 21:45:24 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:41:51 -0500
commit52fcb3ecc6707f52dfe4297f96b7609d4ba517fb (patch)
treefe8ecd66c20b10e8b2ba63c667a6afe78c23a2e1 /drivers/media/video/cx18/cx18-fileops.c
parentfa655dda5ce6e5ac4a9b94fd451358edca2ddab8 (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.c128
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
169static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err) 169static 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
244static void cx18_setup_sliced_vbi_buf(struct cx18 *cx) 246static 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
253static size_t cx18_copy_buf_to_user(struct cx18_stream *s, 261static 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
377static 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
355static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, 419static 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;