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