brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · 31fc5d8 Raw
738 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3#include <linux/module.h>4#include <linux/pci.h>5 6#include <drm/drm_aperture.h>7#include <drm/drm_atomic_helper.h>8#include <drm/drm_drv.h>9#include <drm/drm_edid.h>10#include <drm/drm_fbdev_ttm.h>11#include <drm/drm_fourcc.h>12#include <drm/drm_framebuffer.h>13#include <drm/drm_gem_framebuffer_helper.h>14#include <drm/drm_gem_vram_helper.h>15#include <drm/drm_managed.h>16#include <drm/drm_module.h>17#include <drm/drm_probe_helper.h>18#include <drm/drm_simple_kms_helper.h>19 20#include <video/vga.h>21 22/* ---------------------------------------------------------------------- */23 24#define VBE_DISPI_IOPORT_INDEX           0x01CE25#define VBE_DISPI_IOPORT_DATA            0x01CF26 27#define VBE_DISPI_INDEX_ID               0x028#define VBE_DISPI_INDEX_XRES             0x129#define VBE_DISPI_INDEX_YRES             0x230#define VBE_DISPI_INDEX_BPP              0x331#define VBE_DISPI_INDEX_ENABLE           0x432#define VBE_DISPI_INDEX_BANK             0x533#define VBE_DISPI_INDEX_VIRT_WIDTH       0x634#define VBE_DISPI_INDEX_VIRT_HEIGHT      0x735#define VBE_DISPI_INDEX_X_OFFSET         0x836#define VBE_DISPI_INDEX_Y_OFFSET         0x937#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa38 39#define VBE_DISPI_ID0                    0xB0C040#define VBE_DISPI_ID1                    0xB0C141#define VBE_DISPI_ID2                    0xB0C242#define VBE_DISPI_ID3                    0xB0C343#define VBE_DISPI_ID4                    0xB0C444#define VBE_DISPI_ID5                    0xB0C545 46#define VBE_DISPI_DISABLED               0x0047#define VBE_DISPI_ENABLED                0x0148#define VBE_DISPI_GETCAPS                0x0249#define VBE_DISPI_8BIT_DAC               0x2050#define VBE_DISPI_LFB_ENABLED            0x4051#define VBE_DISPI_NOCLEARMEM             0x8052 53static int bochs_modeset = -1;54static int defx = 1024;55static int defy = 768;56 57module_param_named(modeset, bochs_modeset, int, 0444);58MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");59 60module_param(defx, int, 0444);61module_param(defy, int, 0444);62MODULE_PARM_DESC(defx, "default x resolution");63MODULE_PARM_DESC(defy, "default y resolution");64 65/* ---------------------------------------------------------------------- */66 67enum bochs_types {68	BOCHS_QEMU_STDVGA,69	BOCHS_SIMICS,70	BOCHS_UNKNOWN,71};72 73struct bochs_device {74	/* hw */75	void __iomem   *mmio;76	int            ioports;77	void __iomem   *fb_map;78	unsigned long  fb_base;79	unsigned long  fb_size;80	unsigned long  qext_size;81 82	/* mode */83	u16 xres;84	u16 yres;85	u16 yres_virtual;86	u32 stride;87	u32 bpp;88	const struct drm_edid *drm_edid;89 90	/* drm */91	struct drm_device *dev;92	struct drm_simple_display_pipe pipe;93	struct drm_connector connector;94};95 96/* ---------------------------------------------------------------------- */97 98static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val)99{100	if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df))101		return;102 103	if (bochs->mmio) {104		int offset = ioport - 0x3c0 + 0x400;105 106		writeb(val, bochs->mmio + offset);107	} else {108		outb(val, ioport);109	}110}111 112static u8 bochs_vga_readb(struct bochs_device *bochs, u16 ioport)113{114	if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df))115		return 0xff;116 117	if (bochs->mmio) {118		int offset = ioport - 0x3c0 + 0x400;119 120		return readb(bochs->mmio + offset);121	} else {122		return inb(ioport);123	}124}125 126static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg)127{128	u16 ret = 0;129 130	if (bochs->mmio) {131		int offset = 0x500 + (reg << 1);132 133		ret = readw(bochs->mmio + offset);134	} else {135		outw(reg, VBE_DISPI_IOPORT_INDEX);136		ret = inw(VBE_DISPI_IOPORT_DATA);137	}138	return ret;139}140 141static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val)142{143	if (bochs->mmio) {144		int offset = 0x500 + (reg << 1);145 146		writew(val, bochs->mmio + offset);147	} else {148		outw(reg, VBE_DISPI_IOPORT_INDEX);149		outw(val, VBE_DISPI_IOPORT_DATA);150	}151}152 153static void bochs_hw_set_big_endian(struct bochs_device *bochs)154{155	if (bochs->qext_size < 8)156		return;157 158	writel(0xbebebebe, bochs->mmio + 0x604);159}160 161static void bochs_hw_set_little_endian(struct bochs_device *bochs)162{163	if (bochs->qext_size < 8)164		return;165 166	writel(0x1e1e1e1e, bochs->mmio + 0x604);167}168 169#ifdef __BIG_ENDIAN170#define bochs_hw_set_native_endian(_b) bochs_hw_set_big_endian(_b)171#else172#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b)173#endif174 175static int bochs_get_edid_block(void *data, u8 *buf,176				unsigned int block, size_t len)177{178	struct bochs_device *bochs = data;179	size_t i, start = block * EDID_LENGTH;180 181	if (start + len > 0x400 /* vga register offset */)182		return -1;183 184	for (i = 0; i < len; i++)185		buf[i] = readb(bochs->mmio + start + i);186 187	return 0;188}189 190static int bochs_hw_load_edid(struct bochs_device *bochs)191{192	u8 header[8];193 194	if (!bochs->mmio)195		return -1;196 197	/* check header to detect whenever edid support is enabled in qemu */198	bochs_get_edid_block(bochs, header, 0, ARRAY_SIZE(header));199	if (drm_edid_header_is_valid(header) != 8)200		return -1;201 202	drm_edid_free(bochs->drm_edid);203	bochs->drm_edid = drm_edid_read_custom(&bochs->connector,204					       bochs_get_edid_block, bochs);205	if (!bochs->drm_edid)206		return -1;207 208	return 0;209}210 211static int bochs_hw_init(struct drm_device *dev)212{213	struct bochs_device *bochs = dev->dev_private;214	struct pci_dev *pdev = to_pci_dev(dev->dev);215	unsigned long addr, size, mem, ioaddr, iosize;216	u16 id;217 218	if (pdev->resource[2].flags & IORESOURCE_MEM) {219		/* mmio bar with vga and bochs registers present */220		if (pci_request_region(pdev, 2, "bochs-drm") != 0) {221			DRM_ERROR("Cannot request mmio region\n");222			return -EBUSY;223		}224		ioaddr = pci_resource_start(pdev, 2);225		iosize = pci_resource_len(pdev, 2);226		bochs->mmio = ioremap(ioaddr, iosize);227		if (bochs->mmio == NULL) {228			DRM_ERROR("Cannot map mmio region\n");229			return -ENOMEM;230		}231	} else {232		ioaddr = VBE_DISPI_IOPORT_INDEX;233		iosize = 2;234		if (!request_region(ioaddr, iosize, "bochs-drm")) {235			DRM_ERROR("Cannot request ioports\n");236			return -EBUSY;237		}238		bochs->ioports = 1;239	}240 241	id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID);242	mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K)243		* 64 * 1024;244	if ((id & 0xfff0) != VBE_DISPI_ID0) {245		DRM_ERROR("ID mismatch\n");246		return -ENODEV;247	}248 249	if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0)250		return -ENODEV;251	addr = pci_resource_start(pdev, 0);252	size = pci_resource_len(pdev, 0);253	if (addr == 0)254		return -ENODEV;255	if (size != mem) {256		DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n",257			size, mem);258		size = min(size, mem);259	}260 261	if (pci_request_region(pdev, 0, "bochs-drm") != 0)262		DRM_WARN("Cannot request framebuffer, boot fb still active?\n");263 264	bochs->fb_map = ioremap(addr, size);265	if (bochs->fb_map == NULL) {266		DRM_ERROR("Cannot map framebuffer\n");267		return -ENOMEM;268	}269	bochs->fb_base = addr;270	bochs->fb_size = size;271 272	DRM_INFO("Found bochs VGA, ID 0x%x.\n", id);273	DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n",274		 size / 1024, addr,275		 bochs->ioports ? "ioports" : "mmio",276		 ioaddr);277 278	if (bochs->mmio && pdev->revision >= 2) {279		bochs->qext_size = readl(bochs->mmio + 0x600);280		if (bochs->qext_size < 4 || bochs->qext_size > iosize) {281			bochs->qext_size = 0;282			goto noext;283		}284		DRM_DEBUG("Found qemu ext regs, size %ld\n",285			  bochs->qext_size);286		bochs_hw_set_native_endian(bochs);287	}288 289noext:290	return 0;291}292 293static void bochs_hw_fini(struct drm_device *dev)294{295	struct bochs_device *bochs = dev->dev_private;296 297	/* TODO: shot down existing vram mappings */298 299	if (bochs->mmio)300		iounmap(bochs->mmio);301	if (bochs->ioports)302		release_region(VBE_DISPI_IOPORT_INDEX, 2);303	if (bochs->fb_map)304		iounmap(bochs->fb_map);305	pci_release_regions(to_pci_dev(dev->dev));306	drm_edid_free(bochs->drm_edid);307}308 309static void bochs_hw_blank(struct bochs_device *bochs, bool blank)310{311	DRM_DEBUG_DRIVER("hw_blank %d\n", blank);312	/* enable color bit (so VGA_IS1_RC access works) */313	bochs_vga_writeb(bochs, VGA_MIS_W, VGA_MIS_COLOR);314	/* discard ar_flip_flop */315	(void)bochs_vga_readb(bochs, VGA_IS1_RC);316	/* blank or unblank; we need only update index and set 0x20 */317	bochs_vga_writeb(bochs, VGA_ATT_W, blank ? 0 : 0x20);318}319 320static void bochs_hw_setmode(struct bochs_device *bochs, struct drm_display_mode *mode)321{322	int idx;323 324	if (!drm_dev_enter(bochs->dev, &idx))325		return;326 327	bochs->xres = mode->hdisplay;328	bochs->yres = mode->vdisplay;329	bochs->bpp = 32;330	bochs->stride = mode->hdisplay * (bochs->bpp / 8);331	bochs->yres_virtual = bochs->fb_size / bochs->stride;332 333	DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n",334			 bochs->xres, bochs->yres, bochs->bpp,335			 bochs->yres_virtual);336 337	bochs_hw_blank(bochs, false);338 339	bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,      0);340	bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);341	bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);342	bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES,        bochs->yres);343	bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK,        0);344	bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH,  bochs->xres);345	bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT,346			  bochs->yres_virtual);347	bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET,    0);348	bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET,    0);349 350	bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,351			  VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);352 353	drm_dev_exit(idx);354}355 356static void bochs_hw_setformat(struct bochs_device *bochs, const struct drm_format_info *format)357{358	int idx;359 360	if (!drm_dev_enter(bochs->dev, &idx))361		return;362 363	DRM_DEBUG_DRIVER("format %c%c%c%c\n",364			 (format->format >>  0) & 0xff,365			 (format->format >>  8) & 0xff,366			 (format->format >> 16) & 0xff,367			 (format->format >> 24) & 0xff);368 369	switch (format->format) {370	case DRM_FORMAT_XRGB8888:371		bochs_hw_set_little_endian(bochs);372		break;373	case DRM_FORMAT_BGRX8888:374		bochs_hw_set_big_endian(bochs);375		break;376	default:377		/* should not happen */378		DRM_ERROR("%s: Huh? Got framebuffer format 0x%x",379			  __func__, format->format);380		break;381	}382 383	drm_dev_exit(idx);384}385 386static void bochs_hw_setbase(struct bochs_device *bochs, int x, int y, int stride, u64 addr)387{388	unsigned long offset;389	unsigned int vx, vy, vwidth, idx;390 391	if (!drm_dev_enter(bochs->dev, &idx))392		return;393 394	bochs->stride = stride;395	offset = (unsigned long)addr +396		y * bochs->stride +397		x * (bochs->bpp / 8);398	vy = offset / bochs->stride;399	vx = (offset % bochs->stride) * 8 / bochs->bpp;400	vwidth = stride * 8 / bochs->bpp;401 402	DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n",403			 x, y, addr, offset, vx, vy);404	bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, vwidth);405	bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);406	bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);407 408	drm_dev_exit(idx);409}410 411/* ---------------------------------------------------------------------- */412 413static const uint32_t bochs_formats[] = {414	DRM_FORMAT_XRGB8888,415	DRM_FORMAT_BGRX8888,416};417 418static void bochs_plane_update(struct bochs_device *bochs, struct drm_plane_state *state)419{420	struct drm_gem_vram_object *gbo;421	s64 gpu_addr;422 423	if (!state->fb || !bochs->stride)424		return;425 426	gbo = drm_gem_vram_of_gem(state->fb->obj[0]);427	gpu_addr = drm_gem_vram_offset(gbo);428	if (WARN_ON_ONCE(gpu_addr < 0))429		return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */430 431	bochs_hw_setbase(bochs,432			 state->crtc_x,433			 state->crtc_y,434			 state->fb->pitches[0],435			 state->fb->offsets[0] + gpu_addr);436	bochs_hw_setformat(bochs, state->fb->format);437}438 439static void bochs_pipe_enable(struct drm_simple_display_pipe *pipe,440			      struct drm_crtc_state *crtc_state,441			      struct drm_plane_state *plane_state)442{443	struct bochs_device *bochs = pipe->crtc.dev->dev_private;444 445	bochs_hw_setmode(bochs, &crtc_state->mode);446	bochs_plane_update(bochs, plane_state);447}448 449static void bochs_pipe_disable(struct drm_simple_display_pipe *pipe)450{451	struct bochs_device *bochs = pipe->crtc.dev->dev_private;452 453	bochs_hw_blank(bochs, true);454}455 456static void bochs_pipe_update(struct drm_simple_display_pipe *pipe,457			      struct drm_plane_state *old_state)458{459	struct bochs_device *bochs = pipe->crtc.dev->dev_private;460 461	bochs_plane_update(bochs, pipe->plane.state);462}463 464static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = {465	.enable	    = bochs_pipe_enable,466	.disable    = bochs_pipe_disable,467	.update	    = bochs_pipe_update,468	.prepare_fb = drm_gem_vram_simple_display_pipe_prepare_fb,469	.cleanup_fb = drm_gem_vram_simple_display_pipe_cleanup_fb,470};471 472static int bochs_connector_get_modes(struct drm_connector *connector)473{474	int count;475 476	count = drm_edid_connector_add_modes(connector);477 478	if (!count) {479		count = drm_add_modes_noedid(connector, 8192, 8192);480		drm_set_preferred_mode(connector, defx, defy);481	}482	return count;483}484 485static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {486	.get_modes = bochs_connector_get_modes,487};488 489static const struct drm_connector_funcs bochs_connector_connector_funcs = {490	.fill_modes = drm_helper_probe_single_connector_modes,491	.destroy = drm_connector_cleanup,492	.reset = drm_atomic_helper_connector_reset,493	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,494	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,495};496 497static void bochs_connector_init(struct drm_device *dev)498{499	struct bochs_device *bochs = dev->dev_private;500	struct drm_connector *connector = &bochs->connector;501 502	drm_connector_init(dev, connector, &bochs_connector_connector_funcs,503			   DRM_MODE_CONNECTOR_VIRTUAL);504	drm_connector_helper_add(connector, &bochs_connector_connector_helper_funcs);505 506	bochs_hw_load_edid(bochs);507	if (bochs->drm_edid) {508		DRM_INFO("Found EDID data blob.\n");509		drm_connector_attach_edid_property(connector);510		drm_edid_connector_update(&bochs->connector, bochs->drm_edid);511	}512}513 514static struct drm_framebuffer *515bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,516		    const struct drm_mode_fb_cmd2 *mode_cmd)517{518	if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 &&519	    mode_cmd->pixel_format != DRM_FORMAT_BGRX8888)520		return ERR_PTR(-EINVAL);521 522	return drm_gem_fb_create(dev, file, mode_cmd);523}524 525static const struct drm_mode_config_funcs bochs_mode_funcs = {526	.fb_create = bochs_gem_fb_create,527	.mode_valid = drm_vram_helper_mode_valid,528	.atomic_check = drm_atomic_helper_check,529	.atomic_commit = drm_atomic_helper_commit,530};531 532static int bochs_kms_init(struct bochs_device *bochs)533{534	int ret;535 536	ret = drmm_mode_config_init(bochs->dev);537	if (ret)538		return ret;539 540	bochs->dev->mode_config.max_width = 8192;541	bochs->dev->mode_config.max_height = 8192;542 543	bochs->dev->mode_config.preferred_depth = 24;544	bochs->dev->mode_config.prefer_shadow = 0;545	bochs->dev->mode_config.quirk_addfb_prefer_host_byte_order = true;546 547	bochs->dev->mode_config.funcs = &bochs_mode_funcs;548 549	bochs_connector_init(bochs->dev);550	drm_simple_display_pipe_init(bochs->dev,551				     &bochs->pipe,552				     &bochs_pipe_funcs,553				     bochs_formats,554				     ARRAY_SIZE(bochs_formats),555				     NULL,556				     &bochs->connector);557 558	drm_mode_config_reset(bochs->dev);559 560	return 0;561}562 563/* ---------------------------------------------------------------------- */564/* drm interface                                                          */565 566static int bochs_load(struct drm_device *dev)567{568	struct bochs_device *bochs;569	int ret;570 571	bochs = drmm_kzalloc(dev, sizeof(*bochs), GFP_KERNEL);572	if (bochs == NULL)573		return -ENOMEM;574	dev->dev_private = bochs;575	bochs->dev = dev;576 577	ret = bochs_hw_init(dev);578	if (ret)579		return ret;580 581	ret = drmm_vram_helper_init(dev, bochs->fb_base, bochs->fb_size);582	if (ret)583		goto err_hw_fini;584 585	ret = bochs_kms_init(bochs);586	if (ret)587		goto err_hw_fini;588 589	return 0;590 591err_hw_fini:592	bochs_hw_fini(dev);593	return ret;594}595 596DEFINE_DRM_GEM_FOPS(bochs_fops);597 598static const struct drm_driver bochs_driver = {599	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,600	.fops			= &bochs_fops,601	.name			= "bochs-drm",602	.desc			= "bochs dispi vga interface (qemu stdvga)",603	.date			= "20130925",604	.major			= 1,605	.minor			= 0,606	DRM_GEM_VRAM_DRIVER,607};608 609/* ---------------------------------------------------------------------- */610/* pm interface                                                           */611 612#ifdef CONFIG_PM_SLEEP613static int bochs_pm_suspend(struct device *dev)614{615	struct drm_device *drm_dev = dev_get_drvdata(dev);616 617	return drm_mode_config_helper_suspend(drm_dev);618}619 620static int bochs_pm_resume(struct device *dev)621{622	struct drm_device *drm_dev = dev_get_drvdata(dev);623 624	return drm_mode_config_helper_resume(drm_dev);625}626#endif627 628static const struct dev_pm_ops bochs_pm_ops = {629	SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,630				bochs_pm_resume)631};632 633/* ---------------------------------------------------------------------- */634/* pci interface                                                          */635 636static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)637{638	struct drm_device *dev;639	unsigned long fbsize;640	int ret;641 642	fbsize = pci_resource_len(pdev, 0);643	if (fbsize < 4 * 1024 * 1024) {644		DRM_ERROR("less than 4 MB video memory, ignoring device\n");645		return -ENOMEM;646	}647 648	ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &bochs_driver);649	if (ret)650		return ret;651 652	dev = drm_dev_alloc(&bochs_driver, &pdev->dev);653	if (IS_ERR(dev))654		return PTR_ERR(dev);655 656	ret = pcim_enable_device(pdev);657	if (ret)658		goto err_free_dev;659 660	pci_set_drvdata(pdev, dev);661 662	ret = bochs_load(dev);663	if (ret)664		goto err_free_dev;665 666	ret = drm_dev_register(dev, 0);667	if (ret)668		goto err_hw_fini;669 670	drm_fbdev_ttm_setup(dev, 32);671	return ret;672 673err_hw_fini:674	bochs_hw_fini(dev);675err_free_dev:676	drm_dev_put(dev);677	return ret;678}679 680static void bochs_pci_remove(struct pci_dev *pdev)681{682	struct drm_device *dev = pci_get_drvdata(pdev);683 684	drm_dev_unplug(dev);685	drm_atomic_helper_shutdown(dev);686	bochs_hw_fini(dev);687	drm_dev_put(dev);688}689 690static void bochs_pci_shutdown(struct pci_dev *pdev)691{692	drm_atomic_helper_shutdown(pci_get_drvdata(pdev));693}694 695static const struct pci_device_id bochs_pci_tbl[] = {696	{697		.vendor      = 0x1234,698		.device      = 0x1111,699		.subvendor   = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,700		.subdevice   = PCI_SUBDEVICE_ID_QEMU,701		.driver_data = BOCHS_QEMU_STDVGA,702	},703	{704		.vendor      = 0x1234,705		.device      = 0x1111,706		.subvendor   = PCI_ANY_ID,707		.subdevice   = PCI_ANY_ID,708		.driver_data = BOCHS_UNKNOWN,709	},710	{711		.vendor      = 0x4321,712		.device      = 0x1111,713		.subvendor   = PCI_ANY_ID,714		.subdevice   = PCI_ANY_ID,715		.driver_data = BOCHS_SIMICS,716	},717	{ /* end of list */ }718};719 720static struct pci_driver bochs_pci_driver = {721	.name =		"bochs-drm",722	.id_table =	bochs_pci_tbl,723	.probe =	bochs_pci_probe,724	.remove =	bochs_pci_remove,725	.shutdown =	bochs_pci_shutdown,726	.driver.pm =    &bochs_pm_ops,727};728 729/* ---------------------------------------------------------------------- */730/* module init/exit                                                       */731 732drm_module_pci_driver_if_modeset(bochs_pci_driver, bochs_modeset);733 734MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);735MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");736MODULE_DESCRIPTION("DRM Support for bochs dispi vga interface (qemu stdvga)");737MODULE_LICENSE("GPL");738