Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
Loading...
Note: File does not exist in v6.13.7.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 */
  4
  5#include <linux/module.h>
  6#include <linux/pci.h>
  7
  8#include <drm/drm_drv.h>
  9#include <drm/drm_atomic_helper.h>
 10
 11#include "bochs.h"
 12
 13static int bochs_modeset = -1;
 14module_param_named(modeset, bochs_modeset, int, 0444);
 15MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");
 16
 17/* ---------------------------------------------------------------------- */
 18/* drm interface                                                          */
 19
 20static void bochs_unload(struct drm_device *dev)
 21{
 22	struct bochs_device *bochs = dev->dev_private;
 23
 24	bochs_kms_fini(bochs);
 25	bochs_mm_fini(bochs);
 26	bochs_hw_fini(dev);
 27	kfree(bochs);
 28	dev->dev_private = NULL;
 29}
 30
 31static int bochs_load(struct drm_device *dev)
 32{
 33	struct bochs_device *bochs;
 34	int ret;
 35
 36	bochs = kzalloc(sizeof(*bochs), GFP_KERNEL);
 37	if (bochs == NULL)
 38		return -ENOMEM;
 39	dev->dev_private = bochs;
 40	bochs->dev = dev;
 41
 42	ret = bochs_hw_init(dev);
 43	if (ret)
 44		goto err;
 45
 46	ret = bochs_mm_init(bochs);
 47	if (ret)
 48		goto err;
 49
 50	ret = bochs_kms_init(bochs);
 51	if (ret)
 52		goto err;
 53
 54	return 0;
 55
 56err:
 57	bochs_unload(dev);
 58	return ret;
 59}
 60
 61static const struct file_operations bochs_fops = {
 62	.owner		= THIS_MODULE,
 63	DRM_VRAM_MM_FILE_OPERATIONS
 64};
 65
 66static struct drm_driver bochs_driver = {
 67	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 68	.fops			= &bochs_fops,
 69	.name			= "bochs-drm",
 70	.desc			= "bochs dispi vga interface (qemu stdvga)",
 71	.date			= "20130925",
 72	.major			= 1,
 73	.minor			= 0,
 74	DRM_GEM_VRAM_DRIVER,
 75};
 76
 77/* ---------------------------------------------------------------------- */
 78/* pm interface                                                           */
 79
 80#ifdef CONFIG_PM_SLEEP
 81static int bochs_pm_suspend(struct device *dev)
 82{
 83	struct drm_device *drm_dev = dev_get_drvdata(dev);
 84
 85	return drm_mode_config_helper_suspend(drm_dev);
 86}
 87
 88static int bochs_pm_resume(struct device *dev)
 89{
 90	struct drm_device *drm_dev = dev_get_drvdata(dev);
 91
 92	return drm_mode_config_helper_resume(drm_dev);
 93}
 94#endif
 95
 96static const struct dev_pm_ops bochs_pm_ops = {
 97	SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
 98				bochs_pm_resume)
 99};
100
101/* ---------------------------------------------------------------------- */
102/* pci interface                                                          */
103
104static int bochs_pci_probe(struct pci_dev *pdev,
105			   const struct pci_device_id *ent)
106{
107	struct drm_device *dev;
108	unsigned long fbsize;
109	int ret;
110
111	fbsize = pci_resource_len(pdev, 0);
112	if (fbsize < 4 * 1024 * 1024) {
113		DRM_ERROR("less than 4 MB video memory, ignoring device\n");
114		return -ENOMEM;
115	}
116
117	ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "bochsdrmfb");
118	if (ret)
119		return ret;
120
121	dev = drm_dev_alloc(&bochs_driver, &pdev->dev);
122	if (IS_ERR(dev))
123		return PTR_ERR(dev);
124
125	ret = pci_enable_device(pdev);
126	if (ret)
127		goto err_free_dev;
128
129	dev->pdev = pdev;
130	pci_set_drvdata(pdev, dev);
131
132	ret = bochs_load(dev);
133	if (ret)
134		goto err_free_dev;
135
136	ret = drm_dev_register(dev, 0);
137	if (ret)
138		goto err_unload;
139
140	drm_fbdev_generic_setup(dev, 32);
141	return ret;
142
143err_unload:
144	bochs_unload(dev);
145err_free_dev:
146	drm_dev_put(dev);
147	return ret;
148}
149
150static void bochs_pci_remove(struct pci_dev *pdev)
151{
152	struct drm_device *dev = pci_get_drvdata(pdev);
153
154	drm_atomic_helper_shutdown(dev);
155	drm_dev_unregister(dev);
156	bochs_unload(dev);
157	drm_dev_put(dev);
158}
159
160static const struct pci_device_id bochs_pci_tbl[] = {
161	{
162		.vendor      = 0x1234,
163		.device      = 0x1111,
164		.subvendor   = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
165		.subdevice   = PCI_SUBDEVICE_ID_QEMU,
166		.driver_data = BOCHS_QEMU_STDVGA,
167	},
168	{
169		.vendor      = 0x1234,
170		.device      = 0x1111,
171		.subvendor   = PCI_ANY_ID,
172		.subdevice   = PCI_ANY_ID,
173		.driver_data = BOCHS_UNKNOWN,
174	},
175	{ /* end of list */ }
176};
177
178static struct pci_driver bochs_pci_driver = {
179	.name =		"bochs-drm",
180	.id_table =	bochs_pci_tbl,
181	.probe =	bochs_pci_probe,
182	.remove =	bochs_pci_remove,
183	.driver.pm =    &bochs_pm_ops,
184};
185
186/* ---------------------------------------------------------------------- */
187/* module init/exit                                                       */
188
189static int __init bochs_init(void)
190{
191	if (vgacon_text_force() && bochs_modeset == -1)
192		return -EINVAL;
193
194	if (bochs_modeset == 0)
195		return -EINVAL;
196
197	return pci_register_driver(&bochs_pci_driver);
198}
199
200static void __exit bochs_exit(void)
201{
202	pci_unregister_driver(&bochs_pci_driver);
203}
204
205module_init(bochs_init);
206module_exit(bochs_exit);
207
208MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
209MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
210MODULE_LICENSE("GPL");