Deleted Added
full compact
s3_pci.c (111462) s3_pci.c (119277)
1/*-
2 * Copyright (c) 2000 Alcove - Nicolas Souchu <nsouch@freebsd.org>
3 * All rights reserved.
4 *
5 * Code based on Peter Horton <pdh@colonel-panic.com> patch.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
1/*-
2 * Copyright (c) 2000 Alcove - Nicolas Souchu <nsouch@freebsd.org>
3 * All rights reserved.
4 *
5 * Code based on Peter Horton <pdh@colonel-panic.com> patch.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/dev/fb/s3_pci.c 111462 2003-02-25 03:21:22Z mux $
28 * $FreeBSD: head/sys/dev/fb/s3_pci.c 119277 2003-08-22 05:54:52Z imp $
29 *
30 */
31
32/* Enable LFB on S3 cards that has only VESA 1.2 BIOS */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <machine/bus_pio.h>
38#include <machine/bus_memio.h>
39#include <machine/bus.h>
40
41#include <vm/vm.h>
42#include <vm/vm_extern.h>
43#include <vm/vm_kern.h>
44#include <vm/pmap.h>
45
46#include <sys/uio.h>
47#include <sys/module.h>
48#include <sys/bus.h>
49#include <sys/rman.h>
50#include <machine/resource.h>
51
52#include <sys/malloc.h>
53#include <sys/fbio.h>
54
29 *
30 */
31
32/* Enable LFB on S3 cards that has only VESA 1.2 BIOS */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <machine/bus_pio.h>
38#include <machine/bus_memio.h>
39#include <machine/bus.h>
40
41#include <vm/vm.h>
42#include <vm/vm_extern.h>
43#include <vm/vm_kern.h>
44#include <vm/pmap.h>
45
46#include <sys/uio.h>
47#include <sys/module.h>
48#include <sys/bus.h>
49#include <sys/rman.h>
50#include <machine/resource.h>
51
52#include <sys/malloc.h>
53#include <sys/fbio.h>
54
55#include
56#include
55#include <dev/pci/pcireg.h>
56#include <dev/pci/pcivar.h>
57
58#include <machine/md_var.h>
59#include <machine/vm86.h>
60#include <machine/pc/bios.h>
61#include <machine/pc/vesa.h>
62
63#include <dev/fb/fbreg.h>
64#include <dev/fb/vgareg.h>
65
66#define S3PCI_DEBUG 1
67
68#define PCI_S3_VENDOR_ID 0x5333
69
70#define S3_CONFIG_IO 0x3c0 /* VGA standard config io ports */
71#define S3_CONFIG_IO_SIZE 0x20
72
73#define S3_ENHANCED_IO 0x4ae8 /* Extended config register */
74#define S3_ENHANCED_IO_SIZE 1
75
76#define S3_CRTC_ADDR 0x14
77#define S3_CRTC_VALUE 0x15
78
79#define PCI_BASE_MEMORY 0x10
80
81#define outb_p(value, offset) bus_space_write_1(sc->st, sc->sh, offset, value)
82#define inb_p(offset) (bus_space_read_1(sc->st, sc->sh, offset))
83#define outb_enh(value, offset) bus_space_write_1(sc->enh_st, sc->enh_sh, \
84 offset, value)
85#define inb_enh(offset) (bus_space_read_1(sc->enh_st, sc->enh_sh, offset))
86
87struct s3pci_softc {
88 bus_space_tag_t st;
89 bus_space_handle_t sh;
90 bus_space_tag_t enh_st;
91 bus_space_handle_t enh_sh;
92 struct resource *port_res;
93 struct resource *enh_res;
94 struct resource *mem_res;
95 u_long mem_base;
96 u_long mem_size;
97};
98
99static int s3lfb_error(void);
100static vi_probe_t s3lfb_probe;
101static vi_init_t s3lfb_init;
102static vi_get_info_t s3lfb_get_info;
103static vi_query_mode_t s3lfb_query_mode;
104static vi_set_mode_t s3lfb_set_mode;
105static vi_save_font_t s3lfb_save_font;
106static vi_load_font_t s3lfb_load_font;
107static vi_show_font_t s3lfb_show_font;
108static vi_save_palette_t s3lfb_save_palette;
109static vi_load_palette_t s3lfb_load_palette;
110static vi_set_border_t s3lfb_set_border;
111static vi_save_state_t s3lfb_save_state;
112static vi_load_state_t s3lfb_load_state;
113static vi_set_win_org_t s3lfb_set_origin;
114static vi_read_hw_cursor_t s3lfb_read_hw_cursor;
115static vi_set_hw_cursor_t s3lfb_set_hw_cursor;
116static vi_set_hw_cursor_shape_t s3lfb_set_hw_cursor_shape;
117static vi_blank_display_t s3lfb_blank_display;
118static vi_mmap_t s3lfb_mmap;
119static vi_ioctl_t s3lfb_ioctl;
120static vi_clear_t s3lfb_clear;
121static vi_fill_rect_t s3lfb_fill_rect;
122static vi_bitblt_t s3lfb_bitblt;
123static vi_diag_t s3lfb_diag;
124
125static video_switch_t s3lfbvidsw = {
126 s3lfb_probe,
127 s3lfb_init,
128 s3lfb_get_info,
129 s3lfb_query_mode,
130 s3lfb_set_mode,
131 s3lfb_save_font,
132 s3lfb_load_font,
133 s3lfb_show_font,
134 s3lfb_save_palette,
135 s3lfb_load_palette,
136 s3lfb_set_border,
137 s3lfb_save_state,
138 s3lfb_load_state,
139 s3lfb_set_origin,
140 s3lfb_read_hw_cursor,
141 s3lfb_set_hw_cursor,
142 s3lfb_set_hw_cursor_shape,
143 s3lfb_blank_display,
144 s3lfb_mmap,
145 s3lfb_ioctl,
146 s3lfb_clear,
147 s3lfb_fill_rect,
148 s3lfb_bitblt,
149 s3lfb_error,
150 s3lfb_error,
151 s3lfb_diag,
152};
153
154static video_switch_t *prevvidsw;
155static device_t s3pci_dev = NULL;
156
157static int
158s3lfb_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
159{
160 return (*prevvidsw->probe)(unit, adpp, arg, flags);
161}
162
163static int
164s3lfb_init(int unit, video_adapter_t *adp, int flags)
165{
166 return (*prevvidsw->init)(unit, adp, flags);
167}
168
169static int
170s3lfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
171{
172#if 0
173 device_t dev = s3pci_dev; /* XXX */
174 struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
175#endif
176 int error;
177
178 if ((error = (*prevvidsw->get_info)(adp, mode, info)))
179 return error;
180
181#if 0
182 /* Don't use linear addressing with text modes
183 */
184 if ((mode > M_VESA_BASE) &&
185 (info->vi_flags & V_INFO_GRAPHICS) &&
186 !(info->vi_flags & V_INFO_LINEAR)) {
187
188 info->vi_flags |= V_INFO_LINEAR;
189 info->vi_buffer = sc->mem_base;
190
191 } else {
192 info->vi_buffer = 0;
193 }
194#endif
195
196 return 0;
197}
198
199static int
200s3lfb_query_mode(video_adapter_t *adp, video_info_t *info)
201{
202 return (*prevvidsw->query_mode)(adp, info);
203}
204
205static vm_offset_t
206s3lfb_map_buffer(u_int paddr, size_t size)
207{
208 vm_offset_t vaddr;
209 u_int off;
210
211 off = paddr - trunc_page(paddr);
212 vaddr = (vm_offset_t)pmap_mapdev(paddr - off, size + off);
213
214 return (vaddr + off);
215}
216
217static int
218s3lfb_set_mode(video_adapter_t *adp, int mode)
219{
220 device_t dev = s3pci_dev; /* XXX */
221 struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
222#if 0
223 unsigned char tmp;
224#endif
225 int error;
226
227 /* First, set the mode as if it was a classic VESA card
228 */
229 if ((error = (*prevvidsw->set_mode)(adp, mode)))
230 return error;
231
232 /* If not in a linear mode (according to s3lfb_get_info() called
233 * by vesa_set_mode in the (*vidsw[adp->va_index]->get_info)...
234 * sequence, return with no error
235 */
236#if 0
237 if (!(adp->va_info.vi_flags & V_INFO_LINEAR))
238 return 0;
239#endif
240
241 if ((mode <= M_VESA_BASE) ||
242 !(adp->va_info.vi_flags & V_INFO_GRAPHICS) ||
243 (adp->va_info.vi_flags & V_INFO_LINEAR))
244 return 0;
245
246 /* Ok, now apply the configuration to the card */
247
248 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x48, S3_CRTC_VALUE);
249 outb_p(0x39, S3_CRTC_ADDR); outb_p(0xa5, S3_CRTC_VALUE);
250
251 /* check that CR47 is read/write */
252
253#if 0
254 outb_p(0x47, S3_CRTC_ADDR); outb_p(0xff, S3_CRTC_VALUE);
255 tmp = inb_p(S3_CRTC_VALUE);
256 outb_p(0x00, S3_CRTC_VALUE);
257 if ((tmp != 0xff) || (inb_p(S3_CRTC_VALUE)))
258 {
259 /* lock S3 registers */
260
261 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
262 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
263
264 return ENXIO;
265 }
266#endif
267
268 /* enable enhanced register access */
269
270 outb_p(0x40, S3_CRTC_ADDR);
271 outb_p(inb_p(S3_CRTC_VALUE) | 1, S3_CRTC_VALUE);
272
273 /* enable enhanced functions */
274
275 outb_enh(inb_enh(0) | 1, 0x0);
276
277 /* enable enhanced mode memory mapping */
278
279 outb_p(0x31, S3_CRTC_ADDR);
280 outb_p(inb_p(S3_CRTC_VALUE) | 8, S3_CRTC_VALUE);
281
282 /* enable linear frame buffer and set address window to max */
283
284 outb_p(0x58, S3_CRTC_ADDR);
285 outb_p(inb_p(S3_CRTC_VALUE) | 0x13, S3_CRTC_VALUE);
286
287 /* disabled enhanced register access */
288
289 outb_p(0x40, S3_CRTC_ADDR);
290 outb_p(inb_p(S3_CRTC_VALUE) & ~1, S3_CRTC_VALUE);
291
292 /* lock S3 registers */
293
294 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
295 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
296
297 adp->va_info.vi_flags |= V_INFO_LINEAR;
298 adp->va_info.vi_buffer = sc->mem_base;
299 adp->va_buffer = s3lfb_map_buffer(adp->va_info.vi_buffer,
300 adp->va_info.vi_buffer_size);
301 adp->va_buffer_size = adp->va_info.vi_buffer_size;
302 adp->va_window = adp->va_buffer;
303 adp->va_window_size = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
304 adp->va_window_gran = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
305
306 return 0;
307}
308
309static int
310s3lfb_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
311 int ch, int count)
312{
313 return (*prevvidsw->save_font)(adp, page, fontsize, data, ch, count);
314}
315
316static int
317s3lfb_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
318 int ch, int count)
319{
320 return (*prevvidsw->load_font)(adp, page, fontsize, data, ch, count);
321}
322
323static int
324s3lfb_show_font(video_adapter_t *adp, int page)
325{
326 return (*prevvidsw->show_font)(adp, page);
327}
328
329static int
330s3lfb_save_palette(video_adapter_t *adp, u_char *palette)
331{
332 return (*prevvidsw->save_palette)(adp, palette);
333}
334
335static int
336s3lfb_load_palette(video_adapter_t *adp, u_char *palette)
337{
338 return (*prevvidsw->load_palette)(adp, palette);
339}
340
341static int
342s3lfb_set_border(video_adapter_t *adp, int color)
343{
344 return (*prevvidsw->set_border)(adp, color);
345}
346
347static int
348s3lfb_save_state(video_adapter_t *adp, void *p, size_t size)
349{
350 return (*prevvidsw->save_state)(adp, p, size);
351}
352
353static int
354s3lfb_load_state(video_adapter_t *adp, void *p)
355{
356 return (*prevvidsw->load_state)(adp, p);
357}
358
359static int
360s3lfb_set_origin(video_adapter_t *adp, off_t offset)
361{
362 return (*prevvidsw->set_win_org)(adp, offset);
363}
364
365static int
366s3lfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
367{
368 return (*prevvidsw->read_hw_cursor)(adp, col, row);
369}
370
371static int
372s3lfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
373{
374 return (*prevvidsw->set_hw_cursor)(adp, col, row);
375}
376
377static int
378s3lfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
379 int celsize, int blink)
380{
381 return (*prevvidsw->set_hw_cursor_shape)(adp, base, height,
382 celsize, blink);
383}
384
385static int
386s3lfb_blank_display(video_adapter_t *adp, int mode)
387{
388 return (*prevvidsw->blank_display)(adp, mode);
389}
390
391static int
392s3lfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr,
393 int prot)
394{
395 return (*prevvidsw->mmap)(adp, offset, paddr, prot);
396}
397
398static int
399s3lfb_clear(video_adapter_t *adp)
400{
401 return (*prevvidsw->clear)(adp);
402}
403
404static int
405s3lfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
406{
407 return (*prevvidsw->fill_rect)(adp, val, x, y, cx, cy);
408}
409
410static int
411s3lfb_bitblt(video_adapter_t *adp,...)
412{
413 return (*prevvidsw->bitblt)(adp); /* XXX */
414}
415
416static int
417s3lfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
418{
419 return (*prevvidsw->ioctl)(adp, cmd, arg);
420}
421
422static int
423s3lfb_diag(video_adapter_t *adp, int level)
424{
425 return (*prevvidsw->diag)(adp, level);
426}
427
428static int
429s3lfb_error(void)
430{
431 return 1;
432}
433
434/***********************************/
435/* PCI detection/attachement stuff */
436/***********************************/
437
438static int
439s3pci_probe(device_t dev)
440{
441 u_int32_t vendor, class, subclass, device_id;
442
443 device_id = pci_get_devid(dev);
444 vendor = device_id & 0xffff;
445 class = pci_get_class(dev);
446 subclass = pci_get_subclass(dev);
447
448 if ((class != PCIC_DISPLAY) || (subclass != PCIS_DISPLAY_VGA) ||
449 (vendor != PCI_S3_VENDOR_ID))
450 return ENXIO;
451
452 device_set_desc(dev, "S3 graphic card");
453
454 bus_set_resource(dev, SYS_RES_IOPORT, 0,
455 S3_CONFIG_IO, S3_CONFIG_IO_SIZE);
456 bus_set_resource(dev, SYS_RES_IOPORT, 1,
457 S3_ENHANCED_IO, S3_ENHANCED_IO_SIZE);
458
459 return 0;
460
461};
462
463static int
464s3pci_attach(device_t dev)
465{
466 struct s3pci_softc* sc = (struct s3pci_softc*)device_get_softc(dev);
467 video_adapter_t *adp;
468
469#if 0
470 unsigned char tmp;
471#endif
472 int rid, i;
473
474 if (s3pci_dev) {
475 printf("%s: driver already attached!\n", __func__);
476 goto error;
477 }
478
479 /* Allocate resources
480 */
481 rid = 0;
482 if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
483 0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
484 printf("%s: port resource allocation failed!\n", __func__);
485 goto error;
486 }
487 sc->st = rman_get_bustag(sc->port_res);
488 sc->sh = rman_get_bushandle(sc->port_res);
489
490 rid = 1;
491 if (!(sc->enh_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
492 0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
493 printf("%s: enhanced port resource allocation failed!\n",
494 __func__);
495 goto error;
496 }
497 sc->enh_st = rman_get_bustag(sc->enh_res);
498 sc->enh_sh = rman_get_bushandle(sc->enh_res);
499
500 rid = PCI_BASE_MEMORY;
501 if (!(sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
502 0, ~0, 1, RF_ACTIVE))) {
503
504 printf("%s: mem resource allocation failed!\n", __func__);
505 goto error;
506 }
507
508 /* The memory base address will be our LFB base address
509 */
510 /* sc->mem_base = (u_long)rman_get_virtual(sc->mem_res); */
511 sc->mem_base = bus_get_resource_start(dev, SYS_RES_MEMORY, rid);
512 sc->mem_size = bus_get_resource_count(dev, SYS_RES_MEMORY, rid);
513
514 /* Attach the driver to the VGA/VESA framework
515 */
516 for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) {
517 if ((adp->va_type == KD_VGA))
518 break;
519 }
520
521 /* If the VESA module hasn't been loaded, or VGA doesn't
522 * exist, abort
523 */
524 if ((adp == NULL) || !(adp->va_flags & V_ADP_VESA)) {
525 printf("%s: VGA adapter not found or VESA module not loaded!\n",
526 __func__);
527 goto error;
528 }
529
530 /* Replace the VESA video switch by owers
531 */
532 prevvidsw = vidsw[adp->va_index];
533 vidsw[adp->va_index] = &s3lfbvidsw;
534
535 /* Remember who we are on the bus */
536 s3pci_dev = (void *)dev; /* XXX */
537
538 return 0;
539
540error:
541 if (sc->mem_res)
542 bus_release_resource(dev, SYS_RES_MEMORY, PCI_BASE_MEMORY, sc->mem_res);
543
544 if (sc->enh_res)
545 bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->enh_res);
546
547 if (sc->port_res)
548 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res);
549
550 return ENXIO;
551};
552
553static device_method_t s3pci_methods[] = {
554
555 DEVMETHOD(device_probe, s3pci_probe),
556 DEVMETHOD(device_attach, s3pci_attach),
557 {0,0}
558};
559
560static driver_t s3pci_driver = {
561 "s3pci",
562 s3pci_methods,
563 sizeof(struct s3pci_softc),
564};
565
566static devclass_t s3pci_devclass;
567
568DRIVER_MODULE(s3pci, pci, s3pci_driver, s3pci_devclass, 0, 0);
57
58#include <machine/md_var.h>
59#include <machine/vm86.h>
60#include <machine/pc/bios.h>
61#include <machine/pc/vesa.h>
62
63#include <dev/fb/fbreg.h>
64#include <dev/fb/vgareg.h>
65
66#define S3PCI_DEBUG 1
67
68#define PCI_S3_VENDOR_ID 0x5333
69
70#define S3_CONFIG_IO 0x3c0 /* VGA standard config io ports */
71#define S3_CONFIG_IO_SIZE 0x20
72
73#define S3_ENHANCED_IO 0x4ae8 /* Extended config register */
74#define S3_ENHANCED_IO_SIZE 1
75
76#define S3_CRTC_ADDR 0x14
77#define S3_CRTC_VALUE 0x15
78
79#define PCI_BASE_MEMORY 0x10
80
81#define outb_p(value, offset) bus_space_write_1(sc->st, sc->sh, offset, value)
82#define inb_p(offset) (bus_space_read_1(sc->st, sc->sh, offset))
83#define outb_enh(value, offset) bus_space_write_1(sc->enh_st, sc->enh_sh, \
84 offset, value)
85#define inb_enh(offset) (bus_space_read_1(sc->enh_st, sc->enh_sh, offset))
86
87struct s3pci_softc {
88 bus_space_tag_t st;
89 bus_space_handle_t sh;
90 bus_space_tag_t enh_st;
91 bus_space_handle_t enh_sh;
92 struct resource *port_res;
93 struct resource *enh_res;
94 struct resource *mem_res;
95 u_long mem_base;
96 u_long mem_size;
97};
98
99static int s3lfb_error(void);
100static vi_probe_t s3lfb_probe;
101static vi_init_t s3lfb_init;
102static vi_get_info_t s3lfb_get_info;
103static vi_query_mode_t s3lfb_query_mode;
104static vi_set_mode_t s3lfb_set_mode;
105static vi_save_font_t s3lfb_save_font;
106static vi_load_font_t s3lfb_load_font;
107static vi_show_font_t s3lfb_show_font;
108static vi_save_palette_t s3lfb_save_palette;
109static vi_load_palette_t s3lfb_load_palette;
110static vi_set_border_t s3lfb_set_border;
111static vi_save_state_t s3lfb_save_state;
112static vi_load_state_t s3lfb_load_state;
113static vi_set_win_org_t s3lfb_set_origin;
114static vi_read_hw_cursor_t s3lfb_read_hw_cursor;
115static vi_set_hw_cursor_t s3lfb_set_hw_cursor;
116static vi_set_hw_cursor_shape_t s3lfb_set_hw_cursor_shape;
117static vi_blank_display_t s3lfb_blank_display;
118static vi_mmap_t s3lfb_mmap;
119static vi_ioctl_t s3lfb_ioctl;
120static vi_clear_t s3lfb_clear;
121static vi_fill_rect_t s3lfb_fill_rect;
122static vi_bitblt_t s3lfb_bitblt;
123static vi_diag_t s3lfb_diag;
124
125static video_switch_t s3lfbvidsw = {
126 s3lfb_probe,
127 s3lfb_init,
128 s3lfb_get_info,
129 s3lfb_query_mode,
130 s3lfb_set_mode,
131 s3lfb_save_font,
132 s3lfb_load_font,
133 s3lfb_show_font,
134 s3lfb_save_palette,
135 s3lfb_load_palette,
136 s3lfb_set_border,
137 s3lfb_save_state,
138 s3lfb_load_state,
139 s3lfb_set_origin,
140 s3lfb_read_hw_cursor,
141 s3lfb_set_hw_cursor,
142 s3lfb_set_hw_cursor_shape,
143 s3lfb_blank_display,
144 s3lfb_mmap,
145 s3lfb_ioctl,
146 s3lfb_clear,
147 s3lfb_fill_rect,
148 s3lfb_bitblt,
149 s3lfb_error,
150 s3lfb_error,
151 s3lfb_diag,
152};
153
154static video_switch_t *prevvidsw;
155static device_t s3pci_dev = NULL;
156
157static int
158s3lfb_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
159{
160 return (*prevvidsw->probe)(unit, adpp, arg, flags);
161}
162
163static int
164s3lfb_init(int unit, video_adapter_t *adp, int flags)
165{
166 return (*prevvidsw->init)(unit, adp, flags);
167}
168
169static int
170s3lfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
171{
172#if 0
173 device_t dev = s3pci_dev; /* XXX */
174 struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
175#endif
176 int error;
177
178 if ((error = (*prevvidsw->get_info)(adp, mode, info)))
179 return error;
180
181#if 0
182 /* Don't use linear addressing with text modes
183 */
184 if ((mode > M_VESA_BASE) &&
185 (info->vi_flags & V_INFO_GRAPHICS) &&
186 !(info->vi_flags & V_INFO_LINEAR)) {
187
188 info->vi_flags |= V_INFO_LINEAR;
189 info->vi_buffer = sc->mem_base;
190
191 } else {
192 info->vi_buffer = 0;
193 }
194#endif
195
196 return 0;
197}
198
199static int
200s3lfb_query_mode(video_adapter_t *adp, video_info_t *info)
201{
202 return (*prevvidsw->query_mode)(adp, info);
203}
204
205static vm_offset_t
206s3lfb_map_buffer(u_int paddr, size_t size)
207{
208 vm_offset_t vaddr;
209 u_int off;
210
211 off = paddr - trunc_page(paddr);
212 vaddr = (vm_offset_t)pmap_mapdev(paddr - off, size + off);
213
214 return (vaddr + off);
215}
216
217static int
218s3lfb_set_mode(video_adapter_t *adp, int mode)
219{
220 device_t dev = s3pci_dev; /* XXX */
221 struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
222#if 0
223 unsigned char tmp;
224#endif
225 int error;
226
227 /* First, set the mode as if it was a classic VESA card
228 */
229 if ((error = (*prevvidsw->set_mode)(adp, mode)))
230 return error;
231
232 /* If not in a linear mode (according to s3lfb_get_info() called
233 * by vesa_set_mode in the (*vidsw[adp->va_index]->get_info)...
234 * sequence, return with no error
235 */
236#if 0
237 if (!(adp->va_info.vi_flags & V_INFO_LINEAR))
238 return 0;
239#endif
240
241 if ((mode <= M_VESA_BASE) ||
242 !(adp->va_info.vi_flags & V_INFO_GRAPHICS) ||
243 (adp->va_info.vi_flags & V_INFO_LINEAR))
244 return 0;
245
246 /* Ok, now apply the configuration to the card */
247
248 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x48, S3_CRTC_VALUE);
249 outb_p(0x39, S3_CRTC_ADDR); outb_p(0xa5, S3_CRTC_VALUE);
250
251 /* check that CR47 is read/write */
252
253#if 0
254 outb_p(0x47, S3_CRTC_ADDR); outb_p(0xff, S3_CRTC_VALUE);
255 tmp = inb_p(S3_CRTC_VALUE);
256 outb_p(0x00, S3_CRTC_VALUE);
257 if ((tmp != 0xff) || (inb_p(S3_CRTC_VALUE)))
258 {
259 /* lock S3 registers */
260
261 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
262 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
263
264 return ENXIO;
265 }
266#endif
267
268 /* enable enhanced register access */
269
270 outb_p(0x40, S3_CRTC_ADDR);
271 outb_p(inb_p(S3_CRTC_VALUE) | 1, S3_CRTC_VALUE);
272
273 /* enable enhanced functions */
274
275 outb_enh(inb_enh(0) | 1, 0x0);
276
277 /* enable enhanced mode memory mapping */
278
279 outb_p(0x31, S3_CRTC_ADDR);
280 outb_p(inb_p(S3_CRTC_VALUE) | 8, S3_CRTC_VALUE);
281
282 /* enable linear frame buffer and set address window to max */
283
284 outb_p(0x58, S3_CRTC_ADDR);
285 outb_p(inb_p(S3_CRTC_VALUE) | 0x13, S3_CRTC_VALUE);
286
287 /* disabled enhanced register access */
288
289 outb_p(0x40, S3_CRTC_ADDR);
290 outb_p(inb_p(S3_CRTC_VALUE) & ~1, S3_CRTC_VALUE);
291
292 /* lock S3 registers */
293
294 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
295 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
296
297 adp->va_info.vi_flags |= V_INFO_LINEAR;
298 adp->va_info.vi_buffer = sc->mem_base;
299 adp->va_buffer = s3lfb_map_buffer(adp->va_info.vi_buffer,
300 adp->va_info.vi_buffer_size);
301 adp->va_buffer_size = adp->va_info.vi_buffer_size;
302 adp->va_window = adp->va_buffer;
303 adp->va_window_size = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
304 adp->va_window_gran = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
305
306 return 0;
307}
308
309static int
310s3lfb_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
311 int ch, int count)
312{
313 return (*prevvidsw->save_font)(adp, page, fontsize, data, ch, count);
314}
315
316static int
317s3lfb_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
318 int ch, int count)
319{
320 return (*prevvidsw->load_font)(adp, page, fontsize, data, ch, count);
321}
322
323static int
324s3lfb_show_font(video_adapter_t *adp, int page)
325{
326 return (*prevvidsw->show_font)(adp, page);
327}
328
329static int
330s3lfb_save_palette(video_adapter_t *adp, u_char *palette)
331{
332 return (*prevvidsw->save_palette)(adp, palette);
333}
334
335static int
336s3lfb_load_palette(video_adapter_t *adp, u_char *palette)
337{
338 return (*prevvidsw->load_palette)(adp, palette);
339}
340
341static int
342s3lfb_set_border(video_adapter_t *adp, int color)
343{
344 return (*prevvidsw->set_border)(adp, color);
345}
346
347static int
348s3lfb_save_state(video_adapter_t *adp, void *p, size_t size)
349{
350 return (*prevvidsw->save_state)(adp, p, size);
351}
352
353static int
354s3lfb_load_state(video_adapter_t *adp, void *p)
355{
356 return (*prevvidsw->load_state)(adp, p);
357}
358
359static int
360s3lfb_set_origin(video_adapter_t *adp, off_t offset)
361{
362 return (*prevvidsw->set_win_org)(adp, offset);
363}
364
365static int
366s3lfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
367{
368 return (*prevvidsw->read_hw_cursor)(adp, col, row);
369}
370
371static int
372s3lfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
373{
374 return (*prevvidsw->set_hw_cursor)(adp, col, row);
375}
376
377static int
378s3lfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
379 int celsize, int blink)
380{
381 return (*prevvidsw->set_hw_cursor_shape)(adp, base, height,
382 celsize, blink);
383}
384
385static int
386s3lfb_blank_display(video_adapter_t *adp, int mode)
387{
388 return (*prevvidsw->blank_display)(adp, mode);
389}
390
391static int
392s3lfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr,
393 int prot)
394{
395 return (*prevvidsw->mmap)(adp, offset, paddr, prot);
396}
397
398static int
399s3lfb_clear(video_adapter_t *adp)
400{
401 return (*prevvidsw->clear)(adp);
402}
403
404static int
405s3lfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
406{
407 return (*prevvidsw->fill_rect)(adp, val, x, y, cx, cy);
408}
409
410static int
411s3lfb_bitblt(video_adapter_t *adp,...)
412{
413 return (*prevvidsw->bitblt)(adp); /* XXX */
414}
415
416static int
417s3lfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
418{
419 return (*prevvidsw->ioctl)(adp, cmd, arg);
420}
421
422static int
423s3lfb_diag(video_adapter_t *adp, int level)
424{
425 return (*prevvidsw->diag)(adp, level);
426}
427
428static int
429s3lfb_error(void)
430{
431 return 1;
432}
433
434/***********************************/
435/* PCI detection/attachement stuff */
436/***********************************/
437
438static int
439s3pci_probe(device_t dev)
440{
441 u_int32_t vendor, class, subclass, device_id;
442
443 device_id = pci_get_devid(dev);
444 vendor = device_id & 0xffff;
445 class = pci_get_class(dev);
446 subclass = pci_get_subclass(dev);
447
448 if ((class != PCIC_DISPLAY) || (subclass != PCIS_DISPLAY_VGA) ||
449 (vendor != PCI_S3_VENDOR_ID))
450 return ENXIO;
451
452 device_set_desc(dev, "S3 graphic card");
453
454 bus_set_resource(dev, SYS_RES_IOPORT, 0,
455 S3_CONFIG_IO, S3_CONFIG_IO_SIZE);
456 bus_set_resource(dev, SYS_RES_IOPORT, 1,
457 S3_ENHANCED_IO, S3_ENHANCED_IO_SIZE);
458
459 return 0;
460
461};
462
463static int
464s3pci_attach(device_t dev)
465{
466 struct s3pci_softc* sc = (struct s3pci_softc*)device_get_softc(dev);
467 video_adapter_t *adp;
468
469#if 0
470 unsigned char tmp;
471#endif
472 int rid, i;
473
474 if (s3pci_dev) {
475 printf("%s: driver already attached!\n", __func__);
476 goto error;
477 }
478
479 /* Allocate resources
480 */
481 rid = 0;
482 if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
483 0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
484 printf("%s: port resource allocation failed!\n", __func__);
485 goto error;
486 }
487 sc->st = rman_get_bustag(sc->port_res);
488 sc->sh = rman_get_bushandle(sc->port_res);
489
490 rid = 1;
491 if (!(sc->enh_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
492 0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
493 printf("%s: enhanced port resource allocation failed!\n",
494 __func__);
495 goto error;
496 }
497 sc->enh_st = rman_get_bustag(sc->enh_res);
498 sc->enh_sh = rman_get_bushandle(sc->enh_res);
499
500 rid = PCI_BASE_MEMORY;
501 if (!(sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
502 0, ~0, 1, RF_ACTIVE))) {
503
504 printf("%s: mem resource allocation failed!\n", __func__);
505 goto error;
506 }
507
508 /* The memory base address will be our LFB base address
509 */
510 /* sc->mem_base = (u_long)rman_get_virtual(sc->mem_res); */
511 sc->mem_base = bus_get_resource_start(dev, SYS_RES_MEMORY, rid);
512 sc->mem_size = bus_get_resource_count(dev, SYS_RES_MEMORY, rid);
513
514 /* Attach the driver to the VGA/VESA framework
515 */
516 for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) {
517 if ((adp->va_type == KD_VGA))
518 break;
519 }
520
521 /* If the VESA module hasn't been loaded, or VGA doesn't
522 * exist, abort
523 */
524 if ((adp == NULL) || !(adp->va_flags & V_ADP_VESA)) {
525 printf("%s: VGA adapter not found or VESA module not loaded!\n",
526 __func__);
527 goto error;
528 }
529
530 /* Replace the VESA video switch by owers
531 */
532 prevvidsw = vidsw[adp->va_index];
533 vidsw[adp->va_index] = &s3lfbvidsw;
534
535 /* Remember who we are on the bus */
536 s3pci_dev = (void *)dev; /* XXX */
537
538 return 0;
539
540error:
541 if (sc->mem_res)
542 bus_release_resource(dev, SYS_RES_MEMORY, PCI_BASE_MEMORY, sc->mem_res);
543
544 if (sc->enh_res)
545 bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->enh_res);
546
547 if (sc->port_res)
548 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res);
549
550 return ENXIO;
551};
552
553static device_method_t s3pci_methods[] = {
554
555 DEVMETHOD(device_probe, s3pci_probe),
556 DEVMETHOD(device_attach, s3pci_attach),
557 {0,0}
558};
559
560static driver_t s3pci_driver = {
561 "s3pci",
562 s3pci_methods,
563 sizeof(struct s3pci_softc),
564};
565
566static devclass_t s3pci_devclass;
567
568DRIVER_MODULE(s3pci, pci, s3pci_driver, s3pci_devclass, 0, 0);