The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/fb/s3_pci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/7.4/sys/dev/fb/s3_pci.c 185559 2008-12-02 13:29:35Z kib $");
   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.h>
   38 
   39 #include <vm/vm.h>
   40 #include <vm/vm_extern.h>
   41 #include <vm/vm_kern.h>
   42 #include <vm/pmap.h>
   43 
   44 #include <sys/uio.h>
   45 #include <sys/module.h>
   46 #include <sys/bus.h>
   47 #include <sys/rman.h>
   48 #include <machine/resource.h>
   49 
   50 #include <sys/malloc.h>
   51 #include <sys/fbio.h>
   52 
   53 #include <dev/pci/pcireg.h>
   54 #include <dev/pci/pcivar.h>
   55 
   56 #include <machine/md_var.h>
   57 #include <machine/vm86.h>
   58 #include <machine/pc/bios.h>
   59 #include <machine/pc/vesa.h>
   60 
   61 #include <dev/fb/fbreg.h>
   62 #include <dev/fb/vgareg.h>
   63 
   64 #define S3PCI_DEBUG 1
   65 
   66 #define PCI_S3_VENDOR_ID        0x5333
   67 
   68 #define S3_CONFIG_IO            0x3c0   /* VGA standard config io ports */
   69 #define S3_CONFIG_IO_SIZE       0x20
   70 
   71 #define S3_ENHANCED_IO          0x4ae8  /* Extended config register */
   72 #define S3_ENHANCED_IO_SIZE     1
   73 
   74 #define S3_CRTC_ADDR            0x14
   75 #define S3_CRTC_VALUE           0x15
   76 
   77 #define PCI_BASE_MEMORY         0x10
   78 
   79 #define outb_p(value, offset) bus_space_write_1(sc->st, sc->sh, offset, value)
   80 #define inb_p(offset) (bus_space_read_1(sc->st, sc->sh, offset))
   81 #define outb_enh(value, offset) bus_space_write_1(sc->enh_st, sc->enh_sh, \
   82                                                                 offset, value)
   83 #define inb_enh(offset) (bus_space_read_1(sc->enh_st, sc->enh_sh, offset))
   84 
   85 struct s3pci_softc {
   86         bus_space_tag_t st;
   87         bus_space_handle_t sh;
   88         bus_space_tag_t enh_st;
   89         bus_space_handle_t enh_sh;
   90         struct resource *port_res;
   91         struct resource *enh_res;
   92         struct resource *mem_res;
   93         u_long mem_base;
   94         u_long mem_size;
   95 };
   96 
   97 static int                      s3lfb_error(void);
   98 static vi_probe_t               s3lfb_probe;
   99 static vi_init_t                s3lfb_init;
  100 static vi_get_info_t            s3lfb_get_info;
  101 static vi_query_mode_t          s3lfb_query_mode;
  102 static vi_set_mode_t            s3lfb_set_mode;
  103 static vi_save_font_t           s3lfb_save_font;
  104 static vi_load_font_t           s3lfb_load_font;
  105 static vi_show_font_t           s3lfb_show_font;
  106 static vi_save_palette_t        s3lfb_save_palette;
  107 static vi_load_palette_t        s3lfb_load_palette;
  108 static vi_set_border_t          s3lfb_set_border;
  109 static vi_save_state_t          s3lfb_save_state;
  110 static vi_load_state_t          s3lfb_load_state;
  111 static vi_set_win_org_t         s3lfb_set_origin;
  112 static vi_read_hw_cursor_t      s3lfb_read_hw_cursor;
  113 static vi_set_hw_cursor_t       s3lfb_set_hw_cursor;
  114 static vi_set_hw_cursor_shape_t s3lfb_set_hw_cursor_shape;
  115 static vi_blank_display_t       s3lfb_blank_display;
  116 static vi_mmap_t                s3lfb_mmap;
  117 static vi_ioctl_t               s3lfb_ioctl;
  118 static vi_clear_t               s3lfb_clear;
  119 static vi_fill_rect_t           s3lfb_fill_rect;
  120 static vi_bitblt_t              s3lfb_bitblt;
  121 static vi_diag_t                s3lfb_diag;
  122 
  123 static video_switch_t s3lfbvidsw = {
  124         s3lfb_probe,
  125         s3lfb_init,
  126         s3lfb_get_info,
  127         s3lfb_query_mode,
  128         s3lfb_set_mode,
  129         s3lfb_save_font,
  130         s3lfb_load_font,
  131         s3lfb_show_font,
  132         s3lfb_save_palette,
  133         s3lfb_load_palette,
  134         s3lfb_set_border,
  135         s3lfb_save_state,
  136         s3lfb_load_state,
  137         s3lfb_set_origin,
  138         s3lfb_read_hw_cursor,
  139         s3lfb_set_hw_cursor,
  140         s3lfb_set_hw_cursor_shape,
  141         s3lfb_blank_display,
  142         s3lfb_mmap,
  143         s3lfb_ioctl,
  144         s3lfb_clear,
  145         s3lfb_fill_rect,
  146         s3lfb_bitblt,
  147         s3lfb_error,
  148         s3lfb_error,
  149         s3lfb_diag,
  150 };
  151 
  152 static video_switch_t *prevvidsw;
  153 static device_t s3pci_dev = NULL;
  154 
  155 static int
  156 s3lfb_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
  157 {
  158         return (*prevvidsw->probe)(unit, adpp, arg, flags);
  159 }
  160 
  161 static int
  162 s3lfb_init(int unit, video_adapter_t *adp, int flags)
  163 {
  164         return (*prevvidsw->init)(unit, adp, flags);
  165 }
  166 
  167 static int
  168 s3lfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
  169 {
  170 #if 0
  171         device_t dev = s3pci_dev;                       /* XXX */
  172         struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
  173 #endif
  174         int error;
  175 
  176         if ((error = (*prevvidsw->get_info)(adp, mode, info)))
  177                 return error;
  178 
  179 #if 0
  180         /* Don't use linear addressing with text modes
  181          */
  182         if ((mode > M_VESA_BASE) &&
  183                 (info->vi_flags & V_INFO_GRAPHICS) &&
  184                 !(info->vi_flags & V_INFO_LINEAR)) {
  185 
  186                 info->vi_flags |= V_INFO_LINEAR;
  187                 info->vi_buffer = sc->mem_base;
  188 
  189         } else {
  190                 info->vi_buffer = 0;
  191         }
  192 #endif
  193 
  194         return 0;
  195 }
  196 
  197 static int
  198 s3lfb_query_mode(video_adapter_t *adp, video_info_t *info)
  199 {
  200         return (*prevvidsw->query_mode)(adp, info);
  201 }
  202 
  203 static vm_offset_t
  204 s3lfb_map_buffer(u_int paddr, size_t size)
  205 {
  206         vm_offset_t vaddr;
  207         u_int off;
  208 
  209         off = paddr - trunc_page(paddr);
  210         vaddr = (vm_offset_t)pmap_mapdev(paddr - off, size + off);
  211 
  212         return (vaddr + off);
  213 }
  214 
  215 static int
  216 s3lfb_set_mode(video_adapter_t *adp, int mode)
  217 {
  218         device_t dev = s3pci_dev;                       /* XXX */
  219         struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
  220 #if 0
  221         unsigned char tmp;
  222 #endif
  223         int error;
  224 
  225         /* First, set the mode as if it was a classic VESA card
  226          */
  227         if ((error = (*prevvidsw->set_mode)(adp, mode)))
  228                 return error;
  229 
  230         /* If not in a linear mode (according to s3lfb_get_info() called
  231          * by vesa_set_mode in the (*vidsw[adp->va_index]->get_info)...
  232          * sequence, return with no error
  233          */
  234 #if 0
  235         if (!(adp->va_info.vi_flags & V_INFO_LINEAR))
  236                 return 0;
  237 #endif
  238 
  239         if ((mode <= M_VESA_BASE) ||
  240                 !(adp->va_info.vi_flags & V_INFO_GRAPHICS) ||
  241                 (adp->va_info.vi_flags & V_INFO_LINEAR))
  242                 return 0;
  243 
  244         /* Ok, now apply the configuration to the card */
  245 
  246         outb_p(0x38, S3_CRTC_ADDR); outb_p(0x48, S3_CRTC_VALUE);
  247         outb_p(0x39, S3_CRTC_ADDR); outb_p(0xa5, S3_CRTC_VALUE);
  248        
  249        /* check that CR47 is read/write */
  250        
  251 #if 0
  252         outb_p(0x47, S3_CRTC_ADDR); outb_p(0xff, S3_CRTC_VALUE);
  253         tmp = inb_p(S3_CRTC_VALUE);
  254         outb_p(0x00, S3_CRTC_VALUE);
  255         if ((tmp != 0xff) || (inb_p(S3_CRTC_VALUE)))
  256         {
  257                 /* lock S3 registers */
  258 
  259                 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
  260                 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
  261 
  262                 return ENXIO;
  263         }
  264 #endif
  265 
  266         /* enable enhanced register access */
  267 
  268         outb_p(0x40, S3_CRTC_ADDR);
  269         outb_p(inb_p(S3_CRTC_VALUE) | 1, S3_CRTC_VALUE);
  270 
  271         /* enable enhanced functions */
  272 
  273         outb_enh(inb_enh(0) | 1, 0x0);
  274 
  275         /* enable enhanced mode memory mapping */
  276 
  277         outb_p(0x31, S3_CRTC_ADDR);
  278         outb_p(inb_p(S3_CRTC_VALUE) | 8, S3_CRTC_VALUE);
  279 
  280         /* enable linear frame buffer and set address window to max */
  281 
  282         outb_p(0x58, S3_CRTC_ADDR);
  283         outb_p(inb_p(S3_CRTC_VALUE) | 0x13, S3_CRTC_VALUE);
  284 
  285         /* disabled enhanced register access */
  286 
  287         outb_p(0x40, S3_CRTC_ADDR);
  288         outb_p(inb_p(S3_CRTC_VALUE) & ~1, S3_CRTC_VALUE);
  289 
  290         /* lock S3 registers */
  291 
  292         outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
  293         outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
  294 
  295         adp->va_info.vi_flags |= V_INFO_LINEAR;
  296         adp->va_info.vi_buffer = sc->mem_base;
  297         adp->va_buffer = s3lfb_map_buffer(adp->va_info.vi_buffer,
  298                                 adp->va_info.vi_buffer_size);
  299         adp->va_buffer_size = adp->va_info.vi_buffer_size;
  300         adp->va_window = adp->va_buffer;
  301         adp->va_window_size = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
  302         adp->va_window_gran = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
  303 
  304         return 0;
  305 }
  306 
  307 static int
  308 s3lfb_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
  309                u_char *data, int ch, int count)
  310 {
  311         return (*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data,
  312                 ch, count);
  313 }
  314 
  315 static int
  316 s3lfb_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
  317                u_char *data, int ch, int count)
  318 {
  319         return (*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data,
  320                 ch, count);
  321 }
  322 
  323 static int
  324 s3lfb_show_font(video_adapter_t *adp, int page)
  325 {
  326         return (*prevvidsw->show_font)(adp, page);
  327 }
  328 
  329 static int
  330 s3lfb_save_palette(video_adapter_t *adp, u_char *palette)
  331 {
  332         return (*prevvidsw->save_palette)(adp, palette);
  333 }
  334 
  335 static int
  336 s3lfb_load_palette(video_adapter_t *adp, u_char *palette)
  337 {
  338         return (*prevvidsw->load_palette)(adp, palette);
  339 }
  340 
  341 static int
  342 s3lfb_set_border(video_adapter_t *adp, int color)
  343 {
  344         return (*prevvidsw->set_border)(adp, color);
  345 }
  346 
  347 static int
  348 s3lfb_save_state(video_adapter_t *adp, void *p, size_t size)
  349 {
  350         return (*prevvidsw->save_state)(adp, p, size);
  351 }
  352 
  353 static int
  354 s3lfb_load_state(video_adapter_t *adp, void *p)
  355 {
  356         return (*prevvidsw->load_state)(adp, p);
  357 }
  358 
  359 static int
  360 s3lfb_set_origin(video_adapter_t *adp, off_t offset)
  361 {
  362         return (*prevvidsw->set_win_org)(adp, offset);
  363 }
  364 
  365 static int
  366 s3lfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
  367 {
  368         return (*prevvidsw->read_hw_cursor)(adp, col, row);
  369 }
  370 
  371 static int
  372 s3lfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
  373 {
  374         return (*prevvidsw->set_hw_cursor)(adp, col, row);
  375 }
  376 
  377 static int
  378 s3lfb_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 
  385 static int
  386 s3lfb_blank_display(video_adapter_t *adp, int mode) 
  387 {
  388         return (*prevvidsw->blank_display)(adp, mode);
  389 }
  390 
  391 static int
  392 s3lfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr,
  393           int prot)
  394 {
  395         return (*prevvidsw->mmap)(adp, offset, paddr, prot);
  396 }
  397 
  398 static int
  399 s3lfb_clear(video_adapter_t *adp)
  400 {
  401         return (*prevvidsw->clear)(adp);
  402 }
  403 
  404 static int
  405 s3lfb_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 
  410 static int
  411 s3lfb_bitblt(video_adapter_t *adp,...)
  412 {
  413         return (*prevvidsw->bitblt)(adp);               /* XXX */
  414 }
  415 
  416 static int
  417 s3lfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
  418 {
  419         return (*prevvidsw->ioctl)(adp, cmd, arg);
  420 }
  421 
  422 static int
  423 s3lfb_diag(video_adapter_t *adp, int level)
  424 {
  425         return (*prevvidsw->diag)(adp, level);
  426 }
  427 
  428 static int
  429 s3lfb_error(void)
  430 {
  431         return 1;
  432 }
  433 
  434 /***********************************/
  435 /* PCI detection/attachement stuff */
  436 /***********************************/
  437 
  438 static int
  439 s3pci_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 BUS_PROBE_DEFAULT;
  460 
  461 };
  462 
  463 static int
  464 s3pci_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_any(dev, SYS_RES_MEMORY, &rid,
  502                                  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 
  540 error:
  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 
  553 static device_method_t s3pci_methods[] = {
  554 
  555         DEVMETHOD(device_probe, s3pci_probe),
  556         DEVMETHOD(device_attach, s3pci_attach),
  557         {0,0}
  558 };
  559 
  560 static driver_t s3pci_driver = {
  561         "s3pci",
  562         s3pci_methods,
  563         sizeof(struct s3pci_softc),
  564 };
  565 
  566 static devclass_t s3pci_devclass;
  567 
  568 DRIVER_MODULE(s3pci, pci, s3pci_driver, s3pci_devclass, 0, 0);

Cache object: 606e19ab7082541b7177e4cec6057178


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.