linux/drivers/gpu/drm/cirrus/cirrus.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * Copyright 2012-2019 Red Hat
   4 *
   5 * This file is subject to the terms and conditions of the GNU General
   6 * Public License version 2. See the file COPYING in the main
   7 * directory of this archive for more details.
   8 *
   9 * Authors: Matthew Garrett
  10 *          Dave Airlie
  11 *          Gerd Hoffmann
  12 *
  13 * Portions of this code derived from cirrusfb.c:
  14 * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
  15 *
  16 * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
  17 */
  18
  19#include <linux/console.h>
  20#include <linux/module.h>
  21#include <linux/pci.h>
  22
  23#include <video/cirrus.h>
  24#include <video/vga.h>
  25
  26#include <drm/drm_atomic_helper.h>
  27#include <drm/drm_atomic_state_helper.h>
  28#include <drm/drm_connector.h>
  29#include <drm/drm_damage_helper.h>
  30#include <drm/drm_drv.h>
  31#include <drm/drm_fb_helper.h>
  32#include <drm/drm_file.h>
  33#include <drm/drm_format_helper.h>
  34#include <drm/drm_fourcc.h>
  35#include <drm/drm_gem_shmem_helper.h>
  36#include <drm/drm_gem_framebuffer_helper.h>
  37#include <drm/drm_ioctl.h>
  38#include <drm/drm_modeset_helper_vtables.h>
  39#include <drm/drm_probe_helper.h>
  40#include <drm/drm_simple_kms_helper.h>
  41#include <drm/drm_vblank.h>
  42
  43#define DRIVER_NAME "cirrus"
  44#define DRIVER_DESC "qemu cirrus vga"
  45#define DRIVER_DATE "2019"
  46#define DRIVER_MAJOR 2
  47#define DRIVER_MINOR 0
  48
  49#define CIRRUS_MAX_PITCH (0x1FF << 3)      /* (4096 - 1) & ~111b bytes */
  50#define CIRRUS_VRAM_SIZE (4 * 1024 * 1024) /* 4 MB */
  51
  52struct cirrus_device {
  53        struct drm_device              dev;
  54        struct drm_simple_display_pipe pipe;
  55        struct drm_connector           conn;
  56        unsigned int                   cpp;
  57        unsigned int                   pitch;
  58        void __iomem                   *vram;
  59        void __iomem                   *mmio;
  60};
  61
  62/* ------------------------------------------------------------------ */
  63/*
  64 * The meat of this driver. The core passes us a mode and we have to program
  65 * it. The modesetting here is the bare minimum required to satisfy the qemu
  66 * emulation of this hardware, and running this against a real device is
  67 * likely to result in an inadequately programmed mode. We've already had
  68 * the opportunity to modify the mode, so whatever we receive here should
  69 * be something that can be correctly programmed and displayed
  70 */
  71
  72#define SEQ_INDEX 4
  73#define SEQ_DATA 5
  74
  75static u8 rreg_seq(struct cirrus_device *cirrus, u8 reg)
  76{
  77        iowrite8(reg, cirrus->mmio + SEQ_INDEX);
  78        return ioread8(cirrus->mmio + SEQ_DATA);
  79}
  80
  81static void wreg_seq(struct cirrus_device *cirrus, u8 reg, u8 val)
  82{
  83        iowrite8(reg, cirrus->mmio + SEQ_INDEX);
  84        iowrite8(val, cirrus->mmio + SEQ_DATA);
  85}
  86
  87#define CRT_INDEX 0x14
  88#define CRT_DATA 0x15
  89
  90static u8 rreg_crt(struct cirrus_device *cirrus, u8 reg)
  91{
  92        iowrite8(reg, cirrus->mmio + CRT_INDEX);
  93        return ioread8(cirrus->mmio + CRT_DATA);
  94}
  95
  96static void wreg_crt(struct cirrus_device *cirrus, u8 reg, u8 val)
  97{
  98        iowrite8(reg, cirrus->mmio + CRT_INDEX);
  99        iowrite8(val, cirrus->mmio + CRT_DATA);
 100}
 101
 102#define GFX_INDEX 0xe
 103#define GFX_DATA 0xf
 104
 105static void wreg_gfx(struct cirrus_device *cirrus, u8 reg, u8 val)
 106{
 107        iowrite8(reg, cirrus->mmio + GFX_INDEX);
 108        iowrite8(val, cirrus->mmio + GFX_DATA);
 109}
 110
 111#define VGA_DAC_MASK  0x06
 112
 113static void wreg_hdr(struct cirrus_device *cirrus, u8 val)
 114{
 115        ioread8(cirrus->mmio + VGA_DAC_MASK);
 116        ioread8(cirrus->mmio + VGA_DAC_MASK);
 117        ioread8(cirrus->mmio + VGA_DAC_MASK);
 118        ioread8(cirrus->mmio + VGA_DAC_MASK);
 119        iowrite8(val, cirrus->mmio + VGA_DAC_MASK);
 120}
 121
 122static int cirrus_convert_to(struct drm_framebuffer *fb)
 123{
 124        if (fb->format->cpp[0] == 4 && fb->pitches[0] > CIRRUS_MAX_PITCH) {
 125                if (fb->width * 3 <= CIRRUS_MAX_PITCH)
 126                        /* convert from XR24 to RG24 */
 127                        return 3;
 128                else
 129                        /* convert from XR24 to RG16 */
 130                        return 2;
 131        }
 132        return 0;
 133}
 134
 135static int cirrus_cpp(struct drm_framebuffer *fb)
 136{
 137        int convert_cpp = cirrus_convert_to(fb);
 138
 139        if (convert_cpp)
 140                return convert_cpp;
 141        return fb->format->cpp[0];
 142}
 143
 144static int cirrus_pitch(struct drm_framebuffer *fb)
 145{
 146        int convert_cpp = cirrus_convert_to(fb);
 147
 148        if (convert_cpp)
 149                return convert_cpp * fb->width;
 150        return fb->pitches[0];
 151}
 152
 153static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset)
 154{
 155        u32 addr;
 156        u8 tmp;
 157
 158        addr = offset >> 2;
 159        wreg_crt(cirrus, 0x0c, (u8)((addr >> 8) & 0xff));
 160        wreg_crt(cirrus, 0x0d, (u8)(addr & 0xff));
 161
 162        tmp = rreg_crt(cirrus, 0x1b);
 163        tmp &= 0xf2;
 164        tmp |= (addr >> 16) & 0x01;
 165        tmp |= (addr >> 15) & 0x0c;
 166        wreg_crt(cirrus, 0x1b, tmp);
 167
 168        tmp = rreg_crt(cirrus, 0x1d);
 169        tmp &= 0x7f;
 170        tmp |= (addr >> 12) & 0x80;
 171        wreg_crt(cirrus, 0x1d, tmp);
 172}
 173
 174static int cirrus_mode_set(struct cirrus_device *cirrus,
 175                           struct drm_display_mode *mode,
 176                           struct drm_framebuffer *fb)
 177{
 178        int hsyncstart, hsyncend, htotal, hdispend;
 179        int vtotal, vdispend;
 180        int tmp;
 181        int sr07 = 0, hdr = 0;
 182
 183        htotal = mode->htotal / 8;
 184        hsyncend = mode->hsync_end / 8;
 185        hsyncstart = mode->hsync_start / 8;
 186        hdispend = mode->hdisplay / 8;
 187
 188        vtotal = mode->vtotal;
 189        vdispend = mode->vdisplay;
 190
 191        vdispend -= 1;
 192        vtotal -= 2;
 193
 194        htotal -= 5;
 195        hdispend -= 1;
 196        hsyncstart += 1;
 197        hsyncend += 1;
 198
 199        wreg_crt(cirrus, VGA_CRTC_V_SYNC_END, 0x20);
 200        wreg_crt(cirrus, VGA_CRTC_H_TOTAL, htotal);
 201        wreg_crt(cirrus, VGA_CRTC_H_DISP, hdispend);
 202        wreg_crt(cirrus, VGA_CRTC_H_SYNC_START, hsyncstart);
 203        wreg_crt(cirrus, VGA_CRTC_H_SYNC_END, hsyncend);
 204        wreg_crt(cirrus, VGA_CRTC_V_TOTAL, vtotal & 0xff);
 205        wreg_crt(cirrus, VGA_CRTC_V_DISP_END, vdispend & 0xff);
 206
 207        tmp = 0x40;
 208        if ((vdispend + 1) & 512)
 209                tmp |= 0x20;
 210        wreg_crt(cirrus, VGA_CRTC_MAX_SCAN, tmp);
 211
 212        /*
 213         * Overflow bits for values that don't fit in the standard registers
 214         */
 215        tmp = 0x10;
 216        if (vtotal & 0x100)
 217                tmp |= 0x01;
 218        if (vdispend & 0x100)
 219                tmp |= 0x02;
 220        if ((vdispend + 1) & 0x100)
 221                tmp |= 0x08;
 222        if (vtotal & 0x200)
 223                tmp |= 0x20;
 224        if (vdispend & 0x200)
 225                tmp |= 0x40;
 226        wreg_crt(cirrus, VGA_CRTC_OVERFLOW, tmp);
 227
 228        tmp = 0;
 229
 230        /* More overflow bits */
 231
 232        if ((htotal + 5) & 0x40)
 233                tmp |= 0x10;
 234        if ((htotal + 5) & 0x80)
 235                tmp |= 0x20;
 236        if (vtotal & 0x100)
 237                tmp |= 0x40;
 238        if (vtotal & 0x200)
 239                tmp |= 0x80;
 240
 241        wreg_crt(cirrus, CL_CRT1A, tmp);
 242
 243        /* Disable Hercules/CGA compatibility */
 244        wreg_crt(cirrus, VGA_CRTC_MODE, 0x03);
 245
 246        sr07 = rreg_seq(cirrus, 0x07);
 247        sr07 &= 0xe0;
 248        hdr = 0;
 249
 250        cirrus->cpp = cirrus_cpp(fb);
 251        switch (cirrus->cpp * 8) {
 252        case 8:
 253                sr07 |= 0x11;
 254                break;
 255        case 16:
 256                sr07 |= 0x17;
 257                hdr = 0xc1;
 258                break;
 259        case 24:
 260                sr07 |= 0x15;
 261                hdr = 0xc5;
 262                break;
 263        case 32:
 264                sr07 |= 0x19;
 265                hdr = 0xc5;
 266                break;
 267        default:
 268                return -1;
 269        }
 270
 271        wreg_seq(cirrus, 0x7, sr07);
 272
 273        /* Program the pitch */
 274        cirrus->pitch = cirrus_pitch(fb);
 275        tmp = cirrus->pitch / 8;
 276        wreg_crt(cirrus, VGA_CRTC_OFFSET, tmp);
 277
 278        /* Enable extended blanking and pitch bits, and enable full memory */
 279        tmp = 0x22;
 280        tmp |= (cirrus->pitch >> 7) & 0x10;
 281        tmp |= (cirrus->pitch >> 6) & 0x40;
 282        wreg_crt(cirrus, 0x1b, tmp);
 283
 284        /* Enable high-colour modes */
 285        wreg_gfx(cirrus, VGA_GFX_MODE, 0x40);
 286
 287        /* And set graphics mode */
 288        wreg_gfx(cirrus, VGA_GFX_MISC, 0x01);
 289
 290        wreg_hdr(cirrus, hdr);
 291
 292        cirrus_set_start_address(cirrus, 0);
 293
 294        /* Unblank (needed on S3 resume, vgabios doesn't do it then) */
 295        outb(0x20, 0x3c0);
 296        return 0;
 297}
 298
 299static int cirrus_fb_blit_rect(struct drm_framebuffer *fb,
 300                               struct drm_rect *rect)
 301{
 302        struct cirrus_device *cirrus = fb->dev->dev_private;
 303        void *vmap;
 304
 305        vmap = drm_gem_shmem_vmap(fb->obj[0]);
 306        if (!vmap)
 307                return -ENOMEM;
 308
 309        if (cirrus->cpp == fb->format->cpp[0])
 310                drm_fb_memcpy_dstclip(cirrus->vram,
 311                                      vmap, fb, rect);
 312
 313        else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2)
 314                drm_fb_xrgb8888_to_rgb565_dstclip(cirrus->vram,
 315                                                  cirrus->pitch,
 316                                                  vmap, fb, rect, false);
 317
 318        else if (fb->format->cpp[0] == 4 && cirrus->cpp == 3)
 319                drm_fb_xrgb8888_to_rgb888_dstclip(cirrus->vram,
 320                                                  cirrus->pitch,
 321                                                  vmap, fb, rect);
 322
 323        else
 324                WARN_ON_ONCE("cpp mismatch");
 325
 326        drm_gem_shmem_vunmap(fb->obj[0], vmap);
 327        return 0;
 328}
 329
 330static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb)
 331{
 332        struct drm_rect fullscreen = {
 333                .x1 = 0,
 334                .x2 = fb->width,
 335                .y1 = 0,
 336                .y2 = fb->height,
 337        };
 338        return cirrus_fb_blit_rect(fb, &fullscreen);
 339}
 340
 341static int cirrus_check_size(int width, int height,
 342                             struct drm_framebuffer *fb)
 343{
 344        int pitch = width * 2;
 345
 346        if (fb)
 347                pitch = cirrus_pitch(fb);
 348
 349        if (pitch > CIRRUS_MAX_PITCH)
 350                return -EINVAL;
 351        if (pitch * height > CIRRUS_VRAM_SIZE)
 352                return -EINVAL;
 353        return 0;
 354}
 355
 356/* ------------------------------------------------------------------ */
 357/* cirrus connector                                                   */
 358
 359static int cirrus_conn_get_modes(struct drm_connector *conn)
 360{
 361        int count;
 362
 363        count = drm_add_modes_noedid(conn,
 364                                     conn->dev->mode_config.max_width,
 365                                     conn->dev->mode_config.max_height);
 366        drm_set_preferred_mode(conn, 1024, 768);
 367        return count;
 368}
 369
 370static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = {
 371        .get_modes = cirrus_conn_get_modes,
 372};
 373
 374static const struct drm_connector_funcs cirrus_conn_funcs = {
 375        .fill_modes = drm_helper_probe_single_connector_modes,
 376        .destroy = drm_connector_cleanup,
 377        .reset = drm_atomic_helper_connector_reset,
 378        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 379        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 380};
 381
 382static int cirrus_conn_init(struct cirrus_device *cirrus)
 383{
 384        drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs);
 385        return drm_connector_init(&cirrus->dev, &cirrus->conn,
 386                                  &cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA);
 387
 388}
 389
 390/* ------------------------------------------------------------------ */
 391/* cirrus (simple) display pipe                                       */
 392
 393static enum drm_mode_status cirrus_pipe_mode_valid(struct drm_crtc *crtc,
 394                                                   const struct drm_display_mode *mode)
 395{
 396        if (cirrus_check_size(mode->hdisplay, mode->vdisplay, NULL) < 0)
 397                return MODE_BAD;
 398        return MODE_OK;
 399}
 400
 401static int cirrus_pipe_check(struct drm_simple_display_pipe *pipe,
 402                             struct drm_plane_state *plane_state,
 403                             struct drm_crtc_state *crtc_state)
 404{
 405        struct drm_framebuffer *fb = plane_state->fb;
 406
 407        if (!fb)
 408                return 0;
 409        return cirrus_check_size(fb->width, fb->height, fb);
 410}
 411
 412static void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe,
 413                               struct drm_crtc_state *crtc_state,
 414                               struct drm_plane_state *plane_state)
 415{
 416        struct cirrus_device *cirrus = pipe->crtc.dev->dev_private;
 417
 418        cirrus_mode_set(cirrus, &crtc_state->mode, plane_state->fb);
 419        cirrus_fb_blit_fullscreen(plane_state->fb);
 420}
 421
 422static void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
 423                               struct drm_plane_state *old_state)
 424{
 425        struct cirrus_device *cirrus = pipe->crtc.dev->dev_private;
 426        struct drm_plane_state *state = pipe->plane.state;
 427        struct drm_crtc *crtc = &pipe->crtc;
 428        struct drm_rect rect;
 429
 430        if (pipe->plane.state->fb &&
 431            cirrus->cpp != cirrus_cpp(pipe->plane.state->fb))
 432                cirrus_mode_set(cirrus, &crtc->mode,
 433                                pipe->plane.state->fb);
 434
 435        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
 436                cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
 437
 438        if (crtc->state->event) {
 439                spin_lock_irq(&crtc->dev->event_lock);
 440                drm_crtc_send_vblank_event(crtc, crtc->state->event);
 441                crtc->state->event = NULL;
 442                spin_unlock_irq(&crtc->dev->event_lock);
 443        }
 444}
 445
 446static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = {
 447        .mode_valid = cirrus_pipe_mode_valid,
 448        .check      = cirrus_pipe_check,
 449        .enable     = cirrus_pipe_enable,
 450        .update     = cirrus_pipe_update,
 451};
 452
 453static const uint32_t cirrus_formats[] = {
 454        DRM_FORMAT_RGB565,
 455        DRM_FORMAT_RGB888,
 456        DRM_FORMAT_XRGB8888,
 457};
 458
 459static const uint64_t cirrus_modifiers[] = {
 460        DRM_FORMAT_MOD_LINEAR,
 461        DRM_FORMAT_MOD_INVALID
 462};
 463
 464static int cirrus_pipe_init(struct cirrus_device *cirrus)
 465{
 466        return drm_simple_display_pipe_init(&cirrus->dev,
 467                                            &cirrus->pipe,
 468                                            &cirrus_pipe_funcs,
 469                                            cirrus_formats,
 470                                            ARRAY_SIZE(cirrus_formats),
 471                                            cirrus_modifiers,
 472                                            &cirrus->conn);
 473}
 474
 475/* ------------------------------------------------------------------ */
 476/* cirrus framebuffers & mode config                                  */
 477
 478static struct drm_framebuffer*
 479cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 480                 const struct drm_mode_fb_cmd2 *mode_cmd)
 481{
 482        if (mode_cmd->pixel_format != DRM_FORMAT_RGB565 &&
 483            mode_cmd->pixel_format != DRM_FORMAT_RGB888 &&
 484            mode_cmd->pixel_format != DRM_FORMAT_XRGB8888)
 485                return ERR_PTR(-EINVAL);
 486        if (cirrus_check_size(mode_cmd->width, mode_cmd->height, NULL) < 0)
 487                return ERR_PTR(-EINVAL);
 488        return drm_gem_fb_create_with_dirty(dev, file_priv, mode_cmd);
 489}
 490
 491static const struct drm_mode_config_funcs cirrus_mode_config_funcs = {
 492        .fb_create = cirrus_fb_create,
 493        .atomic_check = drm_atomic_helper_check,
 494        .atomic_commit = drm_atomic_helper_commit,
 495};
 496
 497static void cirrus_mode_config_init(struct cirrus_device *cirrus)
 498{
 499        struct drm_device *dev = &cirrus->dev;
 500
 501        drm_mode_config_init(dev);
 502        dev->mode_config.min_width = 0;
 503        dev->mode_config.min_height = 0;
 504        dev->mode_config.max_width = CIRRUS_MAX_PITCH / 2;
 505        dev->mode_config.max_height = 1024;
 506        dev->mode_config.preferred_depth = 16;
 507        dev->mode_config.prefer_shadow = 0;
 508        dev->mode_config.funcs = &cirrus_mode_config_funcs;
 509}
 510
 511/* ------------------------------------------------------------------ */
 512
 513DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops);
 514
 515static struct drm_driver cirrus_driver = {
 516        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_PRIME,
 517
 518        .name            = DRIVER_NAME,
 519        .desc            = DRIVER_DESC,
 520        .date            = DRIVER_DATE,
 521        .major           = DRIVER_MAJOR,
 522        .minor           = DRIVER_MINOR,
 523
 524        .fops            = &cirrus_fops,
 525        DRM_GEM_SHMEM_DRIVER_OPS,
 526};
 527
 528static int cirrus_pci_probe(struct pci_dev *pdev,
 529                            const struct pci_device_id *ent)
 530{
 531        struct drm_device *dev;
 532        struct cirrus_device *cirrus;
 533        int ret;
 534
 535        ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
 536        if (ret)
 537                return ret;
 538
 539        ret = pci_enable_device(pdev);
 540        if (ret)
 541                return ret;
 542
 543        ret = pci_request_regions(pdev, DRIVER_NAME);
 544        if (ret)
 545                return ret;
 546
 547        ret = -ENOMEM;
 548        cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL);
 549        if (cirrus == NULL)
 550                goto err_pci_release;
 551
 552        dev = &cirrus->dev;
 553        ret = drm_dev_init(dev, &cirrus_driver, &pdev->dev);
 554        if (ret)
 555                goto err_free_cirrus;
 556        dev->dev_private = cirrus;
 557
 558        ret = -ENOMEM;
 559        cirrus->vram = ioremap(pci_resource_start(pdev, 0),
 560                               pci_resource_len(pdev, 0));
 561        if (cirrus->vram == NULL)
 562                goto err_dev_put;
 563
 564        cirrus->mmio = ioremap(pci_resource_start(pdev, 1),
 565                               pci_resource_len(pdev, 1));
 566        if (cirrus->mmio == NULL)
 567                goto err_unmap_vram;
 568
 569        cirrus_mode_config_init(cirrus);
 570
 571        ret = cirrus_conn_init(cirrus);
 572        if (ret < 0)
 573                goto err_cleanup;
 574
 575        ret = cirrus_pipe_init(cirrus);
 576        if (ret < 0)
 577                goto err_cleanup;
 578
 579        drm_mode_config_reset(dev);
 580
 581        dev->pdev = pdev;
 582        pci_set_drvdata(pdev, dev);
 583        ret = drm_dev_register(dev, 0);
 584        if (ret)
 585                goto err_cleanup;
 586
 587        drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
 588        return 0;
 589
 590err_cleanup:
 591        drm_mode_config_cleanup(dev);
 592        iounmap(cirrus->mmio);
 593err_unmap_vram:
 594        iounmap(cirrus->vram);
 595err_dev_put:
 596        drm_dev_put(dev);
 597err_free_cirrus:
 598        kfree(cirrus);
 599err_pci_release:
 600        pci_release_regions(pdev);
 601        return ret;
 602}
 603
 604static void cirrus_pci_remove(struct pci_dev *pdev)
 605{
 606        struct drm_device *dev = pci_get_drvdata(pdev);
 607        struct cirrus_device *cirrus = dev->dev_private;
 608
 609        drm_dev_unregister(dev);
 610        drm_mode_config_cleanup(dev);
 611        iounmap(cirrus->mmio);
 612        iounmap(cirrus->vram);
 613        drm_dev_put(dev);
 614        kfree(cirrus);
 615        pci_release_regions(pdev);
 616}
 617
 618static const struct pci_device_id pciidlist[] = {
 619        {
 620                .vendor    = PCI_VENDOR_ID_CIRRUS,
 621                .device    = PCI_DEVICE_ID_CIRRUS_5446,
 622                /* only bind to the cirrus chip in qemu */
 623                .subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
 624                .subdevice = PCI_SUBDEVICE_ID_QEMU,
 625        }, {
 626                .vendor    = PCI_VENDOR_ID_CIRRUS,
 627                .device    = PCI_DEVICE_ID_CIRRUS_5446,
 628                .subvendor = PCI_VENDOR_ID_XEN,
 629                .subdevice = 0x0001,
 630        },
 631        { /* end if list */ }
 632};
 633
 634static struct pci_driver cirrus_pci_driver = {
 635        .name = DRIVER_NAME,
 636        .id_table = pciidlist,
 637        .probe = cirrus_pci_probe,
 638        .remove = cirrus_pci_remove,
 639};
 640
 641static int __init cirrus_init(void)
 642{
 643        if (vgacon_text_force())
 644                return -EINVAL;
 645        return pci_register_driver(&cirrus_pci_driver);
 646}
 647
 648static void __exit cirrus_exit(void)
 649{
 650        pci_unregister_driver(&cirrus_pci_driver);
 651}
 652
 653module_init(cirrus_init);
 654module_exit(cirrus_exit);
 655
 656MODULE_DEVICE_TABLE(pci, pciidlist);
 657MODULE_LICENSE("GPL");
 658