s3_pci.c revision 143161
170688Snsouch/*-
270688Snsouch * Copyright (c) 2000 Alcove - Nicolas Souchu <nsouch@freebsd.org>
370688Snsouch * All rights reserved.
470688Snsouch *
570688Snsouch * Code based on Peter Horton <pdh@colonel-panic.com> patch.
670688Snsouch *
770688Snsouch * Redistribution and use in source and binary forms, with or without
870688Snsouch * modification, are permitted provided that the following conditions
970688Snsouch * are met:
1070688Snsouch * 1. Redistributions of source code must retain the above copyright
1170688Snsouch *    notice, this list of conditions and the following disclaimer.
1270688Snsouch * 2. Redistributions in binary form must reproduce the above copyright
1370688Snsouch *    notice, this list of conditions and the following disclaimer in the
1470688Snsouch *    documentation and/or other materials provided with the distribution.
1570688Snsouch *
1670688Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1770688Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1870688Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1970688Snsouch * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2070688Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2170688Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2270688Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2370688Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2470688Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2570688Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2670688Snsouch * SUCH DAMAGE.
2770688Snsouch */
2870688Snsouch
29119418Sobrien#include <sys/cdefs.h>
30119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/fb/s3_pci.c 143161 2005-03-05 18:30:12Z imp $");
31119418Sobrien
3270688Snsouch/* Enable LFB on S3 cards that has only VESA 1.2 BIOS */
3370688Snsouch
3470688Snsouch#include <sys/param.h>
3570688Snsouch#include <sys/systm.h>
3670688Snsouch#include <sys/kernel.h>
3770688Snsouch#include <machine/bus_pio.h>
3870688Snsouch#include <machine/bus_memio.h>
3970688Snsouch#include <machine/bus.h>
4070688Snsouch
4170688Snsouch#include <vm/vm.h>
4270688Snsouch#include <vm/vm_extern.h>
4370688Snsouch#include <vm/vm_kern.h>
4470688Snsouch#include <vm/pmap.h>
4570688Snsouch
4670688Snsouch#include <sys/uio.h>
4770688Snsouch#include <sys/module.h>
4870688Snsouch#include <sys/bus.h>
4970688Snsouch#include <sys/rman.h>
5070688Snsouch#include <machine/resource.h>
5170688Snsouch
5270688Snsouch#include <sys/malloc.h>
5370688Snsouch#include <sys/fbio.h>
5470688Snsouch
55119277Simp#include <dev/pci/pcireg.h>
56119277Simp#include <dev/pci/pcivar.h>
5770688Snsouch
5870688Snsouch#include <machine/md_var.h>
5970688Snsouch#include <machine/vm86.h>
6070688Snsouch#include <machine/pc/bios.h>
6170688Snsouch#include <machine/pc/vesa.h>
6270688Snsouch
6370688Snsouch#include <dev/fb/fbreg.h>
6470688Snsouch#include <dev/fb/vgareg.h>
6570688Snsouch
6670688Snsouch#define S3PCI_DEBUG 1
6770688Snsouch
6870688Snsouch#define PCI_S3_VENDOR_ID	0x5333
6970688Snsouch
7070688Snsouch#define S3_CONFIG_IO		0x3c0	/* VGA standard config io ports */
7170688Snsouch#define S3_CONFIG_IO_SIZE	0x20
7270688Snsouch
7370688Snsouch#define S3_ENHANCED_IO		0x4ae8	/* Extended config register */
7470688Snsouch#define S3_ENHANCED_IO_SIZE	1
7570688Snsouch
7670688Snsouch#define S3_CRTC_ADDR		0x14
7770688Snsouch#define S3_CRTC_VALUE		0x15
7870688Snsouch
7970688Snsouch#define PCI_BASE_MEMORY		0x10
8070688Snsouch
8170688Snsouch#define outb_p(value, offset) bus_space_write_1(sc->st, sc->sh, offset, value)
8270688Snsouch#define inb_p(offset) (bus_space_read_1(sc->st, sc->sh, offset))
8370688Snsouch#define outb_enh(value, offset) bus_space_write_1(sc->enh_st, sc->enh_sh, \
8470688Snsouch								offset, value)
8570688Snsouch#define inb_enh(offset) (bus_space_read_1(sc->enh_st, sc->enh_sh, offset))
8670688Snsouch
8770688Snsouchstruct s3pci_softc {
8870688Snsouch	bus_space_tag_t st;
8970688Snsouch	bus_space_handle_t sh;
9070688Snsouch	bus_space_tag_t enh_st;
9170688Snsouch	bus_space_handle_t enh_sh;
9270688Snsouch	struct resource *port_res;
9370688Snsouch	struct resource *enh_res;
9470688Snsouch	struct resource *mem_res;
9570688Snsouch	u_long mem_base;
9670688Snsouch	u_long mem_size;
9770688Snsouch};
9870688Snsouch
9970688Snsouchstatic int			s3lfb_error(void);
10070688Snsouchstatic vi_probe_t		s3lfb_probe;
10170688Snsouchstatic vi_init_t		s3lfb_init;
10270688Snsouchstatic vi_get_info_t		s3lfb_get_info;
10370688Snsouchstatic vi_query_mode_t		s3lfb_query_mode;
10470688Snsouchstatic vi_set_mode_t		s3lfb_set_mode;
10570688Snsouchstatic vi_save_font_t		s3lfb_save_font;
10670688Snsouchstatic vi_load_font_t		s3lfb_load_font;
10770688Snsouchstatic vi_show_font_t		s3lfb_show_font;
10870688Snsouchstatic vi_save_palette_t	s3lfb_save_palette;
10970688Snsouchstatic vi_load_palette_t	s3lfb_load_palette;
11070688Snsouchstatic vi_set_border_t		s3lfb_set_border;
11170688Snsouchstatic vi_save_state_t		s3lfb_save_state;
11270688Snsouchstatic vi_load_state_t		s3lfb_load_state;
11370688Snsouchstatic vi_set_win_org_t		s3lfb_set_origin;
11470688Snsouchstatic vi_read_hw_cursor_t	s3lfb_read_hw_cursor;
11570688Snsouchstatic vi_set_hw_cursor_t	s3lfb_set_hw_cursor;
11670688Snsouchstatic vi_set_hw_cursor_shape_t	s3lfb_set_hw_cursor_shape;
11770688Snsouchstatic vi_blank_display_t	s3lfb_blank_display;
11870688Snsouchstatic vi_mmap_t		s3lfb_mmap;
11970688Snsouchstatic vi_ioctl_t		s3lfb_ioctl;
12070688Snsouchstatic vi_clear_t		s3lfb_clear;
12170688Snsouchstatic vi_fill_rect_t		s3lfb_fill_rect;
12270688Snsouchstatic vi_bitblt_t		s3lfb_bitblt;
12370688Snsouchstatic vi_diag_t		s3lfb_diag;
12470688Snsouch
12570688Snsouchstatic video_switch_t s3lfbvidsw = {
12670688Snsouch	s3lfb_probe,
12770688Snsouch	s3lfb_init,
12870688Snsouch	s3lfb_get_info,
12970688Snsouch	s3lfb_query_mode,
13070688Snsouch	s3lfb_set_mode,
13170688Snsouch	s3lfb_save_font,
13270688Snsouch	s3lfb_load_font,
13370688Snsouch	s3lfb_show_font,
13470688Snsouch	s3lfb_save_palette,
13570688Snsouch	s3lfb_load_palette,
13670688Snsouch	s3lfb_set_border,
13770688Snsouch	s3lfb_save_state,
13870688Snsouch	s3lfb_load_state,
13970688Snsouch	s3lfb_set_origin,
14070688Snsouch	s3lfb_read_hw_cursor,
14170688Snsouch	s3lfb_set_hw_cursor,
14270688Snsouch	s3lfb_set_hw_cursor_shape,
14370688Snsouch	s3lfb_blank_display,
14470688Snsouch	s3lfb_mmap,
14570688Snsouch	s3lfb_ioctl,
14670688Snsouch	s3lfb_clear,
14770688Snsouch	s3lfb_fill_rect,
14870688Snsouch	s3lfb_bitblt,
14970688Snsouch	s3lfb_error,
15070688Snsouch	s3lfb_error,
15170688Snsouch	s3lfb_diag,
15270688Snsouch};
15370688Snsouch
15470688Snsouchstatic video_switch_t *prevvidsw;
15570688Snsouchstatic device_t s3pci_dev = NULL;
15670688Snsouch
15770688Snsouchstatic int
15870688Snsouchs3lfb_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
15970688Snsouch{
16070688Snsouch	return (*prevvidsw->probe)(unit, adpp, arg, flags);
16170688Snsouch}
16270688Snsouch
16370688Snsouchstatic int
16470688Snsouchs3lfb_init(int unit, video_adapter_t *adp, int flags)
16570688Snsouch{
16670688Snsouch	return (*prevvidsw->init)(unit, adp, flags);
16770688Snsouch}
16870688Snsouch
16970688Snsouchstatic int
17070688Snsouchs3lfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
17170688Snsouch{
17271465Sjhb#if 0
17370688Snsouch	device_t dev = s3pci_dev;			/* XXX */
17470688Snsouch	struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
17571465Sjhb#endif
17670688Snsouch	int error;
17770688Snsouch
17870688Snsouch	if ((error = (*prevvidsw->get_info)(adp, mode, info)))
17970688Snsouch		return error;
18070688Snsouch
18170688Snsouch#if 0
18270688Snsouch	/* Don't use linear addressing with text modes
18370688Snsouch	 */
18470688Snsouch	if ((mode > M_VESA_BASE) &&
18570688Snsouch		(info->vi_flags & V_INFO_GRAPHICS) &&
18670688Snsouch		!(info->vi_flags & V_INFO_LINEAR)) {
18770688Snsouch
18870688Snsouch		info->vi_flags |= V_INFO_LINEAR;
18970688Snsouch		info->vi_buffer = sc->mem_base;
19070688Snsouch
19170688Snsouch	} else {
19270688Snsouch		info->vi_buffer = 0;
19370688Snsouch	}
19470688Snsouch#endif
19570688Snsouch
19670688Snsouch	return 0;
19770688Snsouch}
19870688Snsouch
19970688Snsouchstatic int
20070688Snsouchs3lfb_query_mode(video_adapter_t *adp, video_info_t *info)
20170688Snsouch{
20270688Snsouch	return (*prevvidsw->query_mode)(adp, info);
20370688Snsouch}
20470688Snsouch
20570688Snsouchstatic vm_offset_t
20670688Snsouchs3lfb_map_buffer(u_int paddr, size_t size)
20770688Snsouch{
20870688Snsouch	vm_offset_t vaddr;
20970688Snsouch	u_int off;
21070688Snsouch
21170688Snsouch	off = paddr - trunc_page(paddr);
21270688Snsouch	vaddr = (vm_offset_t)pmap_mapdev(paddr - off, size + off);
21370688Snsouch
21470688Snsouch	return (vaddr + off);
21570688Snsouch}
21670688Snsouch
21770688Snsouchstatic int
21870688Snsouchs3lfb_set_mode(video_adapter_t *adp, int mode)
21970688Snsouch{
22070688Snsouch	device_t dev = s3pci_dev;			/* XXX */
22170688Snsouch	struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
22271465Sjhb#if 0
22370688Snsouch	unsigned char tmp;
22471465Sjhb#endif
22570688Snsouch	int error;
22670688Snsouch
22770688Snsouch	/* First, set the mode as if it was a classic VESA card
22870688Snsouch	 */
22970688Snsouch	if ((error = (*prevvidsw->set_mode)(adp, mode)))
23070688Snsouch		return error;
23170688Snsouch
23270688Snsouch	/* If not in a linear mode (according to s3lfb_get_info() called
23370688Snsouch	 * by vesa_set_mode in the (*vidsw[adp->va_index]->get_info)...
23470688Snsouch	 * sequence, return with no error
23570688Snsouch	 */
23670688Snsouch#if 0
23770688Snsouch	if (!(adp->va_info.vi_flags & V_INFO_LINEAR))
23870688Snsouch		return 0;
23970688Snsouch#endif
24070688Snsouch
24170688Snsouch	if ((mode <= M_VESA_BASE) ||
24270688Snsouch		!(adp->va_info.vi_flags & V_INFO_GRAPHICS) ||
24370688Snsouch		(adp->va_info.vi_flags & V_INFO_LINEAR))
24470688Snsouch		return 0;
24570688Snsouch
24670688Snsouch	/* Ok, now apply the configuration to the card */
24770688Snsouch
24870688Snsouch	outb_p(0x38, S3_CRTC_ADDR); outb_p(0x48, S3_CRTC_VALUE);
24970688Snsouch	outb_p(0x39, S3_CRTC_ADDR); outb_p(0xa5, S3_CRTC_VALUE);
25070688Snsouch
25170688Snsouch       /* check that CR47 is read/write */
25270688Snsouch
25370688Snsouch#if 0
25470688Snsouch	outb_p(0x47, S3_CRTC_ADDR); outb_p(0xff, S3_CRTC_VALUE);
25570688Snsouch	tmp = inb_p(S3_CRTC_VALUE);
25670688Snsouch	outb_p(0x00, S3_CRTC_VALUE);
25770688Snsouch	if ((tmp != 0xff) || (inb_p(S3_CRTC_VALUE)))
25870688Snsouch	{
25970688Snsouch		/* lock S3 registers */
26070688Snsouch
26170688Snsouch		outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
26270688Snsouch		outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
26370688Snsouch
26470688Snsouch		return ENXIO;
26570688Snsouch	}
26670688Snsouch#endif
26770688Snsouch
26870688Snsouch	/* enable enhanced register access */
26970688Snsouch
27070688Snsouch	outb_p(0x40, S3_CRTC_ADDR);
27170688Snsouch	outb_p(inb_p(S3_CRTC_VALUE) | 1, S3_CRTC_VALUE);
27270688Snsouch
27370688Snsouch	/* enable enhanced functions */
27470688Snsouch
27570688Snsouch	outb_enh(inb_enh(0) | 1, 0x0);
27670688Snsouch
27770688Snsouch	/* enable enhanced mode memory mapping */
27870688Snsouch
27970688Snsouch	outb_p(0x31, S3_CRTC_ADDR);
28070688Snsouch	outb_p(inb_p(S3_CRTC_VALUE) | 8, S3_CRTC_VALUE);
28170688Snsouch
28270688Snsouch	/* enable linear frame buffer and set address window to max */
28370688Snsouch
28470688Snsouch	outb_p(0x58, S3_CRTC_ADDR);
28570688Snsouch	outb_p(inb_p(S3_CRTC_VALUE) | 0x13, S3_CRTC_VALUE);
28670688Snsouch
28770688Snsouch	/* disabled enhanced register access */
28870688Snsouch
28970688Snsouch	outb_p(0x40, S3_CRTC_ADDR);
29070688Snsouch	outb_p(inb_p(S3_CRTC_VALUE) & ~1, S3_CRTC_VALUE);
29170688Snsouch
29270688Snsouch	/* lock S3 registers */
29370688Snsouch
29470688Snsouch	outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
29570688Snsouch	outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
29670688Snsouch
29770688Snsouch	adp->va_info.vi_flags |= V_INFO_LINEAR;
29870688Snsouch	adp->va_info.vi_buffer = sc->mem_base;
29970688Snsouch	adp->va_buffer = s3lfb_map_buffer(adp->va_info.vi_buffer,
30070688Snsouch				adp->va_info.vi_buffer_size);
30170688Snsouch	adp->va_buffer_size = adp->va_info.vi_buffer_size;
30270688Snsouch	adp->va_window = adp->va_buffer;
30370688Snsouch	adp->va_window_size = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
30470688Snsouch	adp->va_window_gran = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
30570688Snsouch
30670688Snsouch	return 0;
30770688Snsouch}
30870688Snsouch
30970688Snsouchstatic int
31070688Snsouchs3lfb_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
31170688Snsouch	       int ch, int count)
31270688Snsouch{
31370688Snsouch	return (*prevvidsw->save_font)(adp, page, fontsize, data, ch, count);
31470688Snsouch}
31570688Snsouch
31670688Snsouchstatic int
31770688Snsouchs3lfb_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
31870688Snsouch	       int ch, int count)
31970688Snsouch{
32070688Snsouch	return (*prevvidsw->load_font)(adp, page, fontsize, data, ch, count);
32170688Snsouch}
32270688Snsouch
32370688Snsouchstatic int
32470688Snsouchs3lfb_show_font(video_adapter_t *adp, int page)
32570688Snsouch{
32670688Snsouch	return (*prevvidsw->show_font)(adp, page);
32770688Snsouch}
32870688Snsouch
32970688Snsouchstatic int
33070688Snsouchs3lfb_save_palette(video_adapter_t *adp, u_char *palette)
33170688Snsouch{
33270688Snsouch	return (*prevvidsw->save_palette)(adp, palette);
33370688Snsouch}
33470688Snsouch
33570688Snsouchstatic int
33670688Snsouchs3lfb_load_palette(video_adapter_t *adp, u_char *palette)
33770688Snsouch{
33870688Snsouch	return (*prevvidsw->load_palette)(adp, palette);
33970688Snsouch}
34070688Snsouch
34170688Snsouchstatic int
34270688Snsouchs3lfb_set_border(video_adapter_t *adp, int color)
34370688Snsouch{
34470688Snsouch	return (*prevvidsw->set_border)(adp, color);
34570688Snsouch}
34670688Snsouch
34770688Snsouchstatic int
34870688Snsouchs3lfb_save_state(video_adapter_t *adp, void *p, size_t size)
34970688Snsouch{
35070688Snsouch	return (*prevvidsw->save_state)(adp, p, size);
35170688Snsouch}
35270688Snsouch
35370688Snsouchstatic int
35470688Snsouchs3lfb_load_state(video_adapter_t *adp, void *p)
35570688Snsouch{
35670688Snsouch	return (*prevvidsw->load_state)(adp, p);
35770688Snsouch}
35870688Snsouch
35970688Snsouchstatic int
36070688Snsouchs3lfb_set_origin(video_adapter_t *adp, off_t offset)
36170688Snsouch{
36270688Snsouch	return (*prevvidsw->set_win_org)(adp, offset);
36370688Snsouch}
36470688Snsouch
36570688Snsouchstatic int
36670688Snsouchs3lfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
36770688Snsouch{
36870688Snsouch	return (*prevvidsw->read_hw_cursor)(adp, col, row);
36970688Snsouch}
37070688Snsouch
37170688Snsouchstatic int
37270688Snsouchs3lfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
37370688Snsouch{
37470688Snsouch	return (*prevvidsw->set_hw_cursor)(adp, col, row);
37570688Snsouch}
37670688Snsouch
37770688Snsouchstatic int
37870688Snsouchs3lfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
37970688Snsouch			 int celsize, int blink)
38070688Snsouch{
38170688Snsouch	return (*prevvidsw->set_hw_cursor_shape)(adp, base, height,
38270688Snsouch			celsize, blink);
38370688Snsouch}
38470688Snsouch
38570688Snsouchstatic int
38670688Snsouchs3lfb_blank_display(video_adapter_t *adp, int mode)
38770688Snsouch{
38870688Snsouch	return (*prevvidsw->blank_display)(adp, mode);
38970688Snsouch}
39070688Snsouch
39170688Snsouchstatic int
392111462Smuxs3lfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr,
393111462Smux	  int prot)
39470688Snsouch{
395111462Smux	return (*prevvidsw->mmap)(adp, offset, paddr, prot);
39670688Snsouch}
39770688Snsouch
39870688Snsouchstatic int
39970688Snsouchs3lfb_clear(video_adapter_t *adp)
40070688Snsouch{
40170688Snsouch	return (*prevvidsw->clear)(adp);
40270688Snsouch}
40370688Snsouch
40470688Snsouchstatic int
40570688Snsouchs3lfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
40670688Snsouch{
40770688Snsouch	return (*prevvidsw->fill_rect)(adp, val, x, y, cx, cy);
40870688Snsouch}
40970688Snsouch
41070688Snsouchstatic int
41170688Snsouchs3lfb_bitblt(video_adapter_t *adp,...)
41270688Snsouch{
41370688Snsouch	return (*prevvidsw->bitblt)(adp);		/* XXX */
41470688Snsouch}
41570688Snsouch
41670688Snsouchstatic int
41770688Snsouchs3lfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
41870688Snsouch{
41970688Snsouch	return (*prevvidsw->ioctl)(adp, cmd, arg);
42070688Snsouch}
42170688Snsouch
42270688Snsouchstatic int
42370688Snsouchs3lfb_diag(video_adapter_t *adp, int level)
42470688Snsouch{
42570688Snsouch	return (*prevvidsw->diag)(adp, level);
42670688Snsouch}
42770688Snsouch
42870688Snsouchstatic int
42970688Snsouchs3lfb_error(void)
43070688Snsouch{
43170688Snsouch	return 1;
43270688Snsouch}
43370688Snsouch
43470688Snsouch/***********************************/
43570688Snsouch/* PCI detection/attachement stuff */
43670688Snsouch/***********************************/
43770688Snsouch
43870688Snsouchstatic int
43970688Snsouchs3pci_probe(device_t dev)
44070688Snsouch{
44170688Snsouch	u_int32_t vendor, class, subclass, device_id;
44270688Snsouch
44370688Snsouch	device_id = pci_get_devid(dev);
44470688Snsouch	vendor = device_id & 0xffff;
44570688Snsouch	class = pci_get_class(dev);
44670688Snsouch	subclass = pci_get_subclass(dev);
44770688Snsouch
44870688Snsouch	if ((class != PCIC_DISPLAY) || (subclass != PCIS_DISPLAY_VGA) ||
44970688Snsouch		(vendor != PCI_S3_VENDOR_ID))
45070688Snsouch		return ENXIO;
45170688Snsouch
45270688Snsouch	device_set_desc(dev, "S3 graphic card");
45370688Snsouch
45470688Snsouch	bus_set_resource(dev, SYS_RES_IOPORT, 0,
45570688Snsouch				S3_CONFIG_IO, S3_CONFIG_IO_SIZE);
45670688Snsouch	bus_set_resource(dev, SYS_RES_IOPORT, 1,
45770688Snsouch				S3_ENHANCED_IO, S3_ENHANCED_IO_SIZE);
45870688Snsouch
459143161Simp	return BUS_PROBE_DEFAULT;
46070688Snsouch
46170688Snsouch};
46270688Snsouch
46370688Snsouchstatic int
46470688Snsouchs3pci_attach(device_t dev)
46570688Snsouch{
46670688Snsouch	struct s3pci_softc* sc = (struct s3pci_softc*)device_get_softc(dev);
46770688Snsouch	video_adapter_t *adp;
46870688Snsouch
46970688Snsouch#if 0
47070688Snsouch	unsigned char tmp;
47170688Snsouch#endif
47270688Snsouch	int rid, i;
47370688Snsouch
47470688Snsouch	if (s3pci_dev) {
47587599Sobrien		printf("%s: driver already attached!\n", __func__);
47670688Snsouch		goto error;
47770688Snsouch	}
47870688Snsouch
47970688Snsouch	/* Allocate resources
48070688Snsouch	 */
48170688Snsouch	rid = 0;
48270688Snsouch	if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
48370688Snsouch				0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
48487599Sobrien		printf("%s: port resource allocation failed!\n", __func__);
48570688Snsouch		goto error;
48670688Snsouch	}
48770688Snsouch	sc->st = rman_get_bustag(sc->port_res);
48870688Snsouch	sc->sh = rman_get_bushandle(sc->port_res);
48970688Snsouch
49070688Snsouch	rid = 1;
49170688Snsouch	if (!(sc->enh_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
49270688Snsouch				0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
49370688Snsouch		printf("%s: enhanced port resource allocation failed!\n",
49487599Sobrien			__func__);
49570688Snsouch		goto error;
49670688Snsouch	}
49770688Snsouch	sc->enh_st = rman_get_bustag(sc->enh_res);
49870688Snsouch	sc->enh_sh = rman_get_bushandle(sc->enh_res);
49970688Snsouch
50070688Snsouch	rid = PCI_BASE_MEMORY;
501127135Snjl	if (!(sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
502127135Snjl				 RF_ACTIVE))) {
50370688Snsouch
50487599Sobrien		printf("%s: mem resource allocation failed!\n", __func__);
50570688Snsouch		goto error;
50670688Snsouch	}
50770688Snsouch
50870688Snsouch	/* The memory base address will be our LFB base address
50970688Snsouch	 */
51070688Snsouch	/* sc->mem_base = (u_long)rman_get_virtual(sc->mem_res); */
51170688Snsouch	sc->mem_base = bus_get_resource_start(dev, SYS_RES_MEMORY, rid);
51270688Snsouch	sc->mem_size = bus_get_resource_count(dev, SYS_RES_MEMORY, rid);
51370688Snsouch
51470688Snsouch	/* Attach the driver to the VGA/VESA framework
51570688Snsouch	 */
51670688Snsouch	for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) {
51770688Snsouch		if ((adp->va_type == KD_VGA))
51870688Snsouch			break;
51970688Snsouch	}
52070688Snsouch
52170688Snsouch	/* If the VESA module hasn't been loaded, or VGA doesn't
52270688Snsouch	 * exist, abort
52370688Snsouch	 */
52470688Snsouch	if ((adp == NULL) || !(adp->va_flags & V_ADP_VESA)) {
52570688Snsouch		printf("%s: VGA adapter not found or VESA module not loaded!\n",
52687599Sobrien			__func__);
52770688Snsouch		goto error;
52870688Snsouch	}
52970688Snsouch
53070688Snsouch	/* Replace the VESA video switch by owers
53170688Snsouch	 */
53270688Snsouch	prevvidsw = vidsw[adp->va_index];
53370688Snsouch	vidsw[adp->va_index] = &s3lfbvidsw;
53470688Snsouch
53570688Snsouch	/* Remember who we are on the bus */
53670688Snsouch	s3pci_dev = (void *)dev;			/* XXX */
53770688Snsouch
53870688Snsouch	return 0;
53970688Snsouch
54070688Snsoucherror:
54170688Snsouch	if (sc->mem_res)
54270688Snsouch		bus_release_resource(dev, SYS_RES_MEMORY, PCI_BASE_MEMORY, sc->mem_res);
54370688Snsouch
54470688Snsouch	if (sc->enh_res)
54570688Snsouch		bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->enh_res);
54670688Snsouch
54770688Snsouch	if (sc->port_res)
54870688Snsouch		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res);
54970688Snsouch
55070688Snsouch	return ENXIO;
55170688Snsouch};
55270688Snsouch
55370688Snsouchstatic device_method_t s3pci_methods[] = {
55470688Snsouch
55570688Snsouch        DEVMETHOD(device_probe, s3pci_probe),
55670688Snsouch        DEVMETHOD(device_attach, s3pci_attach),
55770688Snsouch        {0,0}
55870688Snsouch};
55970688Snsouch
56070688Snsouchstatic driver_t s3pci_driver = {
56170688Snsouch	"s3pci",
56270688Snsouch	s3pci_methods,
56370688Snsouch	sizeof(struct s3pci_softc),
56470688Snsouch};
56570688Snsouch
56670688Snsouchstatic devclass_t s3pci_devclass;
56770688Snsouch
56870688SnsouchDRIVER_MODULE(s3pci, pci, s3pci_driver, s3pci_devclass, 0, 0);
569