diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-08-19 10:21:50 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-08-24 03:30:01 -0400 |
commit | b8f0fff4279a1b85fa4b6d7d8b538c254edcb4a1 (patch) | |
tree | 9ab3d196fe8e7633baa8b7bb6726af43d8187710 | |
parent | 70b654945bacd27622ef1c424f054ae04de597e0 (diff) |
[media] v4l2-dv-timings: add callback to handle exceptions
In most cases the v4l2_bt_timings_cap struct has all the information
necessary to determine valid timings, but occasionally there are exceptions.
Add a callback function to be able to test for those exceptions.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r-- | drivers/media/i2c/ad9389b.c | 7 | ||||
-rw-r--r-- | drivers/media/i2c/ths8200.c | 9 | ||||
-rw-r--r-- | drivers/media/v4l2-core/v4l2-dv-timings.c | 25 | ||||
-rw-r--r-- | include/media/v4l2-dv-timings.h | 34 |
4 files changed, 55 insertions, 20 deletions
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index fc608516fc43..836978602973 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c | |||
@@ -648,12 +648,12 @@ static int ad9389b_s_dv_timings(struct v4l2_subdev *sd, | |||
648 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); | 648 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); |
649 | 649 | ||
650 | /* quick sanity check */ | 650 | /* quick sanity check */ |
651 | if (!v4l2_valid_dv_timings(timings, &ad9389b_timings_cap)) | 651 | if (!v4l2_valid_dv_timings(timings, &ad9389b_timings_cap, NULL, NULL)) |
652 | return -EINVAL; | 652 | return -EINVAL; |
653 | 653 | ||
654 | /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings | 654 | /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings |
655 | if the format is one of the CEA or DMT timings. */ | 655 | if the format is one of the CEA or DMT timings. */ |
656 | v4l2_find_dv_timings_cap(timings, &ad9389b_timings_cap, 0); | 656 | v4l2_find_dv_timings_cap(timings, &ad9389b_timings_cap, 0, NULL, NULL); |
657 | 657 | ||
658 | timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS; | 658 | timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS; |
659 | 659 | ||
@@ -691,7 +691,8 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd, | |||
691 | static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd, | 691 | static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd, |
692 | struct v4l2_enum_dv_timings *timings) | 692 | struct v4l2_enum_dv_timings *timings) |
693 | { | 693 | { |
694 | return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap); | 694 | return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap, |
695 | NULL, NULL); | ||
695 | } | 696 | } |
696 | 697 | ||
697 | static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd, | 698 | static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd, |
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index 6abf0fb36079..a58a8f663ffb 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c | |||
@@ -378,10 +378,12 @@ static int ths8200_s_dv_timings(struct v4l2_subdev *sd, | |||
378 | 378 | ||
379 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); | 379 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); |
380 | 380 | ||
381 | if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap)) | 381 | if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap, |
382 | NULL, NULL)) | ||
382 | return -EINVAL; | 383 | return -EINVAL; |
383 | 384 | ||
384 | if (!v4l2_find_dv_timings_cap(timings, &ths8200_timings_cap, 10)) { | 385 | if (!v4l2_find_dv_timings_cap(timings, &ths8200_timings_cap, 10, |
386 | NULL, NULL)) { | ||
385 | v4l2_dbg(1, debug, sd, "Unsupported format\n"); | 387 | v4l2_dbg(1, debug, sd, "Unsupported format\n"); |
386 | return -EINVAL; | 388 | return -EINVAL; |
387 | } | 389 | } |
@@ -411,7 +413,8 @@ static int ths8200_g_dv_timings(struct v4l2_subdev *sd, | |||
411 | static int ths8200_enum_dv_timings(struct v4l2_subdev *sd, | 413 | static int ths8200_enum_dv_timings(struct v4l2_subdev *sd, |
412 | struct v4l2_enum_dv_timings *timings) | 414 | struct v4l2_enum_dv_timings *timings) |
413 | { | 415 | { |
414 | return v4l2_enum_dv_timings_cap(timings, &ths8200_timings_cap); | 416 | return v4l2_enum_dv_timings_cap(timings, &ths8200_timings_cap, |
417 | NULL, NULL); | ||
415 | } | 418 | } |
416 | 419 | ||
417 | static int ths8200_dv_timings_cap(struct v4l2_subdev *sd, | 420 | static int ths8200_dv_timings_cap(struct v4l2_subdev *sd, |
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index a77f20145881..ee52b9f4a944 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c | |||
@@ -132,7 +132,9 @@ const struct v4l2_dv_timings v4l2_dv_timings_presets[] = { | |||
132 | EXPORT_SYMBOL_GPL(v4l2_dv_timings_presets); | 132 | EXPORT_SYMBOL_GPL(v4l2_dv_timings_presets); |
133 | 133 | ||
134 | bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t, | 134 | bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t, |
135 | const struct v4l2_dv_timings_cap *dvcap) | 135 | const struct v4l2_dv_timings_cap *dvcap, |
136 | v4l2_check_dv_timings_fnc fnc, | ||
137 | void *fnc_handle) | ||
136 | { | 138 | { |
137 | const struct v4l2_bt_timings *bt = &t->bt; | 139 | const struct v4l2_bt_timings *bt = &t->bt; |
138 | const struct v4l2_bt_timings_cap *cap = &dvcap->bt; | 140 | const struct v4l2_bt_timings_cap *cap = &dvcap->bt; |
@@ -151,18 +153,21 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t, | |||
151 | (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) || | 153 | (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) || |
152 | (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE))) | 154 | (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE))) |
153 | return false; | 155 | return false; |
154 | return true; | 156 | return fnc == NULL || fnc(t, fnc_handle); |
155 | } | 157 | } |
156 | EXPORT_SYMBOL_GPL(v4l2_valid_dv_timings); | 158 | EXPORT_SYMBOL_GPL(v4l2_valid_dv_timings); |
157 | 159 | ||
158 | int v4l2_enum_dv_timings_cap(struct v4l2_enum_dv_timings *t, | 160 | int v4l2_enum_dv_timings_cap(struct v4l2_enum_dv_timings *t, |
159 | const struct v4l2_dv_timings_cap *cap) | 161 | const struct v4l2_dv_timings_cap *cap, |
162 | v4l2_check_dv_timings_fnc fnc, | ||
163 | void *fnc_handle) | ||
160 | { | 164 | { |
161 | u32 i, idx; | 165 | u32 i, idx; |
162 | 166 | ||
163 | memset(t->reserved, 0, sizeof(t->reserved)); | 167 | memset(t->reserved, 0, sizeof(t->reserved)); |
164 | for (i = idx = 0; v4l2_dv_timings_presets[i].bt.width; i++) { | 168 | for (i = idx = 0; v4l2_dv_timings_presets[i].bt.width; i++) { |
165 | if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap) && | 169 | if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap, |
170 | fnc, fnc_handle) && | ||
166 | idx++ == t->index) { | 171 | idx++ == t->index) { |
167 | t->timings = v4l2_dv_timings_presets[i]; | 172 | t->timings = v4l2_dv_timings_presets[i]; |
168 | return 0; | 173 | return 0; |
@@ -174,16 +179,20 @@ EXPORT_SYMBOL_GPL(v4l2_enum_dv_timings_cap); | |||
174 | 179 | ||
175 | bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, | 180 | bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, |
176 | const struct v4l2_dv_timings_cap *cap, | 181 | const struct v4l2_dv_timings_cap *cap, |
177 | unsigned pclock_delta) | 182 | unsigned pclock_delta, |
183 | v4l2_check_dv_timings_fnc fnc, | ||
184 | void *fnc_handle) | ||
178 | { | 185 | { |
179 | int i; | 186 | int i; |
180 | 187 | ||
181 | if (!v4l2_valid_dv_timings(t, cap)) | 188 | if (!v4l2_valid_dv_timings(t, cap, fnc, fnc_handle)) |
182 | return false; | 189 | return false; |
183 | 190 | ||
184 | for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { | 191 | for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { |
185 | if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap) && | 192 | if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap, |
186 | v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i, pclock_delta)) { | 193 | fnc, fnc_handle) && |
194 | v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i, | ||
195 | pclock_delta)) { | ||
187 | *t = v4l2_dv_timings_presets[i]; | 196 | *t = v4l2_dv_timings_presets[i]; |
188 | return true; | 197 | return true; |
189 | } | 198 | } |
diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index bd59df8125c6..4becc6716393 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h | |||
@@ -27,46 +27,68 @@ | |||
27 | */ | 27 | */ |
28 | extern const struct v4l2_dv_timings v4l2_dv_timings_presets[]; | 28 | extern const struct v4l2_dv_timings v4l2_dv_timings_presets[]; |
29 | 29 | ||
30 | /** v4l2_check_dv_timings_fnc - timings check callback | ||
31 | * @t: the v4l2_dv_timings struct. | ||
32 | * @handle: a handle from the driver. | ||
33 | * | ||
34 | * Returns true if the given timings are valid. | ||
35 | */ | ||
36 | typedef bool v4l2_check_dv_timings_fnc(const struct v4l2_dv_timings *t, void *handle); | ||
37 | |||
30 | /** v4l2_valid_dv_timings() - are these timings valid? | 38 | /** v4l2_valid_dv_timings() - are these timings valid? |
31 | * @t: the v4l2_dv_timings struct. | 39 | * @t: the v4l2_dv_timings struct. |
32 | * @cap: the v4l2_dv_timings_cap capabilities. | 40 | * @cap: the v4l2_dv_timings_cap capabilities. |
41 | * @fnc: callback to check if this timing is OK. May be NULL. | ||
42 | * @fnc_handle: a handle that is passed on to @fnc. | ||
33 | * | 43 | * |
34 | * Returns true if the given dv_timings struct is supported by the | 44 | * Returns true if the given dv_timings struct is supported by the |
35 | * hardware capabilities, returns false otherwise. | 45 | * hardware capabilities and the callback function (if non-NULL), returns |
46 | * false otherwise. | ||
36 | */ | 47 | */ |
37 | bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t, | 48 | bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t, |
38 | const struct v4l2_dv_timings_cap *cap); | 49 | const struct v4l2_dv_timings_cap *cap, |
50 | v4l2_check_dv_timings_fnc fnc, | ||
51 | void *fnc_handle); | ||
39 | 52 | ||
40 | /** v4l2_enum_dv_timings_cap() - Helper function to enumerate possible DV timings based on capabilities | 53 | /** v4l2_enum_dv_timings_cap() - Helper function to enumerate possible DV timings based on capabilities |
41 | * @t: the v4l2_enum_dv_timings struct. | 54 | * @t: the v4l2_enum_dv_timings struct. |
42 | * @cap: the v4l2_dv_timings_cap capabilities. | 55 | * @cap: the v4l2_dv_timings_cap capabilities. |
56 | * @fnc: callback to check if this timing is OK. May be NULL. | ||
57 | * @fnc_handle: a handle that is passed on to @fnc. | ||
43 | * | 58 | * |
44 | * This enumerates dv_timings using the full list of possible CEA-861 and DMT | 59 | * This enumerates dv_timings using the full list of possible CEA-861 and DMT |
45 | * timings, filtering out any timings that are not supported based on the | 60 | * timings, filtering out any timings that are not supported based on the |
46 | * hardware capabilities. | 61 | * hardware capabilities and the callback function (if non-NULL). |
47 | * | 62 | * |
48 | * If a valid timing for the given index is found, it will fill in @t and | 63 | * If a valid timing for the given index is found, it will fill in @t and |
49 | * return 0, otherwise it returns -EINVAL. | 64 | * return 0, otherwise it returns -EINVAL. |
50 | */ | 65 | */ |
51 | int v4l2_enum_dv_timings_cap(struct v4l2_enum_dv_timings *t, | 66 | int v4l2_enum_dv_timings_cap(struct v4l2_enum_dv_timings *t, |
52 | const struct v4l2_dv_timings_cap *cap); | 67 | const struct v4l2_dv_timings_cap *cap, |
68 | v4l2_check_dv_timings_fnc fnc, | ||
69 | void *fnc_handle); | ||
53 | 70 | ||
54 | /** v4l2_find_dv_timings_cap() - Find the closest timings struct | 71 | /** v4l2_find_dv_timings_cap() - Find the closest timings struct |
55 | * @t: the v4l2_enum_dv_timings struct. | 72 | * @t: the v4l2_enum_dv_timings struct. |
56 | * @cap: the v4l2_dv_timings_cap capabilities. | 73 | * @cap: the v4l2_dv_timings_cap capabilities. |
57 | * @pclock_delta: maximum delta between t->pixelclock and the timing struct | 74 | * @pclock_delta: maximum delta between t->pixelclock and the timing struct |
58 | * under consideration. | 75 | * under consideration. |
76 | * @fnc: callback to check if a given timings struct is OK. May be NULL. | ||
77 | * @fnc_handle: a handle that is passed on to @fnc. | ||
59 | * | 78 | * |
60 | * This function tries to map the given timings to an entry in the | 79 | * This function tries to map the given timings to an entry in the |
61 | * full list of possible CEA-861 and DMT timings, filtering out any timings | 80 | * full list of possible CEA-861 and DMT timings, filtering out any timings |
62 | * that are not supported based on the hardware capabilities. | 81 | * that are not supported based on the hardware capabilities and the callback |
82 | * function (if non-NULL). | ||
63 | * | 83 | * |
64 | * On success it will fill in @t with the found timings and it returns true. | 84 | * On success it will fill in @t with the found timings and it returns true. |
65 | * On failure it will return false. | 85 | * On failure it will return false. |
66 | */ | 86 | */ |
67 | bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, | 87 | bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, |
68 | const struct v4l2_dv_timings_cap *cap, | 88 | const struct v4l2_dv_timings_cap *cap, |
69 | unsigned pclock_delta); | 89 | unsigned pclock_delta, |
90 | v4l2_check_dv_timings_fnc fnc, | ||
91 | void *fnc_handle); | ||
70 | 92 | ||
71 | /** v4l2_match_dv_timings() - do two timings match? | 93 | /** v4l2_match_dv_timings() - do two timings match? |
72 | * @measured: the measured timings data. | 94 | * @measured: the measured timings data. |