1145132Sanholt/*-
2145132Sanholt * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
3145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4145132Sanholt * All Rights Reserved.
5145132Sanholt *
6145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
7145132Sanholt * copy of this software and associated documentation files (the "Software"),
8145132Sanholt * to deal in the Software without restriction, including without limitation
9145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the
11145132Sanholt * Software is furnished to do so, subject to the following conditions:
12145132Sanholt *
13145132Sanholt * The above copyright notice and this permission notice (including the next
14145132Sanholt * paragraph) shall be included in all copies or substantial portions of the
15145132Sanholt * Software.
16145132Sanholt *
17145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20145132Sanholt * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23145132Sanholt * OTHER DEALINGS IN THE SOFTWARE.
24145132Sanholt *
25145132Sanholt * Authors:
26145132Sanholt *    Rickard E. (Rik) Faith <faith@valinux.com>
27145132Sanholt *    Gareth Hughes <gareth@valinux.com>
28145132Sanholt *
29145132Sanholt */
30145132Sanholt
31152909Sanholt#include <sys/cdefs.h>
32152909Sanholt__FBSDID("$FreeBSD: releng/10.2/sys/dev/drm/drm_drv.c 215367 2010-11-16 03:43:06Z nwhitehorn $");
33152909Sanholt
34182080Srnoland/** @file drm_drv.c
35182080Srnoland * The catch-all file for DRM device support, including module setup/teardown,
36182080Srnoland * open/close, and ioctl dispatch.
37182080Srnoland */
38182080Srnoland
39182080Srnoland
40182080Srnoland#include <sys/limits.h>
41145132Sanholt#include "dev/drm/drmP.h"
42145132Sanholt#include "dev/drm/drm.h"
43152909Sanholt#include "dev/drm/drm_sarea.h"
44145132Sanholt
45153013Sanholt#ifdef DRM_DEBUG_DEFAULT_ON
46153013Sanholtint drm_debug_flag = 1;
47153013Sanholt#else
48145132Sanholtint drm_debug_flag = 0;
49153013Sanholt#endif
50145132Sanholt
51182080Srnolandstatic int drm_load(struct drm_device *dev);
52182080Srnolandstatic void drm_unload(struct drm_device *dev);
53152909Sanholtstatic drm_pci_id_list_t *drm_find_description(int vendor, int device,
54152909Sanholt    drm_pci_id_list_t *idlist);
55145132Sanholt
56145132SanholtMODULE_VERSION(drm, 1);
57145132SanholtMODULE_DEPEND(drm, agp, 1, 1, 1);
58145132SanholtMODULE_DEPEND(drm, pci, 1, 1, 1);
59145132SanholtMODULE_DEPEND(drm, mem, 1, 1, 1);
60145132Sanholt
61145132Sanholtstatic drm_ioctl_desc_t		  drm_ioctls[256] = {
62182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
63182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
64182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
65182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
66182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
67182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
68182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
69182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
70145132Sanholt
71182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
72182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
73182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
74182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
75145132Sanholt
76182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
77182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
78145132Sanholt
79182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
80182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
81145132Sanholt
82189099Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
83182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
84182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
85182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
86182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
87182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
88182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
89145132Sanholt
90182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
91182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
92145132Sanholt
93182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
94182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
95189099Srnoland
96182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
97145132Sanholt
98189099Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
99189099Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
100182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
101182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
102182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
103182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma, DRM_AUTH),
104145132Sanholt
105182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
106145132Sanholt
107182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
108182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
109182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
110182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
111182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
112182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
113182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
114182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
115145132Sanholt
116182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
117182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
118182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
119182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
120182080Srnoland	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
121145132Sanholt};
122145132Sanholt
123145132Sanholtstatic struct cdevsw drm_cdevsw = {
124145132Sanholt	.d_version =	D_VERSION,
125145132Sanholt	.d_open =	drm_open,
126145132Sanholt	.d_read =	drm_read,
127145132Sanholt	.d_ioctl =	drm_ioctl,
128145132Sanholt	.d_poll =	drm_poll,
129145132Sanholt	.d_mmap =	drm_mmap,
130145132Sanholt	.d_name =	"drm",
131189053Srnoland	.d_flags =	D_TRACKCLOSE
132145132Sanholt};
133145132Sanholt
134191274Srnolandstatic int drm_msi = 1;	/* Enable by default. */
135189128SrnolandTUNABLE_INT("hw.drm.msi", &drm_msi);
136196466SrnolandSYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device");
137196466SrnolandSYSCTL_INT(_hw_drm, OID_AUTO, msi, CTLFLAG_RDTUN, &drm_msi, 1,
138196466Srnoland    "Enable MSI interrupts for drm devices");
139189128Srnoland
140189052Srnolandstatic struct drm_msi_blacklist_entry drm_msi_blacklist[] = {
141189052Srnoland	{0x8086, 0x2772}, /* Intel i945G	*/ \
142189052Srnoland	{0x8086, 0x27A2}, /* Intel i945GM	*/ \
143189052Srnoland	{0x8086, 0x27AE}, /* Intel i945GME	*/ \
144189052Srnoland	{0, 0}
145189052Srnoland};
146189052Srnoland
147189052Srnolandstatic int drm_msi_is_blacklisted(int vendor, int device)
148189052Srnoland{
149189052Srnoland	int i = 0;
150189052Srnoland
151189052Srnoland	for (i = 0; drm_msi_blacklist[i].vendor != 0; i++) {
152189052Srnoland		if ((drm_msi_blacklist[i].vendor == vendor) &&
153189052Srnoland		    (drm_msi_blacklist[i].device == device)) {
154189052Srnoland			return 1;
155189052Srnoland		}
156189052Srnoland	}
157189052Srnoland
158189052Srnoland	return 0;
159189052Srnoland}
160189052Srnoland
161189563Srnolandint drm_probe(device_t kdev, drm_pci_id_list_t *idlist)
162145132Sanholt{
163152909Sanholt	drm_pci_id_list_t *id_entry;
164145132Sanholt	int vendor, device;
165153579Sjhb#if __FreeBSD_version < 700010
166153033Sanholt	device_t realdev;
167145132Sanholt
168189563Srnoland	if (!strcmp(device_get_name(kdev), "drmsub"))
169189563Srnoland		realdev = device_get_parent(kdev);
170153033Sanholt	else
171189563Srnoland		realdev = kdev;
172153033Sanholt	vendor = pci_get_vendor(realdev);
173153033Sanholt	device = pci_get_device(realdev);
174153579Sjhb#else
175189563Srnoland	vendor = pci_get_vendor(kdev);
176189563Srnoland	device = pci_get_device(kdev);
177153579Sjhb#endif
178145132Sanholt
179189563Srnoland	if (pci_get_class(kdev) != PCIC_DISPLAY
180189563Srnoland	    || pci_get_subclass(kdev) != PCIS_DISPLAY_VGA)
181186299Srnoland		return ENXIO;
182186299Srnoland
183152909Sanholt	id_entry = drm_find_description(vendor, device, idlist);
184152909Sanholt	if (id_entry != NULL) {
185189915Srnoland		if (!device_get_desc(kdev)) {
186189915Srnoland			DRM_DEBUG("desc : %s\n", device_get_desc(kdev));
187189915Srnoland			device_set_desc(kdev, id_entry->name);
188189915Srnoland		}
189145132Sanholt		return 0;
190145132Sanholt	}
191145132Sanholt
192145132Sanholt	return ENXIO;
193145132Sanholt}
194145132Sanholt
195189563Srnolandint drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
196145132Sanholt{
197182080Srnoland	struct drm_device *dev;
198152909Sanholt	drm_pci_id_list_t *id_entry;
199189052Srnoland	int unit, msicount;
200152909Sanholt
201189563Srnoland	unit = device_get_unit(kdev);
202189563Srnoland	dev = device_get_softc(kdev);
203152909Sanholt
204153579Sjhb#if __FreeBSD_version < 700010
205189563Srnoland	if (!strcmp(device_get_name(kdev), "drmsub"))
206189563Srnoland		dev->device = device_get_parent(kdev);
207152909Sanholt	else
208189563Srnoland		dev->device = kdev;
209153579Sjhb#else
210189563Srnoland	dev->device = kdev;
211153579Sjhb#endif
212152909Sanholt	dev->devnode = make_dev(&drm_cdevsw,
213196465Srnoland			0,
214152909Sanholt			DRM_DEV_UID,
215152909Sanholt			DRM_DEV_GID,
216152909Sanholt			DRM_DEV_MODE,
217152909Sanholt			"dri/card%d", unit);
218196465Srnoland	dev->devnode->si_drv1 = dev;
219183573Srnoland
220189052Srnoland#if __FreeBSD_version >= 700053
221189052Srnoland	dev->pci_domain = pci_get_domain(dev->device);
222189052Srnoland#else
223189052Srnoland	dev->pci_domain = 0;
224189052Srnoland#endif
225189052Srnoland	dev->pci_bus = pci_get_bus(dev->device);
226189052Srnoland	dev->pci_slot = pci_get_slot(dev->device);
227189052Srnoland	dev->pci_func = pci_get_function(dev->device);
228189052Srnoland
229189052Srnoland	dev->pci_vendor = pci_get_vendor(dev->device);
230189052Srnoland	dev->pci_device = pci_get_device(dev->device);
231189052Srnoland
232191274Srnoland	if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) {
233191274Srnoland		if (drm_msi &&
234191274Srnoland		    !drm_msi_is_blacklisted(dev->pci_vendor, dev->pci_device)) {
235191274Srnoland			msicount = pci_msi_count(dev->device);
236191274Srnoland			DRM_DEBUG("MSI count = %d\n", msicount);
237191274Srnoland			if (msicount > 1)
238191274Srnoland				msicount = 1;
239189052Srnoland
240191274Srnoland			if (pci_alloc_msi(dev->device, &msicount) == 0) {
241191274Srnoland				DRM_INFO("MSI enabled %d message(s)\n",
242191274Srnoland				    msicount);
243191274Srnoland				dev->msi_enabled = 1;
244191274Srnoland				dev->irqrid = 1;
245191274Srnoland			}
246189052Srnoland		}
247189052Srnoland
248191274Srnoland		dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
249191274Srnoland		    &dev->irqrid, RF_SHAREABLE);
250191274Srnoland		if (!dev->irqr) {
251191274Srnoland			return ENOENT;
252191274Srnoland		}
253191274Srnoland
254191274Srnoland		dev->irq = (int) rman_get_start(dev->irqr);
255189052Srnoland	}
256189052Srnoland
257182080Srnoland	mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF);
258182080Srnoland	mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF);
259182080Srnoland	mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF);
260182080Srnoland	mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF);
261152909Sanholt
262189052Srnoland	id_entry = drm_find_description(dev->pci_vendor,
263189052Srnoland	    dev->pci_device, idlist);
264152909Sanholt	dev->id_entry = id_entry;
265152909Sanholt
266152909Sanholt	return drm_load(dev);
267145132Sanholt}
268145132Sanholt
269189563Srnolandint drm_detach(device_t kdev)
270145132Sanholt{
271189052Srnoland	struct drm_device *dev;
272189052Srnoland
273189563Srnoland	dev = device_get_softc(kdev);
274189052Srnoland
275189052Srnoland	drm_unload(dev);
276189052Srnoland
277194749Srnoland	if (dev->irqr) {
278194749Srnoland		bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
279194749Srnoland		    dev->irqr);
280189052Srnoland
281194749Srnoland		if (dev->msi_enabled) {
282194749Srnoland			pci_release_msi(dev->device);
283194749Srnoland			DRM_INFO("MSI released\n");
284194749Srnoland		}
285189052Srnoland	}
286189052Srnoland
287145132Sanholt	return 0;
288145132Sanholt}
289145132Sanholt
290145132Sanholt#ifndef DRM_DEV_NAME
291145132Sanholt#define DRM_DEV_NAME "drm"
292145132Sanholt#endif
293145132Sanholt
294145132Sanholtdevclass_t drm_devclass;
295145132Sanholt
296152909Sanholtdrm_pci_id_list_t *drm_find_description(int vendor, int device,
297152909Sanholt    drm_pci_id_list_t *idlist)
298152909Sanholt{
299145132Sanholt	int i = 0;
300145132Sanholt
301145132Sanholt	for (i = 0; idlist[i].vendor != 0; i++) {
302145132Sanholt		if ((idlist[i].vendor == vendor) &&
303189915Srnoland		    ((idlist[i].device == device) ||
304189915Srnoland		    (idlist[i].device == 0))) {
305152909Sanholt			return &idlist[i];
306145132Sanholt		}
307145132Sanholt	}
308145132Sanholt	return NULL;
309145132Sanholt}
310145132Sanholt
311182080Srnolandstatic int drm_firstopen(struct drm_device *dev)
312145132Sanholt{
313152909Sanholt	drm_local_map_t *map;
314145132Sanholt	int i;
315145132Sanholt
316145132Sanholt	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
317145132Sanholt
318152909Sanholt	/* prebuild the SAREA */
319152909Sanholt	i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
320183573Srnoland	    _DRM_CONTAINS_LOCK, &map);
321152909Sanholt	if (i != 0)
322152909Sanholt		return i;
323145132Sanholt
324183573Srnoland	if (dev->driver->firstopen)
325183573Srnoland		dev->driver->firstopen(dev);
326152909Sanholt
327145132Sanholt	dev->buf_use = 0;
328145132Sanholt
329183573Srnoland	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
330145132Sanholt		i = drm_dma_setup(dev);
331145132Sanholt		if (i != 0)
332145132Sanholt			return i;
333145132Sanholt	}
334145132Sanholt
335183573Srnoland	for (i = 0; i < DRM_HASH_SIZE; i++) {
336145132Sanholt		dev->magiclist[i].head = NULL;
337145132Sanholt		dev->magiclist[i].tail = NULL;
338145132Sanholt	}
339145132Sanholt
340145132Sanholt	dev->lock.lock_queue = 0;
341145132Sanholt	dev->irq_enabled = 0;
342145132Sanholt	dev->context_flag = 0;
343145132Sanholt	dev->last_context = 0;
344145132Sanholt	dev->if_version = 0;
345145132Sanholt
346145132Sanholt	dev->buf_sigio = NULL;
347145132Sanholt
348183573Srnoland	DRM_DEBUG("\n");
349145132Sanholt
350145132Sanholt	return 0;
351145132Sanholt}
352145132Sanholt
353182080Srnolandstatic int drm_lastclose(struct drm_device *dev)
354145132Sanholt{
355145132Sanholt	drm_magic_entry_t *pt, *next;
356145132Sanholt	drm_local_map_t *map, *mapsave;
357145132Sanholt	int i;
358145132Sanholt
359145132Sanholt	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
360145132Sanholt
361183573Srnoland	DRM_DEBUG("\n");
362145132Sanholt
363183573Srnoland	if (dev->driver->lastclose != NULL)
364183573Srnoland		dev->driver->lastclose(dev);
365145132Sanholt
366145132Sanholt	if (dev->irq_enabled)
367145132Sanholt		drm_irq_uninstall(dev);
368145132Sanholt
369183573Srnoland	if (dev->unique) {
370183833Srnoland		free(dev->unique, DRM_MEM_DRIVER);
371145132Sanholt		dev->unique = NULL;
372145132Sanholt		dev->unique_len = 0;
373145132Sanholt	}
374183573Srnoland	/* Clear pid list */
375183573Srnoland	for (i = 0; i < DRM_HASH_SIZE; i++) {
376183573Srnoland		for (pt = dev->magiclist[i].head; pt; pt = next) {
377145132Sanholt			next = pt->next;
378183833Srnoland			free(pt, DRM_MEM_MAGIC);
379145132Sanholt		}
380145132Sanholt		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
381145132Sanholt	}
382145132Sanholt
383182467Srnoland	DRM_UNLOCK();
384182080Srnoland	drm_drawable_free_all(dev);
385182467Srnoland	DRM_LOCK();
386182080Srnoland
387183573Srnoland	/* Clear AGP information */
388183573Srnoland	if (dev->agp) {
389145132Sanholt		drm_agp_mem_t *entry;
390145132Sanholt		drm_agp_mem_t *nexte;
391145132Sanholt
392152909Sanholt		/* Remove AGP resources, but leave dev->agp intact until
393152909Sanholt		 * drm_unload is called.
394152909Sanholt		 */
395183573Srnoland		for (entry = dev->agp->memory; entry; entry = nexte) {
396145132Sanholt			nexte = entry->next;
397183573Srnoland			if (entry->bound)
398145132Sanholt				drm_agp_unbind_memory(entry->handle);
399145132Sanholt			drm_agp_free_memory(entry->handle);
400183833Srnoland			free(entry, DRM_MEM_AGPLISTS);
401145132Sanholt		}
402145132Sanholt		dev->agp->memory = NULL;
403145132Sanholt
404145132Sanholt		if (dev->agp->acquired)
405152909Sanholt			drm_agp_release(dev);
406145132Sanholt
407145132Sanholt		dev->agp->acquired = 0;
408145132Sanholt		dev->agp->enabled  = 0;
409145132Sanholt	}
410145132Sanholt	if (dev->sg != NULL) {
411145132Sanholt		drm_sg_cleanup(dev->sg);
412145132Sanholt		dev->sg = NULL;
413145132Sanholt	}
414145132Sanholt
415145132Sanholt	TAILQ_FOREACH_SAFE(map, &dev->maplist, link, mapsave) {
416182080Srnoland		if (!(map->flags & _DRM_DRIVER))
417182080Srnoland			drm_rmmap(dev, map);
418145132Sanholt	}
419145132Sanholt
420145132Sanholt	drm_dma_takedown(dev);
421183573Srnoland	if (dev->lock.hw_lock) {
422145132Sanholt		dev->lock.hw_lock = NULL; /* SHM removed */
423182080Srnoland		dev->lock.file_priv = NULL;
424145132Sanholt		DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
425145132Sanholt	}
426145132Sanholt
427145132Sanholt	return 0;
428145132Sanholt}
429145132Sanholt
430182080Srnolandstatic int drm_load(struct drm_device *dev)
431145132Sanholt{
432182080Srnoland	int i, retcode;
433152909Sanholt
434183573Srnoland	DRM_DEBUG("\n");
435145132Sanholt
436145132Sanholt	TAILQ_INIT(&dev->maplist);
437207066Srnoland	dev->map_unrhdr = new_unrhdr(1, ((1 << DRM_MAP_HANDLE_BITS) - 1), NULL);
438207066Srnoland	if (dev->map_unrhdr == NULL) {
439207066Srnoland		DRM_ERROR("Couldn't allocate map number allocator\n");
440207066Srnoland		return EINVAL;
441207066Srnoland	}
442145132Sanholt
443207066Srnoland
444145132Sanholt	drm_mem_init();
445145132Sanholt	drm_sysctl_init(dev);
446145132Sanholt	TAILQ_INIT(&dev->files);
447145132Sanholt
448182080Srnoland	dev->counters  = 6;
449182080Srnoland	dev->types[0]  = _DRM_STAT_LOCK;
450182080Srnoland	dev->types[1]  = _DRM_STAT_OPENS;
451182080Srnoland	dev->types[2]  = _DRM_STAT_CLOSES;
452182080Srnoland	dev->types[3]  = _DRM_STAT_IOCTLS;
453182080Srnoland	dev->types[4]  = _DRM_STAT_LOCKS;
454182080Srnoland	dev->types[5]  = _DRM_STAT_UNLOCKS;
455182080Srnoland
456183573Srnoland	for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
457183573Srnoland		atomic_set(&dev->counts[i], 0);
458182080Srnoland
459183573Srnoland	if (dev->driver->load != NULL) {
460152909Sanholt		DRM_LOCK();
461182080Srnoland		/* Shared code returns -errno. */
462183573Srnoland		retcode = -dev->driver->load(dev,
463182080Srnoland		    dev->id_entry->driver_private);
464182080Srnoland		if (pci_enable_busmaster(dev->device))
465182080Srnoland			DRM_ERROR("Request to enable bus-master failed.\n");
466152909Sanholt		DRM_UNLOCK();
467145132Sanholt		if (retcode != 0)
468145132Sanholt			goto error;
469145132Sanholt	}
470145132Sanholt
471183573Srnoland	if (drm_core_has_AGP(dev)) {
472145132Sanholt		if (drm_device_is_agp(dev))
473145132Sanholt			dev->agp = drm_agp_init();
474183573Srnoland		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) &&
475183573Srnoland		    dev->agp == NULL) {
476145132Sanholt			DRM_ERROR("Card isn't AGP, or couldn't initialize "
477145132Sanholt			    "AGP.\n");
478182080Srnoland			retcode = ENOMEM;
479145132Sanholt			goto error;
480145132Sanholt		}
481215367Snwhitehorn		if (dev->agp != NULL && dev->agp->info.ai_aperture_base != 0) {
482145132Sanholt			if (drm_mtrr_add(dev->agp->info.ai_aperture_base,
483145132Sanholt			    dev->agp->info.ai_aperture_size, DRM_MTRR_WC) == 0)
484145132Sanholt				dev->agp->mtrr = 1;
485145132Sanholt		}
486145132Sanholt	}
487145132Sanholt
488145132Sanholt	retcode = drm_ctxbitmap_init(dev);
489145132Sanholt	if (retcode != 0) {
490145132Sanholt		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
491145132Sanholt		goto error;
492145132Sanholt	}
493182080Srnoland
494182080Srnoland	dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL);
495182080Srnoland	if (dev->drw_unrhdr == NULL) {
496182080Srnoland		DRM_ERROR("Couldn't allocate drawable number allocator\n");
497182080Srnoland		goto error;
498182080Srnoland	}
499182080Srnoland
500152909Sanholt	DRM_INFO("Initialized %s %d.%d.%d %s\n",
501183573Srnoland	    dev->driver->name,
502183573Srnoland	    dev->driver->major,
503183573Srnoland	    dev->driver->minor,
504183573Srnoland	    dev->driver->patchlevel,
505183573Srnoland	    dev->driver->date);
506145132Sanholt
507145132Sanholt	return 0;
508145132Sanholt
509145132Sanholterror:
510145132Sanholt	drm_sysctl_cleanup(dev);
511145132Sanholt	DRM_LOCK();
512152909Sanholt	drm_lastclose(dev);
513145132Sanholt	DRM_UNLOCK();
514145132Sanholt	destroy_dev(dev->devnode);
515183573Srnoland
516182080Srnoland	mtx_destroy(&dev->drw_lock);
517182080Srnoland	mtx_destroy(&dev->vbl_lock);
518182080Srnoland	mtx_destroy(&dev->irq_lock);
519145132Sanholt	mtx_destroy(&dev->dev_lock);
520183573Srnoland
521145132Sanholt	return retcode;
522145132Sanholt}
523145132Sanholt
524182080Srnolandstatic void drm_unload(struct drm_device *dev)
525145132Sanholt{
526152909Sanholt	int i;
527145132Sanholt
528183573Srnoland	DRM_DEBUG("\n");
529145132Sanholt
530145132Sanholt	drm_sysctl_cleanup(dev);
531145132Sanholt	destroy_dev(dev->devnode);
532145132Sanholt
533145132Sanholt	drm_ctxbitmap_cleanup(dev);
534145132Sanholt
535145132Sanholt	if (dev->agp && dev->agp->mtrr) {
536145132Sanholt		int __unused retcode;
537145132Sanholt
538152909Sanholt		retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base,
539145132Sanholt		    dev->agp->info.ai_aperture_size, DRM_MTRR_WC);
540145132Sanholt		DRM_DEBUG("mtrr_del = %d", retcode);
541145132Sanholt	}
542145132Sanholt
543189130Srnoland	drm_vblank_cleanup(dev);
544189130Srnoland
545145132Sanholt	DRM_LOCK();
546152909Sanholt	drm_lastclose(dev);
547145132Sanholt	DRM_UNLOCK();
548145132Sanholt
549152909Sanholt	/* Clean up PCI resources allocated by drm_bufs.c.  We're not really
550152909Sanholt	 * worried about resource consumption while the DRM is inactive (between
551152909Sanholt	 * lastclose and firstopen or unload) because these aren't actually
552152909Sanholt	 * taking up KVA, just keeping the PCI resource allocated.
553152909Sanholt	 */
554152909Sanholt	for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
555152909Sanholt		if (dev->pcir[i] == NULL)
556152909Sanholt			continue;
557152909Sanholt		bus_release_resource(dev->device, SYS_RES_MEMORY,
558152909Sanholt		    dev->pcirid[i], dev->pcir[i]);
559152909Sanholt		dev->pcir[i] = NULL;
560145132Sanholt	}
561145132Sanholt
562183573Srnoland	if (dev->agp) {
563183833Srnoland		free(dev->agp, DRM_MEM_AGPLISTS);
564145132Sanholt		dev->agp = NULL;
565145132Sanholt	}
566145132Sanholt
567183573Srnoland	if (dev->driver->unload != NULL) {
568182468Srnoland		DRM_LOCK();
569183573Srnoland		dev->driver->unload(dev);
570182468Srnoland		DRM_UNLOCK();
571182468Srnoland	}
572145132Sanholt
573182080Srnoland	delete_unrhdr(dev->drw_unrhdr);
574207066Srnoland	delete_unrhdr(dev->map_unrhdr);
575182080Srnoland
576145132Sanholt	drm_mem_uninit();
577182080Srnoland
578182080Srnoland	if (pci_disable_busmaster(dev->device))
579182080Srnoland		DRM_ERROR("Request to disable bus-master failed.\n");
580182080Srnoland
581182080Srnoland	mtx_destroy(&dev->drw_lock);
582182080Srnoland	mtx_destroy(&dev->vbl_lock);
583182080Srnoland	mtx_destroy(&dev->irq_lock);
584145132Sanholt	mtx_destroy(&dev->dev_lock);
585145132Sanholt}
586145132Sanholt
587182080Srnolandint drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
588145132Sanholt{
589183573Srnoland	struct drm_version *version = data;
590145132Sanholt	int len;
591145132Sanholt
592145132Sanholt#define DRM_COPY( name, value )						\
593145132Sanholt	len = strlen( value );						\
594145132Sanholt	if ( len > name##_len ) len = name##_len;			\
595145132Sanholt	name##_len = strlen( value );					\
596145132Sanholt	if ( len && name ) {						\
597145132Sanholt		if ( DRM_COPY_TO_USER( name, value, len ) )		\
598182080Srnoland			return EFAULT;				\
599145132Sanholt	}
600145132Sanholt
601183573Srnoland	version->version_major		= dev->driver->major;
602183573Srnoland	version->version_minor		= dev->driver->minor;
603183573Srnoland	version->version_patchlevel	= dev->driver->patchlevel;
604145132Sanholt
605183573Srnoland	DRM_COPY(version->name, dev->driver->name);
606183573Srnoland	DRM_COPY(version->date, dev->driver->date);
607183573Srnoland	DRM_COPY(version->desc, dev->driver->desc);
608145132Sanholt
609145132Sanholt	return 0;
610145132Sanholt}
611145132Sanholt
612145132Sanholtint drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p)
613145132Sanholt{
614182080Srnoland	struct drm_device *dev = NULL;
615145132Sanholt	int retcode = 0;
616145132Sanholt
617196465Srnoland	dev = kdev->si_drv1;
618145132Sanholt
619183573Srnoland	DRM_DEBUG("open_count = %d\n", dev->open_count);
620145132Sanholt
621145132Sanholt	retcode = drm_open_helper(kdev, flags, fmt, p, dev);
622145132Sanholt
623183573Srnoland	if (!retcode) {
624183573Srnoland		atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
625145132Sanholt		DRM_LOCK();
626145132Sanholt		device_busy(dev->device);
627183573Srnoland		if (!dev->open_count++)
628152909Sanholt			retcode = drm_firstopen(dev);
629145132Sanholt		DRM_UNLOCK();
630145132Sanholt	}
631145132Sanholt
632145132Sanholt	return retcode;
633145132Sanholt}
634145132Sanholt
635183573Srnolandvoid drm_close(void *data)
636145132Sanholt{
637183573Srnoland	struct drm_file *file_priv = data;
638183573Srnoland	struct drm_device *dev = file_priv->dev;
639145132Sanholt	int retcode = 0;
640182080Srnoland
641183573Srnoland	DRM_DEBUG("open_count = %d\n", dev->open_count);
642145132Sanholt
643145132Sanholt	DRM_LOCK();
644145132Sanholt
645183573Srnoland	if (dev->driver->preclose != NULL)
646183573Srnoland		dev->driver->preclose(dev, file_priv);
647145132Sanholt
648145132Sanholt	/* ========================================================
649145132Sanholt	 * Begin inline drm_release
650145132Sanholt	 */
651145132Sanholt
652183573Srnoland	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
653183573Srnoland	    DRM_CURRENTPID, (long)dev->device, dev->open_count);
654145132Sanholt
655145132Sanholt	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
656182080Srnoland	    && dev->lock.file_priv == file_priv) {
657145132Sanholt		DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
658145132Sanholt			  DRM_CURRENTPID,
659145132Sanholt			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
660183573Srnoland		if (dev->driver->reclaim_buffers_locked != NULL)
661183573Srnoland			dev->driver->reclaim_buffers_locked(dev, file_priv);
662145132Sanholt
663183573Srnoland		drm_lock_free(&dev->lock,
664145132Sanholt		    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
665145132Sanholt
666145132Sanholt				/* FIXME: may require heavy-handed reset of
667145132Sanholt                                   hardware at this point, possibly
668145132Sanholt                                   processed via a callback to the X
669145132Sanholt                                   server. */
670183573Srnoland	} else if (dev->driver->reclaim_buffers_locked != NULL &&
671152909Sanholt	    dev->lock.hw_lock != NULL) {
672145132Sanholt		/* The lock is required to reclaim buffers */
673145132Sanholt		for (;;) {
674183573Srnoland			if (!dev->lock.hw_lock) {
675145132Sanholt				/* Device has been unregistered */
676182080Srnoland				retcode = EINTR;
677145132Sanholt				break;
678145132Sanholt			}
679183573Srnoland			if (drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT)) {
680182080Srnoland				dev->lock.file_priv = file_priv;
681145132Sanholt				dev->lock.lock_time = jiffies;
682183573Srnoland				atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
683145132Sanholt				break;	/* Got lock */
684145132Sanholt			}
685183573Srnoland			/* Contention */
686182080Srnoland			retcode = mtx_sleep((void *)&dev->lock.lock_queue,
687189869Srnoland			    &dev->dev_lock, PCATCH, "drmlk2", 0);
688145132Sanholt			if (retcode)
689145132Sanholt				break;
690145132Sanholt		}
691145132Sanholt		if (retcode == 0) {
692183573Srnoland			dev->driver->reclaim_buffers_locked(dev, file_priv);
693183573Srnoland			drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT);
694145132Sanholt		}
695145132Sanholt	}
696145132Sanholt
697183573Srnoland	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
698183573Srnoland	    !dev->driver->reclaim_buffers_locked)
699182080Srnoland		drm_reclaim_buffers(dev, file_priv);
700145132Sanholt
701145132Sanholt	funsetown(&dev->buf_sigio);
702145132Sanholt
703183573Srnoland	if (dev->driver->postclose != NULL)
704183573Srnoland		dev->driver->postclose(dev, file_priv);
705182080Srnoland	TAILQ_REMOVE(&dev->files, file_priv, link);
706183833Srnoland	free(file_priv, DRM_MEM_FILES);
707145132Sanholt
708145132Sanholt	/* ========================================================
709145132Sanholt	 * End inline drm_release
710145132Sanholt	 */
711145132Sanholt
712183573Srnoland	atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
713145132Sanholt	device_unbusy(dev->device);
714145132Sanholt	if (--dev->open_count == 0) {
715152909Sanholt		retcode = drm_lastclose(dev);
716145132Sanholt	}
717145132Sanholt
718145132Sanholt	DRM_UNLOCK();
719145132Sanholt}
720145132Sanholt
721145132Sanholt/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm.
722145132Sanholt */
723145132Sanholtint drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags,
724145132Sanholt    DRM_STRUCTPROC *p)
725145132Sanholt{
726182080Srnoland	struct drm_device *dev = drm_get_device_from_kdev(kdev);
727145132Sanholt	int retcode = 0;
728145132Sanholt	drm_ioctl_desc_t *ioctl;
729182080Srnoland	int (*func)(struct drm_device *dev, void *data, struct drm_file *file_priv);
730145132Sanholt	int nr = DRM_IOCTL_NR(cmd);
731145132Sanholt	int is_driver_ioctl = 0;
732183573Srnoland	struct drm_file *file_priv;
733145132Sanholt
734183573Srnoland	retcode = devfs_get_cdevpriv((void **)&file_priv);
735183573Srnoland	if (retcode != 0) {
736145132Sanholt		DRM_ERROR("can't find authenticator\n");
737145132Sanholt		return EINVAL;
738145132Sanholt	}
739145132Sanholt
740183573Srnoland	atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
741182080Srnoland	++file_priv->ioctl_count;
742145132Sanholt
743183573Srnoland	DRM_DEBUG("pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
744182080Srnoland	    DRM_CURRENTPID, cmd, nr, (long)dev->device,
745183573Srnoland	    file_priv->authenticated);
746145132Sanholt
747145132Sanholt	switch (cmd) {
748145132Sanholt	case FIONBIO:
749145132Sanholt	case FIOASYNC:
750145132Sanholt		return 0;
751145132Sanholt
752145132Sanholt	case FIOSETOWN:
753145132Sanholt		return fsetown(*(int *)data, &dev->buf_sigio);
754145132Sanholt
755145132Sanholt	case FIOGETOWN:
756145132Sanholt		*(int *) data = fgetown(&dev->buf_sigio);
757145132Sanholt		return 0;
758145132Sanholt	}
759145132Sanholt
760145132Sanholt	if (IOCGROUP(cmd) != DRM_IOCTL_BASE) {
761145132Sanholt		DRM_DEBUG("Bad ioctl group 0x%x\n", (int)IOCGROUP(cmd));
762145132Sanholt		return EINVAL;
763145132Sanholt	}
764145132Sanholt
765145132Sanholt	ioctl = &drm_ioctls[nr];
766145132Sanholt	/* It's not a core DRM ioctl, try driver-specific. */
767145132Sanholt	if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
768145132Sanholt		/* The array entries begin at DRM_COMMAND_BASE ioctl nr */
769145132Sanholt		nr -= DRM_COMMAND_BASE;
770183573Srnoland		if (nr > dev->driver->max_ioctl) {
771145132Sanholt			DRM_DEBUG("Bad driver ioctl number, 0x%x (of 0x%x)\n",
772183573Srnoland			    nr, dev->driver->max_ioctl);
773145132Sanholt			return EINVAL;
774145132Sanholt		}
775183573Srnoland		ioctl = &dev->driver->ioctls[nr];
776145132Sanholt		is_driver_ioctl = 1;
777145132Sanholt	}
778145132Sanholt	func = ioctl->func;
779145132Sanholt
780145132Sanholt	if (func == NULL) {
781183573Srnoland		DRM_DEBUG("no function\n");
782145132Sanholt		return EINVAL;
783145132Sanholt	}
784182080Srnoland
785152909Sanholt	if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(p)) ||
786182080Srnoland	    ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
787182080Srnoland	    ((ioctl->flags & DRM_MASTER) && !file_priv->master))
788145132Sanholt		return EACCES;
789145132Sanholt
790182080Srnoland	if (is_driver_ioctl) {
791145132Sanholt		DRM_LOCK();
792182080Srnoland		/* shared code returns -errno */
793182080Srnoland		retcode = -func(dev, data, file_priv);
794145132Sanholt		DRM_UNLOCK();
795182080Srnoland	} else {
796182080Srnoland		retcode = func(dev, data, file_priv);
797182080Srnoland	}
798145132Sanholt
799145132Sanholt	if (retcode != 0)
800145132Sanholt		DRM_DEBUG("    returning %d\n", retcode);
801145132Sanholt
802182080Srnoland	return retcode;
803145132Sanholt}
804145132Sanholt
805182080Srnolanddrm_local_map_t *drm_getsarea(struct drm_device *dev)
806182080Srnoland{
807182080Srnoland	drm_local_map_t *map;
808145132Sanholt
809182080Srnoland	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
810182080Srnoland	TAILQ_FOREACH(map, &dev->maplist, link) {
811182080Srnoland		if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
812182080Srnoland			return map;
813182080Srnoland	}
814182080Srnoland
815182080Srnoland	return NULL;
816182080Srnoland}
817182080Srnoland
818145132Sanholt#if DRM_LINUX
819145132Sanholt
820145132Sanholt#include <sys/sysproto.h>
821145132Sanholt
822145132SanholtMODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
823145132Sanholt
824145132Sanholt#define LINUX_IOCTL_DRM_MIN		0x6400
825145132Sanholt#define LINUX_IOCTL_DRM_MAX		0x64ff
826145132Sanholt
827145132Sanholtstatic linux_ioctl_function_t drm_linux_ioctl;
828145132Sanholtstatic struct linux_ioctl_handler drm_handler = {drm_linux_ioctl,
829145132Sanholt    LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
830145132Sanholt
831145132SanholtSYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
832145132Sanholt    linux_ioctl_register_handler, &drm_handler);
833145132SanholtSYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
834145132Sanholt    linux_ioctl_unregister_handler, &drm_handler);
835145132Sanholt
836145132Sanholt/* The bits for in/out are switched on Linux */
837145132Sanholt#define LINUX_IOC_IN	IOC_OUT
838145132Sanholt#define LINUX_IOC_OUT	IOC_IN
839145132Sanholt
840145132Sanholtstatic int
841145132Sanholtdrm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)
842145132Sanholt{
843145132Sanholt	int error;
844145132Sanholt	int cmd = args->cmd;
845145132Sanholt
846145132Sanholt	args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT);
847145132Sanholt	if (cmd & LINUX_IOC_IN)
848145132Sanholt		args->cmd |= IOC_IN;
849145132Sanholt	if (cmd & LINUX_IOC_OUT)
850145132Sanholt		args->cmd |= IOC_OUT;
851145132Sanholt
852145132Sanholt	error = ioctl(p, (struct ioctl_args *)args);
853145132Sanholt
854145132Sanholt	return error;
855145132Sanholt}
856145132Sanholt#endif /* DRM_LINUX */
857