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