diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:50:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:50:49 -0500 |
commit | 3e7468313758913c5e4d372f35b271b96bad1298 (patch) | |
tree | eb612d252a9e2349a1173451cd779beebd18a33e /drivers/media/video/cx18 | |
parent | 6825fbc4cb219f2c98bb7d157915d797cf5cb823 (diff) | |
parent | e97f4677961f68e29bd906022ebf60a6df7f530a (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (345 commits)
V4L/DVB (13542): ir-keytable: Allow dynamic table change
V4L/DVB (13541): atbm8830: replace 64-bit division and floating point usage
V4L/DVB (13540): ir-common: Cleanup get key evdev code
V4L/DVB (13539): ir-common: add __func__ for debug messages
V4L/DVB (13538): ir-common: Use a dynamic keycode table
V4L/DVB (13537): ir: Prepare the code for dynamic keycode table allocation
V4L/DVB (13536): em28xx: Use the full RC5 code on HVR-950 Remote Controller
V4L/DVB (13535): ir-common: Add a hauppauge new table with the complete RC5 code
V4L/DVB (13534): ir-common: Remove some unused fields/structs
V4L/DVB (13533): ir: use dynamic tables, instead of static ones
V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table
V4L/DVB (13531): ir-common: rename the debug routine to allow exporting it
V4L/DVB (13458): go7007: subdev conversion
V4L/DVB (13457): s2250: subdev conversion
V4L/DVB (13456): s2250: Change module structure
V4L/DVB (13528): em28xx: add support for em2800 VC211A card
em28xx: don't reduce scale to half size for em2800
em28xx: don't load audio modules when AC97 is mis-detected
em28xx: em2800 chips support max width of 640
V4L/DVB (13523): dvb-bt8xx: fix compile warning
...
Fix up trivial conflicts due to spelling fixes from the trivial tree in
Documentation/video4linux/gspca.txt
drivers/media/video/cx18/cx18-mailbox.h
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r-- | drivers/media/video/cx18/cx18-av-core.c | 14 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-cards.h | 3 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 60 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 62 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.c | 9 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 132 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-i2c.c | 25 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 3 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 62 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.h | 6 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.c | 346 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.h | 41 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-scb.h | 4 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 92 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.h | 10 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-vbi.c | 35 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-vbi.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-version.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx23418.h | 2 |
19 files changed, 666 insertions, 244 deletions
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 536dedb23ba3..4392c76af5df 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c | |||
@@ -99,10 +99,8 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, | |||
99 | or_value); | 99 | or_value); |
100 | } | 100 | } |
101 | 101 | ||
102 | static int cx18_av_init(struct v4l2_subdev *sd, u32 val) | 102 | static void cx18_av_init(struct cx18 *cx) |
103 | { | 103 | { |
104 | struct cx18 *cx = v4l2_get_subdevdata(sd); | ||
105 | |||
106 | /* | 104 | /* |
107 | * The crystal freq used in calculations in this driver will be | 105 | * The crystal freq used in calculations in this driver will be |
108 | * 28.636360 MHz. | 106 | * 28.636360 MHz. |
@@ -125,7 +123,6 @@ static int cx18_av_init(struct v4l2_subdev *sd, u32 val) | |||
125 | 123 | ||
126 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ | 124 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ |
127 | cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); | 125 | cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); |
128 | return 0; | ||
129 | } | 126 | } |
130 | 127 | ||
131 | static void cx18_av_initialize(struct v4l2_subdev *sd) | 128 | static void cx18_av_initialize(struct v4l2_subdev *sd) |
@@ -198,7 +195,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) | |||
198 | cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); | 195 | cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); |
199 | 196 | ||
200 | /* Setup the Video and and Aux/Audio PLLs */ | 197 | /* Setup the Video and and Aux/Audio PLLs */ |
201 | cx18_av_init(sd, 0); | 198 | cx18_av_init(cx); |
202 | 199 | ||
203 | /* set video to auto-detect */ | 200 | /* set video to auto-detect */ |
204 | /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ | 201 | /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ |
@@ -1355,7 +1352,6 @@ static int cx18_av_s_register(struct v4l2_subdev *sd, | |||
1355 | static const struct v4l2_subdev_core_ops cx18_av_general_ops = { | 1352 | static const struct v4l2_subdev_core_ops cx18_av_general_ops = { |
1356 | .g_chip_ident = cx18_av_g_chip_ident, | 1353 | .g_chip_ident = cx18_av_g_chip_ident, |
1357 | .log_status = cx18_av_log_status, | 1354 | .log_status = cx18_av_log_status, |
1358 | .init = cx18_av_init, | ||
1359 | .load_fw = cx18_av_load_fw, | 1355 | .load_fw = cx18_av_load_fw, |
1360 | .reset = cx18_av_reset, | 1356 | .reset = cx18_av_reset, |
1361 | .queryctrl = cx18_av_queryctrl, | 1357 | .queryctrl = cx18_av_queryctrl, |
@@ -1399,6 +1395,7 @@ int cx18_av_probe(struct cx18 *cx) | |||
1399 | { | 1395 | { |
1400 | struct cx18_av_state *state = &cx->av_state; | 1396 | struct cx18_av_state *state = &cx->av_state; |
1401 | struct v4l2_subdev *sd; | 1397 | struct v4l2_subdev *sd; |
1398 | int err; | ||
1402 | 1399 | ||
1403 | state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; | 1400 | state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; |
1404 | state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) | 1401 | state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) |
@@ -1417,5 +1414,8 @@ int cx18_av_probe(struct cx18 *cx) | |||
1417 | snprintf(sd->name, sizeof(sd->name), | 1414 | snprintf(sd->name, sizeof(sd->name), |
1418 | "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); | 1415 | "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); |
1419 | sd->grp_id = CX18_HW_418_AV; | 1416 | sd->grp_id = CX18_HW_418_AV; |
1420 | return v4l2_device_register_subdev(&cx->v4l2_dev, sd); | 1417 | err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); |
1418 | if (!err) | ||
1419 | cx18_av_init(cx); | ||
1420 | return err; | ||
1421 | } | 1421 | } |
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index 444e3c7c563e..af3d71607dc9 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h | |||
@@ -34,6 +34,9 @@ | |||
34 | #define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \ | 34 | #define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \ |
35 | CX18_HW_Z8F0811_IR_TX_HAUP) | 35 | CX18_HW_Z8F0811_IR_TX_HAUP) |
36 | 36 | ||
37 | #define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \ | ||
38 | CX18_HW_Z8F0811_IR_TX_HAUP) | ||
39 | |||
37 | /* video inputs */ | 40 | /* video inputs */ |
38 | #define CX18_CARD_INPUT_VID_TUNER 1 | 41 | #define CX18_CARD_INPUT_VID_TUNER 1 |
39 | #define CX18_CARD_INPUT_SVIDEO1 2 | 42 | #define CX18_CARD_INPUT_SVIDEO1 2 |
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index e12082b8a08d..7f65a47f12e1 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -87,7 +87,6 @@ static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; | |||
87 | static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; | 87 | static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; |
88 | static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; | 88 | static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; |
89 | static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; | 89 | static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; |
90 | /* VBI bufsize based on standards supported by card tuner for now */ | ||
91 | static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; | 90 | static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; |
92 | 91 | ||
93 | static int enc_ts_bufs = -1; | 92 | static int enc_ts_bufs = -1; |
@@ -128,7 +127,6 @@ module_param(enc_ts_bufsize, int, 0644); | |||
128 | module_param(enc_mpg_bufsize, int, 0644); | 127 | module_param(enc_mpg_bufsize, int, 0644); |
129 | module_param(enc_idx_bufsize, int, 0644); | 128 | module_param(enc_idx_bufsize, int, 0644); |
130 | module_param(enc_yuv_bufsize, int, 0644); | 129 | module_param(enc_yuv_bufsize, int, 0644); |
131 | /* VBI bufsize based on standards supported by card tuner for now */ | ||
132 | module_param(enc_pcm_bufsize, int, 0644); | 130 | module_param(enc_pcm_bufsize, int, 0644); |
133 | 131 | ||
134 | module_param(enc_ts_bufs, int, 0644); | 132 | module_param(enc_ts_bufs, int, 0644); |
@@ -211,7 +209,9 @@ MODULE_PARM_DESC(enc_yuv_buffers, | |||
211 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); | 209 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); |
212 | MODULE_PARM_DESC(enc_yuv_bufsize, | 210 | MODULE_PARM_DESC(enc_yuv_bufsize, |
213 | "Size of an encoder YUV buffer (kB)\n" | 211 | "Size of an encoder YUV buffer (kB)\n" |
214 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE)); | 212 | "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n" |
213 | "\t\t\t(multiples of size required for 32 screen lines)\n" | ||
214 | "\t\t\tDefault: 102"); | ||
215 | MODULE_PARM_DESC(enc_yuv_bufs, | 215 | MODULE_PARM_DESC(enc_yuv_bufs, |
216 | "Number of encoder YUV buffers\n" | 216 | "Number of encoder YUV buffers\n" |
217 | "\t\t\tDefault is computed from other enc_yuv_* parameters"); | 217 | "\t\t\tDefault is computed from other enc_yuv_* parameters"); |
@@ -220,7 +220,7 @@ MODULE_PARM_DESC(enc_vbi_buffers, | |||
220 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); | 220 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); |
221 | MODULE_PARM_DESC(enc_vbi_bufs, | 221 | MODULE_PARM_DESC(enc_vbi_bufs, |
222 | "Number of encoder VBI buffers\n" | 222 | "Number of encoder VBI buffers\n" |
223 | "\t\t\tDefault is computed from enc_vbi_buffers & tuner std"); | 223 | "\t\t\tDefault is computed from enc_vbi_buffers"); |
224 | MODULE_PARM_DESC(enc_pcm_buffers, | 224 | MODULE_PARM_DESC(enc_pcm_buffers, |
225 | "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" | 225 | "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" |
226 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); | 226 | "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); |
@@ -499,10 +499,27 @@ static void cx18_process_options(struct cx18 *cx) | |||
499 | continue; | 499 | continue; |
500 | } | 500 | } |
501 | /* | 501 | /* |
502 | * YUV is a special case where the stream_buf_size needs to be | ||
503 | * an integral multiple of 33.75 kB (storage for 32 screens | ||
504 | * lines to maintain alignment in case of lost buffers | ||
505 | */ | ||
506 | if (i == CX18_ENC_STREAM_TYPE_YUV) { | ||
507 | cx->stream_buf_size[i] *= 1024; | ||
508 | cx->stream_buf_size[i] -= | ||
509 | (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE); | ||
510 | |||
511 | if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE) | ||
512 | cx->stream_buf_size[i] = | ||
513 | CX18_UNIT_ENC_YUV_BUFSIZE; | ||
514 | } | ||
515 | /* | ||
516 | * YUV is a special case where the stream_buf_size is | ||
517 | * now in bytes. | ||
502 | * VBI is a special case where the stream_buf_size is fixed | 518 | * VBI is a special case where the stream_buf_size is fixed |
503 | * and already in bytes | 519 | * and already in bytes |
504 | */ | 520 | */ |
505 | if (i == CX18_ENC_STREAM_TYPE_VBI) { | 521 | if (i == CX18_ENC_STREAM_TYPE_VBI || |
522 | i == CX18_ENC_STREAM_TYPE_YUV) { | ||
506 | if (cx->stream_buffers[i] < 0) { | 523 | if (cx->stream_buffers[i] < 0) { |
507 | cx->stream_buffers[i] = | 524 | cx->stream_buffers[i] = |
508 | cx->options.megabytes[i] * 1024 * 1024 | 525 | cx->options.megabytes[i] * 1024 * 1024 |
@@ -513,18 +530,24 @@ static void cx18_process_options(struct cx18 *cx) | |||
513 | cx->stream_buffers[i] | 530 | cx->stream_buffers[i] |
514 | * cx->stream_buf_size[i]/(1024 * 1024); | 531 | * cx->stream_buf_size[i]/(1024 * 1024); |
515 | } | 532 | } |
516 | continue; | ||
517 | } | ||
518 | /* All other streams have stream_buf_size in kB at this point */ | ||
519 | if (cx->stream_buffers[i] < 0) { | ||
520 | cx->stream_buffers[i] = cx->options.megabytes[i] * 1024 | ||
521 | / cx->stream_buf_size[i]; | ||
522 | } else { | 533 | } else { |
523 | /* N.B. This might round down to 0 */ | 534 | /* All other streams have stream_buf_size in kB here */ |
524 | cx->options.megabytes[i] = | 535 | if (cx->stream_buffers[i] < 0) { |
525 | cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024; | 536 | cx->stream_buffers[i] = |
537 | cx->options.megabytes[i] * 1024 | ||
538 | / cx->stream_buf_size[i]; | ||
539 | } else { | ||
540 | /* N.B. This might round down to 0 */ | ||
541 | cx->options.megabytes[i] = | ||
542 | cx->stream_buffers[i] | ||
543 | * cx->stream_buf_size[i] / 1024; | ||
544 | } | ||
545 | /* convert from kB to bytes */ | ||
546 | cx->stream_buf_size[i] *= 1024; | ||
526 | } | 547 | } |
527 | cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */ | 548 | CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, " |
549 | "%d bytes\n", i, cx->options.megabytes[i], | ||
550 | cx->stream_buffers[i], cx->stream_buf_size[i]); | ||
528 | } | 551 | } |
529 | 552 | ||
530 | cx->options.cardtype = cardtype[cx->instance]; | 553 | cx->options.cardtype = cardtype[cx->instance]; |
@@ -669,6 +692,12 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) | |||
669 | cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; | 692 | cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; |
670 | cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; | 693 | cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; |
671 | 694 | ||
695 | /* IVTV style VBI insertion into MPEG streams */ | ||
696 | INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list); | ||
697 | INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list); | ||
698 | INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list); | ||
699 | list_add(&cx->vbi.sliced_mpeg_buf.list, | ||
700 | &cx->vbi.sliced_mpeg_mdl.buf_list); | ||
672 | return 0; | 701 | return 0; |
673 | } | 702 | } |
674 | 703 | ||
@@ -883,7 +912,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
883 | CX18_ERR("Could not register A/V decoder subdevice\n"); | 912 | CX18_ERR("Could not register A/V decoder subdevice\n"); |
884 | goto free_map; | 913 | goto free_map; |
885 | } | 914 | } |
886 | cx18_call_hw(cx, CX18_HW_418_AV, core, init, 0); | ||
887 | 915 | ||
888 | /* Initialize GPIO Reset Controller to do chip resets during i2c init */ | 916 | /* Initialize GPIO Reset Controller to do chip resets during i2c init */ |
889 | if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { | 917 | if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index c6a1e907f63a..e3f7911a7385 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <media/v4l2-ioctl.h> | 50 | #include <media/v4l2-ioctl.h> |
51 | #include <media/v4l2-device.h> | 51 | #include <media/v4l2-device.h> |
52 | #include <media/tuner.h> | 52 | #include <media/tuner.h> |
53 | #include <media/ir-kbd-i2c.h> | ||
53 | #include "cx18-mailbox.h" | 54 | #include "cx18-mailbox.h" |
54 | #include "cx18-av-core.h" | 55 | #include "cx18-av-core.h" |
55 | #include "cx23418.h" | 56 | #include "cx23418.h" |
@@ -120,12 +121,16 @@ | |||
120 | /* Maximum firmware DMA buffers per stream */ | 121 | /* Maximum firmware DMA buffers per stream */ |
121 | #define CX18_MAX_FW_MDLS_PER_STREAM 63 | 122 | #define CX18_MAX_FW_MDLS_PER_STREAM 63 |
122 | 123 | ||
124 | /* YUV buffer sizes in bytes to ensure integer # of frames per buffer */ | ||
125 | #define CX18_UNIT_ENC_YUV_BUFSIZE (720 * 32 * 3 / 2) /* bytes */ | ||
126 | #define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32) | ||
127 | #define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32) | ||
128 | |||
123 | /* DMA buffer, default size in kB allocated */ | 129 | /* DMA buffer, default size in kB allocated */ |
124 | #define CX18_DEFAULT_ENC_TS_BUFSIZE 32 | 130 | #define CX18_DEFAULT_ENC_TS_BUFSIZE 32 |
125 | #define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 | 131 | #define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 |
126 | #define CX18_DEFAULT_ENC_IDX_BUFSIZE 32 | 132 | #define CX18_DEFAULT_ENC_IDX_BUFSIZE 32 |
127 | #define CX18_DEFAULT_ENC_YUV_BUFSIZE 128 | 133 | #define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1) |
128 | /* Default VBI bufsize based on standards supported by card tuner for now */ | ||
129 | #define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 | 134 | #define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 |
130 | 135 | ||
131 | /* i2c stuff */ | 136 | /* i2c stuff */ |
@@ -246,8 +251,8 @@ struct cx18_options { | |||
246 | int radio; /* enable/disable radio */ | 251 | int radio; /* enable/disable radio */ |
247 | }; | 252 | }; |
248 | 253 | ||
249 | /* per-buffer bit flags */ | 254 | /* per-mdl bit flags */ |
250 | #define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ | 255 | #define CX18_F_M_NEED_SWAP 0 /* mdl buffer data must be endianess swapped */ |
251 | 256 | ||
252 | /* per-stream, s_flags */ | 257 | /* per-stream, s_flags */ |
253 | #define CX18_F_S_CLAIMED 3 /* this stream is claimed */ | 258 | #define CX18_F_S_CLAIMED 3 /* this stream is claimed */ |
@@ -274,18 +279,29 @@ struct cx18_options { | |||
274 | struct cx18_buffer { | 279 | struct cx18_buffer { |
275 | struct list_head list; | 280 | struct list_head list; |
276 | dma_addr_t dma_handle; | 281 | dma_addr_t dma_handle; |
277 | u32 id; | ||
278 | unsigned long b_flags; | ||
279 | unsigned skipped; | ||
280 | char *buf; | 282 | char *buf; |
281 | 283 | ||
282 | u32 bytesused; | 284 | u32 bytesused; |
283 | u32 readpos; | 285 | u32 readpos; |
284 | }; | 286 | }; |
285 | 287 | ||
288 | struct cx18_mdl { | ||
289 | struct list_head list; | ||
290 | u32 id; /* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */ | ||
291 | |||
292 | unsigned int skipped; | ||
293 | unsigned long m_flags; | ||
294 | |||
295 | struct list_head buf_list; | ||
296 | struct cx18_buffer *curr_buf; /* current buffer in list for reading */ | ||
297 | |||
298 | u32 bytesused; | ||
299 | u32 readpos; | ||
300 | }; | ||
301 | |||
286 | struct cx18_queue { | 302 | struct cx18_queue { |
287 | struct list_head list; | 303 | struct list_head list; |
288 | atomic_t buffers; | 304 | atomic_t depth; |
289 | u32 bytesused; | 305 | u32 bytesused; |
290 | spinlock_t lock; | 306 | spinlock_t lock; |
291 | }; | 307 | }; |
@@ -337,7 +353,7 @@ struct cx18_stream { | |||
337 | const char *name; /* name of the stream */ | 353 | const char *name; /* name of the stream */ |
338 | int type; /* stream type */ | 354 | int type; /* stream type */ |
339 | u32 handle; /* task handle */ | 355 | u32 handle; /* task handle */ |
340 | unsigned mdl_offset; | 356 | unsigned int mdl_base_idx; |
341 | 357 | ||
342 | u32 id; | 358 | u32 id; |
343 | unsigned long s_flags; /* status flags, see above */ | 359 | unsigned long s_flags; /* status flags, see above */ |
@@ -346,14 +362,20 @@ struct cx18_stream { | |||
346 | PCI_DMA_NONE */ | 362 | PCI_DMA_NONE */ |
347 | wait_queue_head_t waitq; | 363 | wait_queue_head_t waitq; |
348 | 364 | ||
349 | /* Buffer Stats */ | 365 | /* Buffers */ |
350 | u32 buffers; | 366 | struct list_head buf_pool; /* buffers not attached to an MDL */ |
351 | u32 buf_size; | 367 | u32 buffers; /* total buffers owned by this stream */ |
368 | u32 buf_size; /* size in bytes of a single buffer */ | ||
369 | |||
370 | /* MDL sizes - all stream MDLs are the same size */ | ||
371 | u32 bufs_per_mdl; | ||
372 | u32 mdl_size; /* total bytes in all buffers in a mdl */ | ||
352 | 373 | ||
353 | /* Buffer Queues */ | 374 | /* MDL Queues */ |
354 | struct cx18_queue q_free; /* free buffers */ | 375 | struct cx18_queue q_free; /* free - in rotation, not committed */ |
355 | struct cx18_queue q_busy; /* busy buffers - in use by firmware */ | 376 | struct cx18_queue q_busy; /* busy - in use by firmware */ |
356 | struct cx18_queue q_full; /* full buffers - data for user apps */ | 377 | struct cx18_queue q_full; /* full - data for user apps */ |
378 | struct cx18_queue q_idle; /* idle - not in rotation */ | ||
357 | 379 | ||
358 | struct work_struct out_work_order; | 380 | struct work_struct out_work_order; |
359 | 381 | ||
@@ -481,10 +503,11 @@ struct vbi_info { | |||
481 | u32 inserted_frame; | 503 | u32 inserted_frame; |
482 | 504 | ||
483 | /* | 505 | /* |
484 | * A dummy driver stream transfer buffer with a copy of the next | 506 | * A dummy driver stream transfer mdl & buffer with a copy of the next |
485 | * sliced_mpeg_data[] buffer for output to userland apps. | 507 | * sliced_mpeg_data[] buffer for output to userland apps. |
486 | * Only used in cx18-fileops.c, but its state needs to persist at times. | 508 | * Only used in cx18-fileops.c, but its state needs to persist at times. |
487 | */ | 509 | */ |
510 | struct cx18_mdl sliced_mpeg_mdl; | ||
488 | struct cx18_buffer sliced_mpeg_buf; | 511 | struct cx18_buffer sliced_mpeg_buf; |
489 | }; | 512 | }; |
490 | 513 | ||
@@ -511,10 +534,9 @@ struct cx18 { | |||
511 | u8 is_60hz; | 534 | u8 is_60hz; |
512 | u8 nof_inputs; /* number of video inputs */ | 535 | u8 nof_inputs; /* number of video inputs */ |
513 | u8 nof_audio_inputs; /* number of audio inputs */ | 536 | u8 nof_audio_inputs; /* number of audio inputs */ |
514 | u16 buffer_id; /* buffer ID counter */ | ||
515 | u32 v4l2_cap; /* V4L2 capabilities of card */ | 537 | u32 v4l2_cap; /* V4L2 capabilities of card */ |
516 | u32 hw_flags; /* Hardware description of the board */ | 538 | u32 hw_flags; /* Hardware description of the board */ |
517 | unsigned mdl_offset; | 539 | unsigned int free_mdl_idx; |
518 | struct cx18_scb __iomem *scb; /* pointer to SCB */ | 540 | struct cx18_scb __iomem *scb; /* pointer to SCB */ |
519 | struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ | 541 | struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ |
520 | struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ | 542 | struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ |
@@ -585,6 +607,8 @@ struct cx18 { | |||
585 | struct i2c_algo_bit_data i2c_algo[2]; | 607 | struct i2c_algo_bit_data i2c_algo[2]; |
586 | struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; | 608 | struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; |
587 | 609 | ||
610 | struct IR_i2c_init_data ir_i2c_init_data; | ||
611 | |||
588 | /* gpio */ | 612 | /* gpio */ |
589 | u32 gpio_dir; | 613 | u32 gpio_dir; |
590 | u32 gpio_val; | 614 | u32 gpio_val; |
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 51a0c33b25b7..71ad2d1b4c2c 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c | |||
@@ -61,6 +61,7 @@ static struct mxl5005s_config hauppauge_hvr1600_tuner = { | |||
61 | .top = MXL5005S_TOP_25P2, | 61 | .top = MXL5005S_TOP_25P2, |
62 | .mod_mode = MXL_DIGITAL_MODE, | 62 | .mod_mode = MXL_DIGITAL_MODE, |
63 | .if_mode = MXL_ZERO_IF, | 63 | .if_mode = MXL_ZERO_IF, |
64 | .qam_gain = 0x02, | ||
64 | .AgcMasterByte = 0x00, | 65 | .AgcMasterByte = 0x00, |
65 | }; | 66 | }; |
66 | 67 | ||
@@ -71,7 +72,8 @@ static struct s5h1409_config hauppauge_hvr1600_config = { | |||
71 | .qam_if = 44000, | 72 | .qam_if = 44000, |
72 | .inversion = S5H1409_INVERSION_OFF, | 73 | .inversion = S5H1409_INVERSION_OFF, |
73 | .status_mode = S5H1409_DEMODLOCKING, | 74 | .status_mode = S5H1409_DEMODLOCKING, |
74 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK | 75 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, |
76 | .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE | ||
75 | }; | 77 | }; |
76 | 78 | ||
77 | /* | 79 | /* |
@@ -360,9 +362,10 @@ int cx18_dvb_register(struct cx18_stream *stream) | |||
360 | dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); | 362 | dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); |
361 | 363 | ||
362 | CX18_INFO("DVB Frontend registered\n"); | 364 | CX18_INFO("DVB Frontend registered\n"); |
363 | CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n", | 365 | CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n", |
364 | stream->dvb.dvb_adapter.num, stream->name, | 366 | stream->dvb.dvb_adapter.num, stream->name, |
365 | stream->buffers, stream->buf_size/1024); | 367 | stream->buffers, stream->buf_size/1024, |
368 | (stream->buf_size * 100 / 1024) % 100); | ||
366 | 369 | ||
367 | mutex_init(&dvb->feedlock); | 370 | mutex_init(&dvb->feedlock); |
368 | dvb->enabled = 1; | 371 | dvb->enabled = 1; |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 04d9c2508b86..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 */ |
@@ -229,7 +231,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, | |||
229 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | 231 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); |
230 | /* New buffers might have become available before we were added | 232 | /* New buffers might have become available before we were added |
231 | to the waitqueue */ | 233 | to the waitqueue */ |
232 | if (!atomic_read(&s->q_full.buffers)) | 234 | if (!atomic_read(&s->q_full.depth)) |
233 | schedule(); | 235 | schedule(); |
234 | finish_wait(&s->waitq, &wait); | 236 | finish_wait(&s->waitq, &wait); |
235 | if (signal_pending(current)) { | 237 | if (signal_pending(current)) { |
@@ -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; |
@@ -543,7 +607,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) | |||
543 | CX18_DEBUG_HI_FILE("Encoder poll\n"); | 607 | CX18_DEBUG_HI_FILE("Encoder poll\n"); |
544 | poll_wait(filp, &s->waitq, wait); | 608 | poll_wait(filp, &s->waitq, wait); |
545 | 609 | ||
546 | if (atomic_read(&s->q_full.buffers)) | 610 | if (atomic_read(&s->q_full.depth)) |
547 | return POLLIN | POLLRDNORM; | 611 | return POLLIN | POLLRDNORM; |
548 | if (eof) | 612 | if (eof) |
549 | return POLLHUP; | 613 | return POLLHUP; |
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index 2477461e84d7..eecf29af916c 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include "cx18-gpio.h" | 28 | #include "cx18-gpio.h" |
29 | #include "cx18-i2c.h" | 29 | #include "cx18-i2c.h" |
30 | #include "cx18-irq.h" | 30 | #include "cx18-irq.h" |
31 | #include <media/ir-kbd-i2c.h> | ||
32 | 31 | ||
33 | #define CX18_REG_I2C_1_WR 0xf15000 | 32 | #define CX18_REG_I2C_1_WR 0xf15000 |
34 | #define CX18_REG_I2C_1_RD 0xf15008 | 33 | #define CX18_REG_I2C_1_RD 0xf15008 |
@@ -97,17 +96,11 @@ static const char * const hw_devicenames[] = { | |||
97 | "ir_rx_z8f0811_haup", | 96 | "ir_rx_z8f0811_haup", |
98 | }; | 97 | }; |
99 | 98 | ||
100 | static const struct IR_i2c_init_data z8f0811_ir_init_data = { | 99 | static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, |
101 | .ir_codes = &ir_codes_hauppauge_new_table, | 100 | const char *type, u8 addr) |
102 | .internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR, | ||
103 | .type = IR_TYPE_RC5, | ||
104 | .name = "CX23418 Z8F0811 Hauppauge", | ||
105 | }; | ||
106 | |||
107 | static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type, | ||
108 | u8 addr) | ||
109 | { | 101 | { |
110 | struct i2c_board_info info; | 102 | struct i2c_board_info info; |
103 | struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data; | ||
111 | unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; | 104 | unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; |
112 | 105 | ||
113 | memset(&info, 0, sizeof(struct i2c_board_info)); | 106 | memset(&info, 0, sizeof(struct i2c_board_info)); |
@@ -116,9 +109,11 @@ static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type, | |||
116 | /* Our default information for ir-kbd-i2c.c to use */ | 109 | /* Our default information for ir-kbd-i2c.c to use */ |
117 | switch (hw) { | 110 | switch (hw) { |
118 | case CX18_HW_Z8F0811_IR_RX_HAUP: | 111 | case CX18_HW_Z8F0811_IR_RX_HAUP: |
119 | info.platform_data = (void *) &z8f0811_ir_init_data; | 112 | init_data->ir_codes = &ir_codes_hauppauge_new_table; |
120 | break; | 113 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
121 | default: | 114 | init_data->type = IR_TYPE_RC5; |
115 | init_data->name = cx->card_name; | ||
116 | info.platform_data = init_data; | ||
122 | break; | 117 | break; |
123 | } | 118 | } |
124 | 119 | ||
@@ -154,8 +149,8 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx) | |||
154 | return sd != NULL ? 0 : -1; | 149 | return sd != NULL ? 0 : -1; |
155 | } | 150 | } |
156 | 151 | ||
157 | if (hw & CX18_HW_Z8F0811_IR_HAUP) | 152 | if (hw & CX18_HW_IR_ANY) |
158 | return cx18_i2c_new_ir(adap, hw, type, hw_addrs[idx]); | 153 | return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]); |
159 | 154 | ||
160 | /* Is it not an I2C device or one we do not wish to register? */ | 155 | /* Is it not an I2C device or one we do not wish to register? */ |
161 | if (!hw_addrs[idx]) | 156 | if (!hw_addrs[idx]) |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index fc76e4d6ffa7..3e4fc192fdec 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -910,7 +910,8 @@ static int cx18_log_status(struct file *file, void *fh) | |||
910 | continue; | 910 | continue; |
911 | CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", | 911 | CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", |
912 | s->name, s->s_flags, | 912 | s->name, s->s_flags, |
913 | atomic_read(&s->q_full.buffers) * 100 / s->buffers, | 913 | atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100 |
914 | / s->buffers, | ||
914 | (s->buffers * s->buf_size) / 1024, s->buffers); | 915 | (s->buffers * s->buf_size) / 1024, s->buffers); |
915 | } | 916 | } |
916 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", | 917 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", |
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index afe46c3d4057..f231dd09c720 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -131,13 +131,39 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) | |||
131 | * Functions that run in a work_queue work handling context | 131 | * Functions that run in a work_queue work handling context |
132 | */ | 132 | */ |
133 | 133 | ||
134 | static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) | ||
135 | { | ||
136 | struct cx18_buffer *buf; | ||
137 | |||
138 | if (!s->dvb.enabled || mdl->bytesused == 0) | ||
139 | return; | ||
140 | |||
141 | /* We ignore mdl and buf readpos accounting here - it doesn't matter */ | ||
142 | |||
143 | /* The likely case */ | ||
144 | if (list_is_singular(&mdl->buf_list)) { | ||
145 | buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, | ||
146 | list); | ||
147 | if (buf->bytesused) | ||
148 | dvb_dmx_swfilter(&s->dvb.demux, | ||
149 | buf->buf, buf->bytesused); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
154 | if (buf->bytesused == 0) | ||
155 | break; | ||
156 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused); | ||
157 | } | ||
158 | } | ||
159 | |||
134 | static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | 160 | static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) |
135 | { | 161 | { |
136 | u32 handle, mdl_ack_count, id; | 162 | u32 handle, mdl_ack_count, id; |
137 | struct cx18_mailbox *mb; | 163 | struct cx18_mailbox *mb; |
138 | struct cx18_mdl_ack *mdl_ack; | 164 | struct cx18_mdl_ack *mdl_ack; |
139 | struct cx18_stream *s; | 165 | struct cx18_stream *s; |
140 | struct cx18_buffer *buf; | 166 | struct cx18_mdl *mdl; |
141 | int i; | 167 | int i; |
142 | 168 | ||
143 | mb = &order->mb; | 169 | mb = &order->mb; |
@@ -158,7 +184,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | |||
158 | id = mdl_ack->id; | 184 | id = mdl_ack->id; |
159 | /* | 185 | /* |
160 | * Simple integrity check for processing a stale (and possibly | 186 | * Simple integrity check for processing a stale (and possibly |
161 | * inconsistent mailbox): make sure the buffer id is in the | 187 | * inconsistent mailbox): make sure the MDL id is in the |
162 | * valid range for the stream. | 188 | * valid range for the stream. |
163 | * | 189 | * |
164 | * We go through the trouble of dealing with stale mailboxes | 190 | * We go through the trouble of dealing with stale mailboxes |
@@ -169,44 +195,42 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | |||
169 | * There are occasions when we get a half changed mailbox, | 195 | * There are occasions when we get a half changed mailbox, |
170 | * which this check catches for a handle & id mismatch. If the | 196 | * which this check catches for a handle & id mismatch. If the |
171 | * handle and id do correspond, the worst case is that we | 197 | * handle and id do correspond, the worst case is that we |
172 | * completely lost the old buffer, but pick up the new buffer | 198 | * completely lost the old MDL, but pick up the new MDL |
173 | * early (but the new mdl_ack is guaranteed to be good in this | 199 | * early (but the new mdl_ack is guaranteed to be good in this |
174 | * case as the firmware wouldn't point us to a new mdl_ack until | 200 | * case as the firmware wouldn't point us to a new mdl_ack until |
175 | * it's filled in). | 201 | * it's filled in). |
176 | * | 202 | * |
177 | * cx18_queue_get buf() will detect the lost buffers | 203 | * cx18_queue_get_mdl() will detect the lost MDLs |
178 | * and send them back to q_free for fw rotation eventually. | 204 | * and send them back to q_free for fw rotation eventually. |
179 | */ | 205 | */ |
180 | if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && | 206 | if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && |
181 | !(id >= s->mdl_offset && | 207 | !(id >= s->mdl_base_idx && |
182 | id < (s->mdl_offset + s->buffers))) { | 208 | id < (s->mdl_base_idx + s->buffers))) { |
183 | CX18_WARN("Fell behind! Ignoring stale mailbox with " | 209 | CX18_WARN("Fell behind! Ignoring stale mailbox with " |
184 | " inconsistent data. Lost buffer for mailbox " | 210 | " inconsistent data. Lost MDL for mailbox " |
185 | "seq no %d\n", mb->request); | 211 | "seq no %d\n", mb->request); |
186 | break; | 212 | break; |
187 | } | 213 | } |
188 | buf = cx18_queue_get_buf(s, id, mdl_ack->data_used); | 214 | mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); |
189 | 215 | ||
190 | CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); | 216 | CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); |
191 | if (buf == NULL) { | 217 | if (mdl == NULL) { |
192 | CX18_WARN("Could not find buf %d for stream %s\n", | 218 | CX18_WARN("Could not find MDL %d for stream %s\n", |
193 | id, s->name); | 219 | id, s->name); |
194 | continue; | 220 | continue; |
195 | } | 221 | } |
196 | 222 | ||
197 | CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", | 223 | CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", |
198 | s->name, buf->bytesused); | 224 | s->name, mdl->bytesused); |
199 | 225 | ||
200 | if (s->type != CX18_ENC_STREAM_TYPE_TS) | 226 | if (s->type != CX18_ENC_STREAM_TYPE_TS) |
201 | cx18_enqueue(s, buf, &s->q_full); | 227 | cx18_enqueue(s, mdl, &s->q_full); |
202 | else { | 228 | else { |
203 | if (s->dvb.enabled) | 229 | cx18_mdl_send_to_dvb(s, mdl); |
204 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, | 230 | cx18_enqueue(s, mdl, &s->q_free); |
205 | buf->bytesused); | ||
206 | cx18_enqueue(s, buf, &s->q_free); | ||
207 | } | 231 | } |
208 | } | 232 | } |
209 | /* Put as many buffers as possible back into fw use */ | 233 | /* Put as many MDLs as possible back into fw use */ |
210 | cx18_stream_load_fw_queue(s); | 234 | cx18_stream_load_fw_queue(s); |
211 | 235 | ||
212 | wake_up(&cx->dma_waitq); | 236 | wake_up(&cx->dma_waitq); |
@@ -616,7 +640,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) | |||
616 | 640 | ||
617 | /* | 641 | /* |
618 | * Wait for XPU to perform extra actions for the caller in some cases. | 642 | * Wait for XPU to perform extra actions for the caller in some cases. |
619 | * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers | 643 | * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs |
620 | * back in a burst shortly thereafter | 644 | * back in a burst shortly thereafter |
621 | */ | 645 | */ |
622 | if (info->flags & API_SLOW) | 646 | if (info->flags & API_SLOW) |
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 522ad534034c..33a3491c4537 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h | |||
@@ -39,14 +39,14 @@ | |||
39 | struct cx18; | 39 | struct cx18; |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * This structure is used by CPU to provide completed buffers information | 42 | * This structure is used by CPU to provide completed MDL & buffers information. |
43 | * Its structure is dictrated by the layout of the SCB, required by the | 43 | * Its structure is dictated by the layout of the SCB, required by the |
44 | * firmware, but its definition needs to be here, instead of in cx18-scb.h, | 44 | * firmware, but its definition needs to be here, instead of in cx18-scb.h, |
45 | * for mailbox work order scheduling | 45 | * for mailbox work order scheduling |
46 | */ | 46 | */ |
47 | struct cx18_mdl_ack { | 47 | struct cx18_mdl_ack { |
48 | u32 id; /* ID of a completed MDL */ | 48 | u32 id; /* ID of a completed MDL */ |
49 | u32 data_used; /* Total data filled in the MDL for buffer 'id' */ | 49 | u32 data_used; /* Total data filled in the MDL with 'id' */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* The cx18_mailbox struct is the mailbox structure which is used for passing | 52 | /* The cx18_mailbox struct is the mailbox structure which is used for passing |
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index fa1ed7897d97..63304823cef5 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "cx18-queue.h" | 26 | #include "cx18-queue.h" |
27 | #include "cx18-streams.h" | 27 | #include "cx18-streams.h" |
28 | #include "cx18-scb.h" | 28 | #include "cx18-scb.h" |
29 | #include "cx18-io.h" | ||
29 | 30 | ||
30 | void cx18_buf_swap(struct cx18_buffer *buf) | 31 | void cx18_buf_swap(struct cx18_buffer *buf) |
31 | { | 32 | { |
@@ -35,151 +36,312 @@ void cx18_buf_swap(struct cx18_buffer *buf) | |||
35 | swab32s((u32 *)(buf->buf + i)); | 36 | swab32s((u32 *)(buf->buf + i)); |
36 | } | 37 | } |
37 | 38 | ||
39 | void _cx18_mdl_swap(struct cx18_mdl *mdl) | ||
40 | { | ||
41 | struct cx18_buffer *buf; | ||
42 | |||
43 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
44 | if (buf->bytesused == 0) | ||
45 | break; | ||
46 | cx18_buf_swap(buf); | ||
47 | } | ||
48 | } | ||
49 | |||
38 | void cx18_queue_init(struct cx18_queue *q) | 50 | void cx18_queue_init(struct cx18_queue *q) |
39 | { | 51 | { |
40 | INIT_LIST_HEAD(&q->list); | 52 | INIT_LIST_HEAD(&q->list); |
41 | atomic_set(&q->buffers, 0); | 53 | atomic_set(&q->depth, 0); |
42 | q->bytesused = 0; | 54 | q->bytesused = 0; |
43 | } | 55 | } |
44 | 56 | ||
45 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 57 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, |
46 | struct cx18_queue *q, int to_front) | 58 | struct cx18_queue *q, int to_front) |
47 | { | 59 | { |
48 | /* clear the buffer if it is not to be enqueued to the full queue */ | 60 | /* clear the mdl if it is not to be enqueued to the full queue */ |
49 | if (q != &s->q_full) { | 61 | if (q != &s->q_full) { |
50 | buf->bytesused = 0; | 62 | mdl->bytesused = 0; |
51 | buf->readpos = 0; | 63 | mdl->readpos = 0; |
52 | buf->b_flags = 0; | 64 | mdl->m_flags = 0; |
53 | buf->skipped = 0; | 65 | mdl->skipped = 0; |
66 | mdl->curr_buf = NULL; | ||
54 | } | 67 | } |
55 | 68 | ||
56 | /* q_busy is restricted to a max buffer count imposed by firmware */ | 69 | /* q_busy is restricted to a max buffer count imposed by firmware */ |
57 | if (q == &s->q_busy && | 70 | if (q == &s->q_busy && |
58 | atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM) | 71 | atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM) |
59 | q = &s->q_free; | 72 | q = &s->q_free; |
60 | 73 | ||
61 | spin_lock(&q->lock); | 74 | spin_lock(&q->lock); |
62 | 75 | ||
63 | if (to_front) | 76 | if (to_front) |
64 | list_add(&buf->list, &q->list); /* LIFO */ | 77 | list_add(&mdl->list, &q->list); /* LIFO */ |
65 | else | 78 | else |
66 | list_add_tail(&buf->list, &q->list); /* FIFO */ | 79 | list_add_tail(&mdl->list, &q->list); /* FIFO */ |
67 | q->bytesused += buf->bytesused - buf->readpos; | 80 | q->bytesused += mdl->bytesused - mdl->readpos; |
68 | atomic_inc(&q->buffers); | 81 | atomic_inc(&q->depth); |
69 | 82 | ||
70 | spin_unlock(&q->lock); | 83 | spin_unlock(&q->lock); |
71 | return q; | 84 | return q; |
72 | } | 85 | } |
73 | 86 | ||
74 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) | 87 | struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) |
75 | { | 88 | { |
76 | struct cx18_buffer *buf = NULL; | 89 | struct cx18_mdl *mdl = NULL; |
77 | 90 | ||
78 | spin_lock(&q->lock); | 91 | spin_lock(&q->lock); |
79 | if (!list_empty(&q->list)) { | 92 | if (!list_empty(&q->list)) { |
80 | buf = list_first_entry(&q->list, struct cx18_buffer, list); | 93 | mdl = list_first_entry(&q->list, struct cx18_mdl, list); |
81 | list_del_init(&buf->list); | 94 | list_del_init(&mdl->list); |
82 | q->bytesused -= buf->bytesused - buf->readpos; | 95 | q->bytesused -= mdl->bytesused - mdl->readpos; |
83 | buf->skipped = 0; | 96 | mdl->skipped = 0; |
84 | atomic_dec(&q->buffers); | 97 | atomic_dec(&q->depth); |
85 | } | 98 | } |
86 | spin_unlock(&q->lock); | 99 | spin_unlock(&q->lock); |
87 | return buf; | 100 | return mdl; |
101 | } | ||
102 | |||
103 | static void _cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, | ||
104 | struct cx18_mdl *mdl) | ||
105 | { | ||
106 | struct cx18_buffer *buf; | ||
107 | u32 buf_size = s->buf_size; | ||
108 | u32 bytesused = mdl->bytesused; | ||
109 | |||
110 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
111 | buf->readpos = 0; | ||
112 | if (bytesused >= buf_size) { | ||
113 | buf->bytesused = buf_size; | ||
114 | bytesused -= buf_size; | ||
115 | } else { | ||
116 | buf->bytesused = bytesused; | ||
117 | bytesused = 0; | ||
118 | } | ||
119 | cx18_buf_sync_for_cpu(s, buf); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, | ||
124 | struct cx18_mdl *mdl) | ||
125 | { | ||
126 | struct cx18_buffer *buf; | ||
127 | |||
128 | if (list_is_singular(&mdl->buf_list)) { | ||
129 | buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, | ||
130 | list); | ||
131 | buf->bytesused = mdl->bytesused; | ||
132 | buf->readpos = 0; | ||
133 | cx18_buf_sync_for_cpu(s, buf); | ||
134 | } else { | ||
135 | _cx18_mdl_update_bufs_for_cpu(s, mdl); | ||
136 | } | ||
88 | } | 137 | } |
89 | 138 | ||
90 | struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | 139 | struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, |
91 | u32 bytesused) | 140 | u32 bytesused) |
92 | { | 141 | { |
93 | struct cx18 *cx = s->cx; | 142 | struct cx18 *cx = s->cx; |
94 | struct cx18_buffer *buf; | 143 | struct cx18_mdl *mdl; |
95 | struct cx18_buffer *tmp; | 144 | struct cx18_mdl *tmp; |
96 | struct cx18_buffer *ret = NULL; | 145 | struct cx18_mdl *ret = NULL; |
97 | LIST_HEAD(sweep_up); | 146 | LIST_HEAD(sweep_up); |
98 | 147 | ||
99 | /* | 148 | /* |
100 | * We don't have to acquire multiple q locks here, because we are | 149 | * We don't have to acquire multiple q locks here, because we are |
101 | * serialized by the single threaded work handler. | 150 | * serialized by the single threaded work handler. |
102 | * Buffers from the firmware will thus remain in order as | 151 | * MDLs from the firmware will thus remain in order as |
103 | * they are moved from q_busy to q_full or to the dvb ring buffer. | 152 | * they are moved from q_busy to q_full or to the dvb ring buffer. |
104 | */ | 153 | */ |
105 | spin_lock(&s->q_busy.lock); | 154 | spin_lock(&s->q_busy.lock); |
106 | list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) { | 155 | list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) { |
107 | /* | 156 | /* |
108 | * We should find what the firmware told us is done, | 157 | * We should find what the firmware told us is done, |
109 | * right at the front of the queue. If we don't, we likely have | 158 | * right at the front of the queue. If we don't, we likely have |
110 | * missed a buffer done message from the firmware. | 159 | * missed an mdl done message from the firmware. |
111 | * Once we skip a buffer repeatedly, relative to the size of | 160 | * Once we skip an mdl repeatedly, relative to the size of |
112 | * q_busy, we have high confidence we've missed it. | 161 | * q_busy, we have high confidence we've missed it. |
113 | */ | 162 | */ |
114 | if (buf->id != id) { | 163 | if (mdl->id != id) { |
115 | buf->skipped++; | 164 | mdl->skipped++; |
116 | if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { | 165 | if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { |
117 | /* buffer must have fallen out of rotation */ | 166 | /* mdl must have fallen out of rotation */ |
118 | CX18_WARN("Skipped %s, buffer %d, %d " | 167 | CX18_WARN("Skipped %s, MDL %d, %d " |
119 | "times - it must have dropped out of " | 168 | "times - it must have dropped out of " |
120 | "rotation\n", s->name, buf->id, | 169 | "rotation\n", s->name, mdl->id, |
121 | buf->skipped); | 170 | mdl->skipped); |
122 | /* Sweep it up to put it back into rotation */ | 171 | /* Sweep it up to put it back into rotation */ |
123 | list_move_tail(&buf->list, &sweep_up); | 172 | list_move_tail(&mdl->list, &sweep_up); |
124 | atomic_dec(&s->q_busy.buffers); | 173 | atomic_dec(&s->q_busy.depth); |
125 | } | 174 | } |
126 | continue; | 175 | continue; |
127 | } | 176 | } |
128 | /* | 177 | /* |
129 | * We pull the desired buffer off of the queue here. Something | 178 | * We pull the desired mdl off of the queue here. Something |
130 | * will have to put it back on a queue later. | 179 | * will have to put it back on a queue later. |
131 | */ | 180 | */ |
132 | list_del_init(&buf->list); | 181 | list_del_init(&mdl->list); |
133 | atomic_dec(&s->q_busy.buffers); | 182 | atomic_dec(&s->q_busy.depth); |
134 | ret = buf; | 183 | ret = mdl; |
135 | break; | 184 | break; |
136 | } | 185 | } |
137 | spin_unlock(&s->q_busy.lock); | 186 | spin_unlock(&s->q_busy.lock); |
138 | 187 | ||
139 | /* | 188 | /* |
140 | * We found the buffer for which we were looking. Get it ready for | 189 | * We found the mdl for which we were looking. Get it ready for |
141 | * the caller to put on q_full or in the dvb ring buffer. | 190 | * the caller to put on q_full or in the dvb ring buffer. |
142 | */ | 191 | */ |
143 | if (ret != NULL) { | 192 | if (ret != NULL) { |
144 | ret->bytesused = bytesused; | 193 | ret->bytesused = bytesused; |
145 | ret->skipped = 0; | 194 | ret->skipped = 0; |
146 | /* readpos and b_flags were 0'ed when the buf went on q_busy */ | 195 | /* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */ |
147 | cx18_buf_sync_for_cpu(s, ret); | 196 | cx18_mdl_update_bufs_for_cpu(s, ret); |
148 | if (s->type != CX18_ENC_STREAM_TYPE_TS) | 197 | if (s->type != CX18_ENC_STREAM_TYPE_TS) |
149 | set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags); | 198 | set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags); |
150 | } | 199 | } |
151 | 200 | ||
152 | /* Put any buffers the firmware is ignoring back into normal rotation */ | 201 | /* Put any mdls the firmware is ignoring back into normal rotation */ |
153 | list_for_each_entry_safe(buf, tmp, &sweep_up, list) { | 202 | list_for_each_entry_safe(mdl, tmp, &sweep_up, list) { |
154 | list_del_init(&buf->list); | 203 | list_del_init(&mdl->list); |
155 | cx18_enqueue(s, buf, &s->q_free); | 204 | cx18_enqueue(s, mdl, &s->q_free); |
156 | } | 205 | } |
157 | return ret; | 206 | return ret; |
158 | } | 207 | } |
159 | 208 | ||
160 | /* Move all buffers of a queue to q_free, while flushing the buffers */ | 209 | /* Move all mdls of a queue, while flushing the mdl */ |
161 | static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) | 210 | static void cx18_queue_flush(struct cx18_stream *s, |
211 | struct cx18_queue *q_src, struct cx18_queue *q_dst) | ||
162 | { | 212 | { |
163 | struct cx18_buffer *buf; | 213 | struct cx18_mdl *mdl; |
164 | 214 | ||
165 | if (q == &s->q_free) | 215 | /* It only makes sense to flush to q_free or q_idle */ |
216 | if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy) | ||
166 | return; | 217 | return; |
167 | 218 | ||
168 | spin_lock(&q->lock); | 219 | spin_lock(&q_src->lock); |
169 | while (!list_empty(&q->list)) { | 220 | spin_lock(&q_dst->lock); |
170 | buf = list_first_entry(&q->list, struct cx18_buffer, list); | 221 | while (!list_empty(&q_src->list)) { |
171 | list_move_tail(&buf->list, &s->q_free.list); | 222 | mdl = list_first_entry(&q_src->list, struct cx18_mdl, list); |
172 | buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; | 223 | list_move_tail(&mdl->list, &q_dst->list); |
173 | atomic_inc(&s->q_free.buffers); | 224 | mdl->bytesused = 0; |
225 | mdl->readpos = 0; | ||
226 | mdl->m_flags = 0; | ||
227 | mdl->skipped = 0; | ||
228 | mdl->curr_buf = NULL; | ||
229 | atomic_inc(&q_dst->depth); | ||
174 | } | 230 | } |
175 | cx18_queue_init(q); | 231 | cx18_queue_init(q_src); |
176 | spin_unlock(&q->lock); | 232 | spin_unlock(&q_src->lock); |
233 | spin_unlock(&q_dst->lock); | ||
177 | } | 234 | } |
178 | 235 | ||
179 | void cx18_flush_queues(struct cx18_stream *s) | 236 | void cx18_flush_queues(struct cx18_stream *s) |
180 | { | 237 | { |
181 | cx18_queue_flush(s, &s->q_busy); | 238 | cx18_queue_flush(s, &s->q_busy, &s->q_free); |
182 | cx18_queue_flush(s, &s->q_full); | 239 | cx18_queue_flush(s, &s->q_full, &s->q_free); |
240 | } | ||
241 | |||
242 | /* | ||
243 | * Note, s->buf_pool is not protected by a lock, | ||
244 | * the stream better not have *anything* going on when calling this | ||
245 | */ | ||
246 | void cx18_unload_queues(struct cx18_stream *s) | ||
247 | { | ||
248 | struct cx18_queue *q_idle = &s->q_idle; | ||
249 | struct cx18_mdl *mdl; | ||
250 | struct cx18_buffer *buf; | ||
251 | |||
252 | /* Move all MDLS to q_idle */ | ||
253 | cx18_queue_flush(s, &s->q_busy, q_idle); | ||
254 | cx18_queue_flush(s, &s->q_full, q_idle); | ||
255 | cx18_queue_flush(s, &s->q_free, q_idle); | ||
256 | |||
257 | /* Reset MDL id's and move all buffers back to the stream's buf_pool */ | ||
258 | spin_lock(&q_idle->lock); | ||
259 | list_for_each_entry(mdl, &q_idle->list, list) { | ||
260 | while (!list_empty(&mdl->buf_list)) { | ||
261 | buf = list_first_entry(&mdl->buf_list, | ||
262 | struct cx18_buffer, list); | ||
263 | list_move_tail(&buf->list, &s->buf_pool); | ||
264 | buf->bytesused = 0; | ||
265 | buf->readpos = 0; | ||
266 | } | ||
267 | mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */ | ||
268 | /* all other mdl fields were cleared by cx18_queue_flush() */ | ||
269 | } | ||
270 | spin_unlock(&q_idle->lock); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Note, s->buf_pool is not protected by a lock, | ||
275 | * the stream better not have *anything* going on when calling this | ||
276 | */ | ||
277 | void cx18_load_queues(struct cx18_stream *s) | ||
278 | { | ||
279 | struct cx18 *cx = s->cx; | ||
280 | struct cx18_mdl *mdl; | ||
281 | struct cx18_buffer *buf; | ||
282 | int mdl_id; | ||
283 | int i; | ||
284 | u32 partial_buf_size; | ||
285 | |||
286 | /* | ||
287 | * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free | ||
288 | * Excess MDLs are left on q_idle | ||
289 | * Excess buffers are left in buf_pool and/or on an MDL in q_idle | ||
290 | */ | ||
291 | mdl_id = s->mdl_base_idx; | ||
292 | for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl; | ||
293 | mdl != NULL && i == s->bufs_per_mdl; | ||
294 | mdl = cx18_dequeue(s, &s->q_idle)) { | ||
295 | |||
296 | mdl->id = mdl_id; | ||
297 | |||
298 | for (i = 0; i < s->bufs_per_mdl; i++) { | ||
299 | if (list_empty(&s->buf_pool)) | ||
300 | break; | ||
301 | |||
302 | buf = list_first_entry(&s->buf_pool, struct cx18_buffer, | ||
303 | list); | ||
304 | list_move_tail(&buf->list, &mdl->buf_list); | ||
305 | |||
306 | /* update the firmware's MDL array with this buffer */ | ||
307 | cx18_writel(cx, buf->dma_handle, | ||
308 | &cx->scb->cpu_mdl[mdl_id + i].paddr); | ||
309 | cx18_writel(cx, s->buf_size, | ||
310 | &cx->scb->cpu_mdl[mdl_id + i].length); | ||
311 | } | ||
312 | |||
313 | if (i == s->bufs_per_mdl) { | ||
314 | /* | ||
315 | * The encoder doesn't honor s->mdl_size. So in the | ||
316 | * case of a non-integral number of buffers to meet | ||
317 | * mdl_size, we lie about the size of the last buffer | ||
318 | * in the MDL to get the encoder to really only send | ||
319 | * us mdl_size bytes per MDL transfer. | ||
320 | */ | ||
321 | partial_buf_size = s->mdl_size % s->buf_size; | ||
322 | if (partial_buf_size) { | ||
323 | cx18_writel(cx, partial_buf_size, | ||
324 | &cx->scb->cpu_mdl[mdl_id + i - 1].length); | ||
325 | } | ||
326 | cx18_enqueue(s, mdl, &s->q_free); | ||
327 | } else { | ||
328 | /* Not enough buffers for this MDL; we won't use it */ | ||
329 | cx18_push(s, mdl, &s->q_idle); | ||
330 | } | ||
331 | mdl_id += i; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl) | ||
336 | { | ||
337 | int dma = s->dma; | ||
338 | u32 buf_size = s->buf_size; | ||
339 | struct pci_dev *pci_dev = s->cx->pci_dev; | ||
340 | struct cx18_buffer *buf; | ||
341 | |||
342 | list_for_each_entry(buf, &mdl->buf_list, list) | ||
343 | pci_dma_sync_single_for_device(pci_dev, buf->dma_handle, | ||
344 | buf_size, dma); | ||
183 | } | 345 | } |
184 | 346 | ||
185 | int cx18_stream_alloc(struct cx18_stream *s) | 347 | int cx18_stream_alloc(struct cx18_stream *s) |
@@ -190,44 +352,62 @@ int cx18_stream_alloc(struct cx18_stream *s) | |||
190 | if (s->buffers == 0) | 352 | if (s->buffers == 0) |
191 | return 0; | 353 | return 0; |
192 | 354 | ||
193 | CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n", | 355 | CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers " |
356 | "(%d.%02d kB total)\n", | ||
194 | s->name, s->buffers, s->buf_size, | 357 | s->name, s->buffers, s->buf_size, |
195 | s->buffers * s->buf_size / 1024); | 358 | s->buffers * s->buf_size / 1024, |
359 | (s->buffers * s->buf_size * 100 / 1024) % 100); | ||
196 | 360 | ||
197 | if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - | 361 | if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] - |
198 | (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { | 362 | (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { |
199 | unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - | 363 | unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - |
200 | ((char __iomem *)cx->scb->cpu_mdl)); | 364 | ((char __iomem *)cx->scb->cpu_mdl)); |
201 | 365 | ||
202 | CX18_ERR("Too many buffers, cannot fit in SCB area\n"); | 366 | CX18_ERR("Too many buffers, cannot fit in SCB area\n"); |
203 | CX18_ERR("Max buffers = %zd\n", | 367 | CX18_ERR("Max buffers = %zd\n", |
204 | bufsz / sizeof(struct cx18_mdl)); | 368 | bufsz / sizeof(struct cx18_mdl_ent)); |
205 | return -ENOMEM; | 369 | return -ENOMEM; |
206 | } | 370 | } |
207 | 371 | ||
208 | s->mdl_offset = cx->mdl_offset; | 372 | s->mdl_base_idx = cx->free_mdl_idx; |
209 | 373 | ||
210 | /* allocate stream buffers. Initially all buffers are in q_free. */ | 374 | /* allocate stream buffers and MDLs */ |
211 | for (i = 0; i < s->buffers; i++) { | 375 | for (i = 0; i < s->buffers; i++) { |
212 | struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer), | 376 | struct cx18_mdl *mdl; |
213 | GFP_KERNEL|__GFP_NOWARN); | 377 | struct cx18_buffer *buf; |
214 | 378 | ||
215 | if (buf == NULL) | 379 | /* 1 MDL per buffer to handle the worst & also default case */ |
380 | mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN); | ||
381 | if (mdl == NULL) | ||
216 | break; | 382 | break; |
383 | |||
384 | buf = kzalloc(sizeof(struct cx18_buffer), | ||
385 | GFP_KERNEL|__GFP_NOWARN); | ||
386 | if (buf == NULL) { | ||
387 | kfree(mdl); | ||
388 | break; | ||
389 | } | ||
390 | |||
217 | buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); | 391 | buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); |
218 | if (buf->buf == NULL) { | 392 | if (buf->buf == NULL) { |
393 | kfree(mdl); | ||
219 | kfree(buf); | 394 | kfree(buf); |
220 | break; | 395 | break; |
221 | } | 396 | } |
222 | buf->id = cx->buffer_id++; | 397 | |
398 | INIT_LIST_HEAD(&mdl->list); | ||
399 | INIT_LIST_HEAD(&mdl->buf_list); | ||
400 | mdl->id = s->mdl_base_idx; /* a somewhat safe value */ | ||
401 | cx18_enqueue(s, mdl, &s->q_idle); | ||
402 | |||
223 | INIT_LIST_HEAD(&buf->list); | 403 | INIT_LIST_HEAD(&buf->list); |
224 | buf->dma_handle = pci_map_single(s->cx->pci_dev, | 404 | buf->dma_handle = pci_map_single(s->cx->pci_dev, |
225 | buf->buf, s->buf_size, s->dma); | 405 | buf->buf, s->buf_size, s->dma); |
226 | cx18_buf_sync_for_cpu(s, buf); | 406 | cx18_buf_sync_for_cpu(s, buf); |
227 | cx18_enqueue(s, buf, &s->q_free); | 407 | list_add_tail(&buf->list, &s->buf_pool); |
228 | } | 408 | } |
229 | if (i == s->buffers) { | 409 | if (i == s->buffers) { |
230 | cx->mdl_offset += s->buffers; | 410 | cx->free_mdl_idx += s->buffers; |
231 | return 0; | 411 | return 0; |
232 | } | 412 | } |
233 | CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); | 413 | CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); |
@@ -237,13 +417,21 @@ int cx18_stream_alloc(struct cx18_stream *s) | |||
237 | 417 | ||
238 | void cx18_stream_free(struct cx18_stream *s) | 418 | void cx18_stream_free(struct cx18_stream *s) |
239 | { | 419 | { |
420 | struct cx18_mdl *mdl; | ||
240 | struct cx18_buffer *buf; | 421 | struct cx18_buffer *buf; |
241 | 422 | ||
242 | /* move all buffers to q_free */ | 423 | /* move all buffers to buf_pool and all MDLs to q_idle */ |
243 | cx18_flush_queues(s); | 424 | cx18_unload_queues(s); |
425 | |||
426 | /* empty q_idle */ | ||
427 | while ((mdl = cx18_dequeue(s, &s->q_idle))) | ||
428 | kfree(mdl); | ||
429 | |||
430 | /* empty buf_pool */ | ||
431 | while (!list_empty(&s->buf_pool)) { | ||
432 | buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list); | ||
433 | list_del_init(&buf->list); | ||
244 | 434 | ||
245 | /* empty q_free */ | ||
246 | while ((buf = cx18_dequeue(s, &s->q_free))) { | ||
247 | pci_unmap_single(s->cx->pci_dev, buf->dma_handle, | 435 | pci_unmap_single(s->cx->pci_dev, buf->dma_handle, |
248 | s->buf_size, s->dma); | 436 | s->buf_size, s->dma); |
249 | kfree(buf->buf); | 437 | kfree(buf->buf); |
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index 4de06269d88f..88a6d34ad3bb 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h | |||
@@ -40,32 +40,59 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s, | |||
40 | s->buf_size, s->dma); | 40 | s->buf_size, s->dma); |
41 | } | 41 | } |
42 | 42 | ||
43 | void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl); | ||
44 | |||
45 | static inline void cx18_mdl_sync_for_device(struct cx18_stream *s, | ||
46 | struct cx18_mdl *mdl) | ||
47 | { | ||
48 | if (list_is_singular(&mdl->buf_list)) | ||
49 | cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list, | ||
50 | struct cx18_buffer, | ||
51 | list)); | ||
52 | else | ||
53 | _cx18_mdl_sync_for_device(s, mdl); | ||
54 | } | ||
55 | |||
43 | void cx18_buf_swap(struct cx18_buffer *buf); | 56 | void cx18_buf_swap(struct cx18_buffer *buf); |
57 | void _cx18_mdl_swap(struct cx18_mdl *mdl); | ||
58 | |||
59 | static inline void cx18_mdl_swap(struct cx18_mdl *mdl) | ||
60 | { | ||
61 | if (list_is_singular(&mdl->buf_list)) | ||
62 | cx18_buf_swap(list_first_entry(&mdl->buf_list, | ||
63 | struct cx18_buffer, list)); | ||
64 | else | ||
65 | _cx18_mdl_swap(mdl); | ||
66 | } | ||
44 | 67 | ||
45 | /* cx18_queue utility functions */ | 68 | /* cx18_queue utility functions */ |
46 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 69 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, |
47 | struct cx18_queue *q, int to_front); | 70 | struct cx18_queue *q, int to_front); |
48 | 71 | ||
49 | static inline | 72 | static inline |
50 | struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 73 | struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, |
51 | struct cx18_queue *q) | 74 | struct cx18_queue *q) |
52 | { | 75 | { |
53 | return _cx18_enqueue(s, buf, q, 0); /* FIFO */ | 76 | return _cx18_enqueue(s, mdl, q, 0); /* FIFO */ |
54 | } | 77 | } |
55 | 78 | ||
56 | static inline | 79 | static inline |
57 | struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf, | 80 | struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl, |
58 | struct cx18_queue *q) | 81 | struct cx18_queue *q) |
59 | { | 82 | { |
60 | return _cx18_enqueue(s, buf, q, 1); /* LIFO */ | 83 | return _cx18_enqueue(s, mdl, q, 1); /* LIFO */ |
61 | } | 84 | } |
62 | 85 | ||
63 | void cx18_queue_init(struct cx18_queue *q); | 86 | void cx18_queue_init(struct cx18_queue *q); |
64 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); | 87 | struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); |
65 | struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | 88 | struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, |
66 | u32 bytesused); | 89 | u32 bytesused); |
67 | void cx18_flush_queues(struct cx18_stream *s); | 90 | void cx18_flush_queues(struct cx18_stream *s); |
68 | 91 | ||
92 | /* queue MDL reconfiguration helpers */ | ||
93 | void cx18_unload_queues(struct cx18_stream *s); | ||
94 | void cx18_load_queues(struct cx18_stream *s); | ||
95 | |||
69 | /* cx18_stream utility functions */ | 96 | /* cx18_stream utility functions */ |
70 | int cx18_stream_alloc(struct cx18_stream *s); | 97 | int cx18_stream_alloc(struct cx18_stream *s); |
71 | void cx18_stream_free(struct cx18_stream *s); | 98 | void cx18_stream_free(struct cx18_stream *s); |
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h index 1dc1c431f5a1..368f23d08709 100644 --- a/drivers/media/video/cx18/cx18-scb.h +++ b/drivers/media/video/cx18/cx18-scb.h | |||
@@ -81,7 +81,7 @@ | |||
81 | 81 | ||
82 | 82 | ||
83 | /* This structure is used by EPU to provide memory descriptors in its memory */ | 83 | /* This structure is used by EPU to provide memory descriptors in its memory */ |
84 | struct cx18_mdl { | 84 | struct cx18_mdl_ent { |
85 | u32 paddr; /* Physical address of a buffer segment */ | 85 | u32 paddr; /* Physical address of a buffer segment */ |
86 | u32 length; /* Length of the buffer segment */ | 86 | u32 length; /* Length of the buffer segment */ |
87 | }; | 87 | }; |
@@ -272,7 +272,7 @@ struct cx18_scb { | |||
272 | struct cx18_mailbox ppu2epu_mb; | 272 | struct cx18_mailbox ppu2epu_mb; |
273 | 273 | ||
274 | struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; | 274 | struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; |
275 | struct cx18_mdl cpu_mdl[1]; | 275 | struct cx18_mdl_ent cpu_mdl[1]; |
276 | }; | 276 | }; |
277 | 277 | ||
278 | void cx18_init_scb(struct cx18 *cx); | 278 | void cx18_init_scb(struct cx18 *cx); |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 7df513a2dba8..c398651dd74c 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -115,6 +115,9 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
115 | s->dma = cx18_stream_info[type].dma; | 115 | s->dma = cx18_stream_info[type].dma; |
116 | s->buffers = cx->stream_buffers[type]; | 116 | s->buffers = cx->stream_buffers[type]; |
117 | s->buf_size = cx->stream_buf_size[type]; | 117 | s->buf_size = cx->stream_buf_size[type]; |
118 | INIT_LIST_HEAD(&s->buf_pool); | ||
119 | s->bufs_per_mdl = 1; | ||
120 | s->mdl_size = s->buf_size * s->bufs_per_mdl; | ||
118 | 121 | ||
119 | init_waitqueue_head(&s->waitq); | 122 | init_waitqueue_head(&s->waitq); |
120 | s->id = -1; | 123 | s->id = -1; |
@@ -124,6 +127,8 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
124 | cx18_queue_init(&s->q_busy); | 127 | cx18_queue_init(&s->q_busy); |
125 | spin_lock_init(&s->q_full.lock); | 128 | spin_lock_init(&s->q_full.lock); |
126 | cx18_queue_init(&s->q_full); | 129 | cx18_queue_init(&s->q_full); |
130 | spin_lock_init(&s->q_idle.lock); | ||
131 | cx18_queue_init(&s->q_idle); | ||
127 | 132 | ||
128 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); | 133 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); |
129 | } | 134 | } |
@@ -257,9 +262,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type) | |||
257 | 262 | ||
258 | switch (vfl_type) { | 263 | switch (vfl_type) { |
259 | case VFL_TYPE_GRABBER: | 264 | case VFL_TYPE_GRABBER: |
260 | CX18_INFO("Registered device video%d for %s (%d x %d kB)\n", | 265 | CX18_INFO("Registered device video%d for %s " |
266 | "(%d x %d.%02d kB)\n", | ||
261 | num, s->name, cx->stream_buffers[type], | 267 | num, s->name, cx->stream_buffers[type], |
262 | cx->stream_buf_size[type]/1024); | 268 | cx->stream_buf_size[type] / 1024, |
269 | (cx->stream_buf_size[type] * 100 / 1024) % 100); | ||
263 | break; | 270 | break; |
264 | 271 | ||
265 | case VFL_TYPE_RADIO: | 272 | case VFL_TYPE_RADIO: |
@@ -441,8 +448,8 @@ static void cx18_vbi_setup(struct cx18_stream *s) | |||
441 | } | 448 | } |
442 | 449 | ||
443 | static | 450 | static |
444 | struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s, | 451 | struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s, |
445 | struct cx18_buffer *buf) | 452 | struct cx18_mdl *mdl) |
446 | { | 453 | { |
447 | struct cx18 *cx = s->cx; | 454 | struct cx18 *cx = s->cx; |
448 | struct cx18_queue *q; | 455 | struct cx18_queue *q; |
@@ -451,16 +458,16 @@ struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s, | |||
451 | if (s->handle == CX18_INVALID_TASK_HANDLE || | 458 | if (s->handle == CX18_INVALID_TASK_HANDLE || |
452 | test_bit(CX18_F_S_STOPPING, &s->s_flags) || | 459 | test_bit(CX18_F_S_STOPPING, &s->s_flags) || |
453 | !test_bit(CX18_F_S_STREAMING, &s->s_flags)) | 460 | !test_bit(CX18_F_S_STREAMING, &s->s_flags)) |
454 | return cx18_enqueue(s, buf, &s->q_free); | 461 | return cx18_enqueue(s, mdl, &s->q_free); |
455 | 462 | ||
456 | q = cx18_enqueue(s, buf, &s->q_busy); | 463 | q = cx18_enqueue(s, mdl, &s->q_busy); |
457 | if (q != &s->q_busy) | 464 | if (q != &s->q_busy) |
458 | return q; /* The firmware has the max buffers it can handle */ | 465 | return q; /* The firmware has the max MDLs it can handle */ |
459 | 466 | ||
460 | cx18_buf_sync_for_device(s, buf); | 467 | cx18_mdl_sync_for_device(s, mdl); |
461 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | 468 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, |
462 | (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | 469 | (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem, |
463 | 1, buf->id, s->buf_size); | 470 | s->bufs_per_mdl, mdl->id, s->mdl_size); |
464 | return q; | 471 | return q; |
465 | } | 472 | } |
466 | 473 | ||
@@ -468,19 +475,19 @@ static | |||
468 | void _cx18_stream_load_fw_queue(struct cx18_stream *s) | 475 | void _cx18_stream_load_fw_queue(struct cx18_stream *s) |
469 | { | 476 | { |
470 | struct cx18_queue *q; | 477 | struct cx18_queue *q; |
471 | struct cx18_buffer *buf; | 478 | struct cx18_mdl *mdl; |
472 | 479 | ||
473 | if (atomic_read(&s->q_free.buffers) == 0 || | 480 | if (atomic_read(&s->q_free.depth) == 0 || |
474 | atomic_read(&s->q_busy.buffers) >= CX18_MAX_FW_MDLS_PER_STREAM) | 481 | atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) |
475 | return; | 482 | return; |
476 | 483 | ||
477 | /* Move from q_free to q_busy notifying the firmware, until the limit */ | 484 | /* Move from q_free to q_busy notifying the firmware, until the limit */ |
478 | do { | 485 | do { |
479 | buf = cx18_dequeue(s, &s->q_free); | 486 | mdl = cx18_dequeue(s, &s->q_free); |
480 | if (buf == NULL) | 487 | if (mdl == NULL) |
481 | break; | 488 | break; |
482 | q = _cx18_stream_put_buf_fw(s, buf); | 489 | q = _cx18_stream_put_mdl_fw(s, mdl); |
483 | } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM | 490 | } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM |
484 | && q == &s->q_busy); | 491 | && q == &s->q_busy); |
485 | } | 492 | } |
486 | 493 | ||
@@ -492,11 +499,51 @@ void cx18_out_work_handler(struct work_struct *work) | |||
492 | _cx18_stream_load_fw_queue(s); | 499 | _cx18_stream_load_fw_queue(s); |
493 | } | 500 | } |
494 | 501 | ||
502 | static void cx18_stream_configure_mdls(struct cx18_stream *s) | ||
503 | { | ||
504 | cx18_unload_queues(s); | ||
505 | |||
506 | switch (s->type) { | ||
507 | case CX18_ENC_STREAM_TYPE_YUV: | ||
508 | /* | ||
509 | * Height should be a multiple of 32 lines. | ||
510 | * Set the MDL size to the exact size needed for one frame. | ||
511 | * Use enough buffers per MDL to cover the MDL size | ||
512 | */ | ||
513 | s->mdl_size = 720 * s->cx->params.height * 3 / 2; | ||
514 | s->bufs_per_mdl = s->mdl_size / s->buf_size; | ||
515 | if (s->mdl_size % s->buf_size) | ||
516 | s->bufs_per_mdl++; | ||
517 | break; | ||
518 | case CX18_ENC_STREAM_TYPE_VBI: | ||
519 | s->bufs_per_mdl = 1; | ||
520 | if (cx18_raw_vbi(s->cx)) { | ||
521 | s->mdl_size = (s->cx->is_60hz ? 12 : 18) | ||
522 | * 2 * vbi_active_samples; | ||
523 | } else { | ||
524 | /* | ||
525 | * See comment in cx18_vbi_setup() below about the | ||
526 | * extra lines we capture in sliced VBI mode due to | ||
527 | * the lines on which EAV RP codes toggle. | ||
528 | */ | ||
529 | s->mdl_size = s->cx->is_60hz | ||
530 | ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz | ||
531 | : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz; | ||
532 | } | ||
533 | break; | ||
534 | default: | ||
535 | s->bufs_per_mdl = 1; | ||
536 | s->mdl_size = s->buf_size * s->bufs_per_mdl; | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | cx18_load_queues(s); | ||
541 | } | ||
542 | |||
495 | int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | 543 | int cx18_start_v4l2_encode_stream(struct cx18_stream *s) |
496 | { | 544 | { |
497 | u32 data[MAX_MB_ARGUMENTS]; | 545 | u32 data[MAX_MB_ARGUMENTS]; |
498 | struct cx18 *cx = s->cx; | 546 | struct cx18 *cx = s->cx; |
499 | struct cx18_buffer *buf; | ||
500 | int captype = 0; | 547 | int captype = 0; |
501 | struct cx18_api_func_private priv; | 548 | struct cx18_api_func_private priv; |
502 | 549 | ||
@@ -619,14 +666,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
619 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); | 666 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); |
620 | 667 | ||
621 | /* Init all the cpu_mdls for this stream */ | 668 | /* Init all the cpu_mdls for this stream */ |
622 | cx18_flush_queues(s); | 669 | cx18_stream_configure_mdls(s); |
623 | spin_lock(&s->q_free.lock); | ||
624 | list_for_each_entry(buf, &s->q_free.list, list) { | ||
625 | cx18_writel(cx, buf->dma_handle, | ||
626 | &cx->scb->cpu_mdl[buf->id].paddr); | ||
627 | cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); | ||
628 | } | ||
629 | spin_unlock(&s->q_free.lock); | ||
630 | _cx18_stream_load_fw_queue(s); | 670 | _cx18_stream_load_fw_queue(s); |
631 | 671 | ||
632 | /* begin_capture */ | 672 | /* begin_capture */ |
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 1afc3fd9d822..4a01db5e5a35 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h | |||
@@ -28,18 +28,18 @@ int cx18_streams_setup(struct cx18 *cx); | |||
28 | int cx18_streams_register(struct cx18 *cx); | 28 | int cx18_streams_register(struct cx18 *cx); |
29 | void cx18_streams_cleanup(struct cx18 *cx, int unregister); | 29 | void cx18_streams_cleanup(struct cx18 *cx, int unregister); |
30 | 30 | ||
31 | /* Related to submission of buffers to firmware */ | 31 | /* Related to submission of mdls to firmware */ |
32 | static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) | 32 | static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) |
33 | { | 33 | { |
34 | struct cx18 *cx = s->cx; | 34 | struct cx18 *cx = s->cx; |
35 | queue_work(cx->out_work_queue, &s->out_work_order); | 35 | queue_work(cx->out_work_queue, &s->out_work_order); |
36 | } | 36 | } |
37 | 37 | ||
38 | static inline void cx18_stream_put_buf_fw(struct cx18_stream *s, | 38 | static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, |
39 | struct cx18_buffer *buf) | 39 | struct cx18_mdl *mdl) |
40 | { | 40 | { |
41 | /* Put buf on q_free; the out work handler will move buf(s) to q_busy */ | 41 | /* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */ |
42 | cx18_enqueue(s, buf, &s->q_free); | 42 | cx18_enqueue(s, mdl, &s->q_free); |
43 | cx18_stream_load_fw_queue(s); | 43 | cx18_stream_load_fw_queue(s); |
44 | } | 44 | } |
45 | 45 | ||
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c index c2aef4add31d..574c1c6974f8 100644 --- a/drivers/media/video/cx18/cx18-vbi.c +++ b/drivers/media/video/cx18/cx18-vbi.c | |||
@@ -105,6 +105,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) | |||
105 | 105 | ||
106 | /* Compress raw VBI format, removes leading SAV codes and surplus space | 106 | /* Compress raw VBI format, removes leading SAV codes and surplus space |
107 | after the frame. Returns new compressed size. */ | 107 | after the frame. Returns new compressed size. */ |
108 | /* FIXME - this function ignores the input size. */ | ||
108 | static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) | 109 | static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) |
109 | { | 110 | { |
110 | u32 line_size = vbi_active_samples; | 111 | u32 line_size = vbi_active_samples; |
@@ -185,8 +186,7 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, | |||
185 | return line; | 186 | return line; |
186 | } | 187 | } |
187 | 188 | ||
188 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | 189 | static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf) |
189 | int streamtype) | ||
190 | { | 190 | { |
191 | /* | 191 | /* |
192 | * The CX23418 provides a 12 byte header in its raw VBI buffers to us: | 192 | * The CX23418 provides a 12 byte header in its raw VBI buffers to us: |
@@ -203,9 +203,6 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | |||
203 | u32 pts; | 203 | u32 pts; |
204 | int lines; | 204 | int lines; |
205 | 205 | ||
206 | if (streamtype != CX18_ENC_STREAM_TYPE_VBI) | ||
207 | return; | ||
208 | |||
209 | /* | 206 | /* |
210 | * The CX23418 sends us data that is 32 bit little-endian swapped, | 207 | * The CX23418 sends us data that is 32 bit little-endian swapped, |
211 | * but we want the raw VBI bytes in the order they were in the raster | 208 | * but we want the raw VBI bytes in the order they were in the raster |
@@ -250,3 +247,31 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | |||
250 | copy_vbi_data(cx, lines, pts); | 247 | copy_vbi_data(cx, lines, pts); |
251 | cx->vbi.frame++; | 248 | cx->vbi.frame++; |
252 | } | 249 | } |
250 | |||
251 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, | ||
252 | int streamtype) | ||
253 | { | ||
254 | struct cx18_buffer *buf; | ||
255 | u32 orig_used; | ||
256 | |||
257 | if (streamtype != CX18_ENC_STREAM_TYPE_VBI) | ||
258 | return; | ||
259 | |||
260 | /* | ||
261 | * Big assumption here: | ||
262 | * Every buffer hooked to the MDL's buf_list is a complete VBI frame | ||
263 | * that ends at the end of the buffer. | ||
264 | * | ||
265 | * To assume anything else would make the code in this file | ||
266 | * more complex, or require extra memcpy()'s to make the | ||
267 | * buffers satisfy the above assumption. It's just simpler to set | ||
268 | * up the encoder buffer transfers to make the assumption true. | ||
269 | */ | ||
270 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
271 | orig_used = buf->bytesused; | ||
272 | if (orig_used == 0) | ||
273 | break; | ||
274 | _cx18_process_vbi_data(cx, buf); | ||
275 | mdl->bytesused -= (orig_used - buf->bytesused); | ||
276 | } | ||
277 | } | ||
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h index e7e1ae427f34..b365cf4b4668 100644 --- a/drivers/media/video/cx18/cx18-vbi.h +++ b/drivers/media/video/cx18/cx18-vbi.h | |||
@@ -21,6 +21,6 @@ | |||
21 | * 02111-1307 USA | 21 | * 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | 24 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, |
25 | int streamtype); | 25 | int streamtype); |
26 | int cx18_used_line(struct cx18 *cx, int line, int field); | 26 | int cx18_used_line(struct cx18 *cx, int line, int field); |
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h index 45494b094e7f..9c0b5bb1b019 100644 --- a/drivers/media/video/cx18/cx18-version.h +++ b/drivers/media/video/cx18/cx18-version.h | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #define CX18_DRIVER_NAME "cx18" | 25 | #define CX18_DRIVER_NAME "cx18" |
26 | #define CX18_DRIVER_VERSION_MAJOR 1 | 26 | #define CX18_DRIVER_VERSION_MAJOR 1 |
27 | #define CX18_DRIVER_VERSION_MINOR 2 | 27 | #define CX18_DRIVER_VERSION_MINOR 3 |
28 | #define CX18_DRIVER_VERSION_PATCHLEVEL 0 | 28 | #define CX18_DRIVER_VERSION_PATCHLEVEL 0 |
29 | 29 | ||
30 | #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) | 30 | #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) |
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 9956abf576c5..868806effdcf 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h | |||
@@ -363,7 +363,7 @@ | |||
363 | /* Description: This command provides the offset to a Memory Descriptor List | 363 | /* Description: This command provides the offset to a Memory Descriptor List |
364 | IN[0] - Task handle. Handle of the task to start | 364 | IN[0] - Task handle. Handle of the task to start |
365 | IN[1] - Offset of the MDL from the beginning of the local DDR. | 365 | IN[1] - Offset of the MDL from the beginning of the local DDR. |
366 | IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1] | 366 | IN[2] - Number of cx18_mdl_ent structures in the array pointed to by IN[1] |
367 | IN[3] - Buffer ID | 367 | IN[3] - Buffer ID |
368 | IN[4] - Total buffer length | 368 | IN[4] - Total buffer length |
369 | ReturnCode - One of the ERR_DE_... */ | 369 | ReturnCode - One of the ERR_DE_... */ |