1 /* $NetBSD: pickmode.c,v 1.4 2011/04/09 20:53:39 christos Exp $ */
4 * Copyright (c) 2006 The NetBSD Foundation
7 * this code was contributed to The NetBSD Foundation by Michael Lorenz
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE NETBSD FOUNDATION BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: pickmode.c,v 1.4 2011/04/09 20:53:39 christos Exp $");
34 #include <sys/param.h>
35 #include <dev/videomode/videomode.h>
37 #include "opt_videomode.h"
39 #include <lib/libkern/libkern.h>
40 #include <minix/sysutil.h>
41 #endif /* !defined(__minix) */
44 #define DPRINTF printf
46 #define DPRINTF while (0) printf
49 const struct videomode
*
50 pick_mode_by_dotclock(int width
, int height
, int dotclock
)
52 const struct videomode
*this, *best
= NULL
;
55 DPRINTF("%s: looking for %d x %d at up to %d kHz\n", __func__
, width
,
57 for (i
= 0; i
< videomode_count
; i
++) {
58 this = &videomode_list
[i
];
59 if ((this->hdisplay
!= width
) || (this->vdisplay
!= height
) ||
60 (this->dot_clock
> dotclock
))
63 if (this->dot_clock
> best
->dot_clock
)
69 DPRINTF("found %s\n", best
->name
);
74 const struct videomode
*
75 pick_mode_by_ref(int width
, int height
, int refresh
)
77 const struct videomode
*this, *best
= NULL
;
78 int mref
, closest
= 1000, i
, diff
;
80 DPRINTF("%s: looking for %d x %d at up to %d Hz\n", __func__
, width
,
82 for (i
= 0; i
< videomode_count
; i
++) {
84 this = &videomode_list
[i
];
85 mref
= this->dot_clock
* 1000 / (this->htotal
* this->vtotal
);
86 diff
= abs(mref
- refresh
);
87 if ((this->hdisplay
!= width
) || (this->vdisplay
!= height
))
89 DPRINTF("%s in %d hz, diff %d\n", this->name
, mref
, diff
);
101 DPRINTF("found %s %d\n", best
->name
, best
->dot_clock
);
107 swap_modes(struct videomode
*left
, struct videomode
*right
)
109 struct videomode temp
;
117 * Sort modes by refresh rate, aspect ratio (*), then resolution.
118 * Preferred mode or largest mode is first in the list and other modes
119 * are sorted on closest match to that mode.
120 * (*) Note that the aspect ratio calculation treats "close" aspect ratios
121 * (within 12.5%) as the same for this purpose.
123 #define DIVIDE(x, y) (((x) + ((y) / 2)) / (y))
125 sort_modes(struct videomode
*modes
, struct videomode
**preferred
, int nmodes
)
127 int aspect
, refresh
, hbest
, vbest
, abest
, atemp
, rbest
, rtemp
;
129 struct videomode
*mtemp
= NULL
;
134 if (*preferred
!= NULL
) {
135 /* Put the preferred mode first in the list */
136 aspect
= (*preferred
)->hdisplay
* 100 / (*preferred
)->vdisplay
;
137 refresh
= DIVIDE(DIVIDE((*preferred
)->dot_clock
* 1000,
138 (*preferred
)->htotal
), (*preferred
)->vtotal
);
139 if (*preferred
!= modes
) {
140 swap_modes(*preferred
, modes
);
145 * Find the largest horizontal and vertical mode and put that
146 * first in the list. Preferred refresh rate is taken from
147 * the first mode of this size.
151 for (i
= 0; i
< nmodes
; i
++) {
152 if (modes
[i
].hdisplay
> hbest
) {
153 hbest
= modes
[i
].hdisplay
;
154 vbest
= modes
[i
].vdisplay
;
156 } else if (modes
[i
].hdisplay
== hbest
&&
157 modes
[i
].vdisplay
> vbest
) {
158 vbest
= modes
[i
].vdisplay
;
162 aspect
= mtemp
->hdisplay
* 100 / mtemp
->vdisplay
;
163 refresh
= DIVIDE(DIVIDE(mtemp
->dot_clock
* 1000,
164 mtemp
->htotal
), mtemp
->vtotal
);
166 swap_modes(mtemp
, modes
);
169 /* Sort other modes by refresh rate, aspect ratio, then resolution */
170 for (j
= 1; j
< nmodes
- 1; j
++) {
175 for (i
= j
; i
< nmodes
; i
++) {
176 rtemp
= abs(refresh
-
177 DIVIDE(DIVIDE(modes
[i
].dot_clock
* 1000,
178 modes
[i
].htotal
), modes
[i
].vtotal
));
179 atemp
= (modes
[i
].hdisplay
* 100 / modes
[i
].vdisplay
);
184 if (rtemp
== rbest
) {
185 /* Treat "close" aspect ratios as identical */
186 if (abs(abest
- atemp
) > (abest
/ 8) &&
187 abs(aspect
- atemp
) < abs(aspect
- abest
)) {
191 if (atemp
== abest
||
192 abs(abest
- atemp
) <= (abest
/ 8)) {
193 if (modes
[i
].hdisplay
> hbest
) {
194 hbest
= modes
[i
].hdisplay
;
197 if (modes
[i
].hdisplay
== hbest
&&
198 modes
[i
].vdisplay
> vbest
) {
199 vbest
= modes
[i
].vdisplay
;
205 if (mtemp
!= &modes
[j
])
206 swap_modes(mtemp
, &modes
[j
]);