| @@ -1,816 +1,825 @@ | | | @@ -1,816 +1,825 @@ |
1 | /* $NetBSD: drm_drv.c,v 1.13 2015/01/01 01:15:42 mrg Exp $ */ | | 1 | /* $NetBSD: drm_drv.c,v 1.14 2015/03/06 14:02:39 riastradh Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. | | 8 | * by Taylor R. Campbell. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.13 2015/01/01 01:15:42 mrg Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.14 2015/03/06 14:02:39 riastradh Exp $"); |
34 | | | 34 | |
35 | #include <sys/param.h> | | 35 | #include <sys/param.h> |
36 | #include <sys/types.h> | | 36 | #include <sys/types.h> |
37 | #include <sys/conf.h> | | 37 | #include <sys/conf.h> |
38 | #include <sys/device.h> | | 38 | #include <sys/device.h> |
39 | #include <sys/file.h> | | 39 | #include <sys/file.h> |
40 | #include <sys/filedesc.h> | | 40 | #include <sys/filedesc.h> |
41 | #include <sys/ioccom.h> | | 41 | #include <sys/ioccom.h> |
42 | #include <sys/kauth.h> | | 42 | #include <sys/kauth.h> |
43 | #ifndef _MODULE | | 43 | #ifndef _MODULE |
44 | /* XXX Mega-kludge because modules are broken. */ | | 44 | /* XXX Mega-kludge because modules are broken. */ |
45 | #include <sys/once.h> | | 45 | #include <sys/once.h> |
46 | #endif | | 46 | #endif |
47 | #include <sys/pmf.h> | | 47 | #include <sys/pmf.h> |
48 | #include <sys/poll.h> | | 48 | #include <sys/poll.h> |
49 | #ifndef _MODULE | | 49 | #ifndef _MODULE |
50 | #include <sys/reboot.h> /* XXX drm_init kludge */ | | 50 | #include <sys/reboot.h> /* XXX drm_init kludge */ |
51 | #endif | | 51 | #endif |
52 | #include <sys/select.h> | | 52 | #include <sys/select.h> |
53 | | | 53 | |
54 | #include <uvm/uvm_extern.h> | | 54 | #include <uvm/uvm_extern.h> |
55 | | | 55 | |
56 | #include <linux/err.h> | | 56 | #include <linux/err.h> |
57 | | | 57 | |
58 | #include <linux/pm.h> | | 58 | #include <linux/pm.h> |
59 | | | 59 | |
60 | #include <drm/drmP.h> | | 60 | #include <drm/drmP.h> |
61 | | | 61 | |
62 | static dev_type_open(drm_open); | | 62 | static dev_type_open(drm_open); |
63 | | | 63 | |
64 | static int drm_firstopen(struct drm_device *); | | 64 | static int drm_firstopen(struct drm_device *); |
65 | | | 65 | |
66 | static int drm_close(struct file *); | | 66 | static int drm_close(struct file *); |
67 | static int drm_read(struct file *, off_t *, struct uio *, kauth_cred_t, | | 67 | static int drm_read(struct file *, off_t *, struct uio *, kauth_cred_t, |
68 | int); | | 68 | int); |
69 | static int drm_dequeue_event(struct drm_file *, size_t, | | 69 | static int drm_dequeue_event(struct drm_file *, size_t, |
70 | struct drm_pending_event **, int); | | 70 | struct drm_pending_event **, int); |
71 | static int drm_poll(struct file *, int); | | 71 | static int drm_poll(struct file *, int); |
72 | static int drm_kqfilter(struct file *, struct knote *); | | 72 | static int drm_kqfilter(struct file *, struct knote *); |
73 | static int drm_stat(struct file *, struct stat *); | | 73 | static int drm_stat(struct file *, struct stat *); |
74 | static int drm_ioctl(struct file *, unsigned long, void *); | | 74 | static int drm_ioctl(struct file *, unsigned long, void *); |
75 | static int drm_fop_mmap(struct file *, off_t *, size_t, int, int *, int *, | | 75 | static int drm_fop_mmap(struct file *, off_t *, size_t, int, int *, int *, |
76 | struct uvm_object **, int *); | | 76 | struct uvm_object **, int *); |
77 | static int drm_version_string(char *, size_t *, const char *); | | 77 | static int drm_version_string(char *, size_t *, const char *); |
78 | static paddr_t drm_mmap(dev_t, off_t, int); | | 78 | static paddr_t drm_mmap(dev_t, off_t, int); |
79 | | | 79 | |
80 | static drm_ioctl_t drm_version; | | 80 | static drm_ioctl_t drm_version; |
81 | | | 81 | |
82 | #define DRM_IOCTL_DEF(IOCTL, FUNC, FLAGS) \ | | 82 | #define DRM_IOCTL_DEF(IOCTL, FUNC, FLAGS) \ |
83 | [DRM_IOCTL_NR(IOCTL)] = { \ | | 83 | [DRM_IOCTL_NR(IOCTL)] = { \ |
84 | .cmd = (IOCTL), \ | | 84 | .cmd = (IOCTL), \ |
85 | .flags = (FLAGS), \ | | 85 | .flags = (FLAGS), \ |
86 | .func = (FUNC), \ | | 86 | .func = (FUNC), \ |
87 | .cmd_drv = 0, \ | | 87 | .cmd_drv = 0, \ |
88 | } | | 88 | } |
89 | | | 89 | |
90 | /* XXX Kludge for AGP. */ | | 90 | /* XXX Kludge for AGP. */ |
91 | static drm_ioctl_t drm_agp_acquire_hook_ioctl; | | 91 | static drm_ioctl_t drm_agp_acquire_hook_ioctl; |
92 | static drm_ioctl_t drm_agp_release_hook_ioctl; | | 92 | static drm_ioctl_t drm_agp_release_hook_ioctl; |
93 | static drm_ioctl_t drm_agp_enable_hook_ioctl; | | 93 | static drm_ioctl_t drm_agp_enable_hook_ioctl; |
94 | static drm_ioctl_t drm_agp_info_hook_ioctl; | | 94 | static drm_ioctl_t drm_agp_info_hook_ioctl; |
95 | static drm_ioctl_t drm_agp_alloc_hook_ioctl; | | 95 | static drm_ioctl_t drm_agp_alloc_hook_ioctl; |
96 | static drm_ioctl_t drm_agp_free_hook_ioctl; | | 96 | static drm_ioctl_t drm_agp_free_hook_ioctl; |
97 | static drm_ioctl_t drm_agp_bind_hook_ioctl; | | 97 | static drm_ioctl_t drm_agp_bind_hook_ioctl; |
98 | static drm_ioctl_t drm_agp_unbind_hook_ioctl; | | 98 | static drm_ioctl_t drm_agp_unbind_hook_ioctl; |
99 | | | 99 | |
100 | #define drm_agp_acquire_ioctl drm_agp_acquire_hook_ioctl | | 100 | #define drm_agp_acquire_ioctl drm_agp_acquire_hook_ioctl |
101 | #define drm_agp_release_ioctl drm_agp_release_hook_ioctl | | 101 | #define drm_agp_release_ioctl drm_agp_release_hook_ioctl |
102 | #define drm_agp_enable_ioctl drm_agp_enable_hook_ioctl | | 102 | #define drm_agp_enable_ioctl drm_agp_enable_hook_ioctl |
103 | #define drm_agp_info_ioctl drm_agp_info_hook_ioctl | | 103 | #define drm_agp_info_ioctl drm_agp_info_hook_ioctl |
104 | #define drm_agp_alloc_ioctl drm_agp_alloc_hook_ioctl | | 104 | #define drm_agp_alloc_ioctl drm_agp_alloc_hook_ioctl |
105 | #define drm_agp_free_ioctl drm_agp_free_hook_ioctl | | 105 | #define drm_agp_free_ioctl drm_agp_free_hook_ioctl |
106 | #define drm_agp_bind_ioctl drm_agp_bind_hook_ioctl | | 106 | #define drm_agp_bind_ioctl drm_agp_bind_hook_ioctl |
107 | #define drm_agp_unbind_ioctl drm_agp_unbind_hook_ioctl | | 107 | #define drm_agp_unbind_ioctl drm_agp_unbind_hook_ioctl |
108 | | | 108 | |
109 | /* Table copied verbatim from dist/drm/drm_drv.c. */ | | 109 | /* Table copied verbatim from dist/drm/drm_drv.c. */ |
110 | static const struct drm_ioctl_desc drm_ioctls[] = { | | 110 | static const struct drm_ioctl_desc drm_ioctls[] = { |
111 | DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW), | | 111 | DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW), |
112 | DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), | | 112 | DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), |
113 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), | | 113 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), |
114 | DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), | | 114 | DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), |
115 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, DRM_UNLOCKED), | | 115 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, DRM_UNLOCKED), |
116 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED), | | 116 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED), |
117 | DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED), | | 117 | DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED), |
118 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW), | | 118 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW), |
119 | DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), | | 119 | DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), |
120 | DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), | | 120 | DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), |
121 | | | 121 | |
122 | DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 122 | DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
123 | DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 123 | DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
124 | DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 124 | DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
125 | DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER), | | 125 | DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER), |
126 | | | 126 | |
127 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 127 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
128 | DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH), | | 128 | DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH), |
129 | | | 129 | |
130 | DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 130 | DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
131 | DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), | | 131 | DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), |
132 | | | 132 | |
133 | DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY), | | 133 | DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY), |
134 | DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY), | | 134 | DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY), |
135 | | | 135 | |
136 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), | | 136 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), |
137 | DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 137 | DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
138 | DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 138 | DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
139 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH), | | 139 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH), |
140 | DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 140 | DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
141 | DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 141 | DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
142 | DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH), | | 142 | DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH), |
143 | | | 143 | |
144 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 144 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
145 | DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 145 | DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
146 | | | 146 | |
147 | DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH), | | 147 | DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH), |
148 | DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH), | | 148 | DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH), |
149 | | | 149 | |
150 | DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), | | 150 | DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), |
151 | | | 151 | |
152 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 152 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
153 | DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 153 | DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
154 | DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH), | | 154 | DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH), |
155 | DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH), | | 155 | DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH), |
156 | DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH), | | 156 | DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH), |
157 | DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma_ioctl, DRM_AUTH), | | 157 | DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma_ioctl, DRM_AUTH), |
158 | | | 158 | |
159 | DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 159 | DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
160 | | | 160 | |
161 | #if __OS_HAS_AGP | | 161 | #if __OS_HAS_AGP |
162 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 162 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
163 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 163 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
164 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 164 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
165 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH), | | 165 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH), |
166 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 166 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
167 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 167 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
168 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 168 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
169 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 169 | DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
170 | #endif | | 170 | #endif |
171 | | | 171 | |
172 | DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 172 | DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
173 | DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 173 | DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
174 | | | 174 | |
175 | DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED), | | 175 | DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED), |
176 | | | 176 | |
177 | DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), | | 177 | DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), |
178 | | | 178 | |
179 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | | 179 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
180 | | | 180 | |
181 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), | | 181 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), |
182 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED), | | 182 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED), |
183 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED), | | 183 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED), |
184 | | | 184 | |
185 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 185 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
186 | | | 186 | |
187 | #ifndef __NetBSD__ /* XXX drm prime */ | | 187 | #ifndef __NetBSD__ /* XXX drm prime */ |
188 | DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), | | 188 | DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), |
189 | DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), | | 189 | DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), |
190 | #endif | | 190 | #endif |
191 | | | 191 | |
192 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 192 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
193 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 193 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
194 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 194 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
195 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 195 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
196 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 196 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
197 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 197 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
198 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED), | | 198 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED), |
199 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), | | 199 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), |
200 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 200 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
201 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 201 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
202 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 202 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
203 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 203 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
204 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 204 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
205 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 205 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
206 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 206 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
207 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 207 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
208 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 208 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
209 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 209 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
210 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 210 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
211 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 211 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
212 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 212 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
213 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 213 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
214 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 214 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
215 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 215 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
216 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 216 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
217 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 217 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
218 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | | 218 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
219 | }; | | 219 | }; |
220 | | | 220 | |
221 | const struct cdevsw drm_cdevsw = { | | 221 | const struct cdevsw drm_cdevsw = { |
222 | .d_open = drm_open, | | 222 | .d_open = drm_open, |
223 | .d_close = noclose, | | 223 | .d_close = noclose, |
224 | .d_read = noread, | | 224 | .d_read = noread, |
225 | .d_write = nowrite, | | 225 | .d_write = nowrite, |
226 | .d_ioctl = noioctl, | | 226 | .d_ioctl = noioctl, |
227 | .d_stop = nostop, | | 227 | .d_stop = nostop, |
228 | .d_tty = notty, | | 228 | .d_tty = notty, |
229 | .d_poll = nopoll, | | 229 | .d_poll = nopoll, |
230 | .d_mmap = drm_mmap, | | 230 | .d_mmap = drm_mmap, |
231 | .d_kqfilter = nokqfilter, | | 231 | .d_kqfilter = nokqfilter, |
232 | .d_discard = nodiscard, | | 232 | .d_discard = nodiscard, |
233 | /* XXX was D_TTY | D_NEGOFFSAFE */ | | 233 | /* XXX was D_TTY | D_NEGOFFSAFE */ |
234 | /* XXX Add D_MPSAFE some day... */ | | 234 | /* XXX Add D_MPSAFE some day... */ |
235 | .d_flag = D_NEGOFFSAFE, | | 235 | .d_flag = D_NEGOFFSAFE, |
236 | }; | | 236 | }; |
237 | | | 237 | |
238 | static const struct fileops drm_fileops = { | | 238 | static const struct fileops drm_fileops = { |
239 | .fo_read = drm_read, | | 239 | .fo_read = drm_read, |
240 | .fo_write = fbadop_write, | | 240 | .fo_write = fbadop_write, |
241 | .fo_ioctl = drm_ioctl, | | 241 | .fo_ioctl = drm_ioctl, |
242 | .fo_fcntl = fnullop_fcntl, | | 242 | .fo_fcntl = fnullop_fcntl, |
243 | .fo_poll = drm_poll, | | 243 | .fo_poll = drm_poll, |
244 | .fo_stat = drm_stat, | | 244 | .fo_stat = drm_stat, |
245 | .fo_close = drm_close, | | 245 | .fo_close = drm_close, |
246 | .fo_kqfilter = drm_kqfilter, | | 246 | .fo_kqfilter = drm_kqfilter, |
247 | .fo_restart = fnullop_restart, | | 247 | .fo_restart = fnullop_restart, |
248 | .fo_mmap = drm_fop_mmap, | | 248 | .fo_mmap = drm_fop_mmap, |
249 | }; | | 249 | }; |
250 | | | 250 | |
251 | static int | | 251 | static int |
252 | drm_open(dev_t d, int flags, int fmt, struct lwp *l) | | 252 | drm_open(dev_t d, int flags, int fmt, struct lwp *l) |
253 | { | | 253 | { |
254 | struct drm_minor *dminor; | | 254 | struct drm_minor *dminor; |
255 | struct drm_device *dev; | | 255 | struct drm_device *dev; |
256 | bool firstopen, lastclose; | | 256 | bool firstopen, lastclose; |
257 | int fd; | | 257 | int fd; |
258 | struct file *fp; | | 258 | struct file *fp; |
259 | int error; | | 259 | int error; |
260 | extern int drm_guarantee_initialized(void); | | 260 | extern int drm_guarantee_initialized(void); |
261 | | | 261 | |
262 | error = drm_guarantee_initialized(); | | 262 | error = drm_guarantee_initialized(); |
263 | if (error) | | 263 | if (error) |
264 | goto fail0; | | 264 | goto fail0; |
265 | | | 265 | |
266 | if (flags & O_EXCL) { | | 266 | if (flags & O_EXCL) { |
267 | error = EBUSY; | | 267 | error = EBUSY; |
268 | goto fail0; | | 268 | goto fail0; |
269 | } | | 269 | } |
270 | | | 270 | |
271 | dminor = drm_minor_acquire(minor(d)); | | 271 | dminor = drm_minor_acquire(minor(d)); |
272 | if (IS_ERR(dminor)) { | | 272 | if (IS_ERR(dminor)) { |
273 | /* XXX errno Linux->NetBSD */ | | 273 | /* XXX errno Linux->NetBSD */ |
274 | error = -PTR_ERR(dminor); | | 274 | error = -PTR_ERR(dminor); |
275 | goto fail0; | | 275 | goto fail0; |
276 | } | | 276 | } |
277 | dev = dminor->dev; | | 277 | dev = dminor->dev; |
278 | if (dev->switch_power_state != DRM_SWITCH_POWER_ON) { | | 278 | if (dev->switch_power_state != DRM_SWITCH_POWER_ON) { |
279 | error = EINVAL; | | 279 | error = EINVAL; |
280 | goto fail1; | | 280 | goto fail1; |
281 | } | | 281 | } |
282 | | | 282 | |
283 | spin_lock(&dev->count_lock); | | 283 | spin_lock(&dev->count_lock); |
284 | if (dev->open_count == INT_MAX) { | | 284 | if (dev->open_count == INT_MAX) { |
285 | spin_unlock(&dev->count_lock); | | 285 | spin_unlock(&dev->count_lock); |
286 | error = EBUSY; | | 286 | error = EBUSY; |
287 | goto fail1; | | 287 | goto fail1; |
288 | } | | 288 | } |
289 | firstopen = (dev->open_count == 0); | | 289 | firstopen = (dev->open_count == 0); |
290 | dev->open_count++; | | 290 | dev->open_count++; |
291 | spin_unlock(&dev->count_lock); | | 291 | spin_unlock(&dev->count_lock); |
292 | | | 292 | |
293 | if (firstopen) { | | 293 | if (firstopen) { |
294 | /* XXX errno Linux->NetBSD */ | | 294 | /* XXX errno Linux->NetBSD */ |
295 | error = drm_firstopen(dev); | | 295 | error = drm_firstopen(dev); |
296 | if (error) | | 296 | if (error) |
297 | goto fail2; | | 297 | goto fail2; |
298 | } | | 298 | } |
299 | | | 299 | |
300 | error = fd_allocfile(&fp, &fd); | | 300 | error = fd_allocfile(&fp, &fd); |
301 | if (error) | | 301 | if (error) |
302 | goto fail2; | | 302 | goto fail2; |
303 | | | 303 | |
304 | struct drm_file *const file = kmem_zalloc(sizeof(*file), KM_SLEEP); | | 304 | struct drm_file *const file = kmem_zalloc(sizeof(*file), KM_SLEEP); |
305 | /* XXX errno Linux->NetBSD */ | | 305 | /* XXX errno Linux->NetBSD */ |
306 | error = -drm_open_file(file, fp, dminor); | | 306 | error = -drm_open_file(file, fp, dminor); |
307 | if (error) | | 307 | if (error) |
308 | goto fail3; | | 308 | goto fail3; |
309 | | | 309 | |
310 | error = fd_clone(fp, fd, flags, &drm_fileops, file); | | 310 | error = fd_clone(fp, fd, flags, &drm_fileops, file); |
311 | KASSERT(error == EMOVEFD); /* XXX */ | | 311 | KASSERT(error == EMOVEFD); /* XXX */ |
312 | | | 312 | |
313 | /* Success! (But error has to be EMOVEFD, not 0.) */ | | 313 | /* Success! (But error has to be EMOVEFD, not 0.) */ |
314 | return error; | | 314 | return error; |
315 | | | 315 | |
316 | fail3: kmem_free(file, sizeof(*file)); | | 316 | fail3: kmem_free(file, sizeof(*file)); |
317 | fd_abort(curproc, fp, fd); | | 317 | fd_abort(curproc, fp, fd); |
318 | fail2: spin_lock(&dev->count_lock); | | 318 | fail2: spin_lock(&dev->count_lock); |
319 | KASSERT(0 < dev->open_count); | | 319 | KASSERT(0 < dev->open_count); |
320 | --dev->open_count; | | 320 | --dev->open_count; |
321 | lastclose = (dev->open_count == 0); | | 321 | lastclose = (dev->open_count == 0); |
322 | spin_unlock(&dev->count_lock); | | 322 | spin_unlock(&dev->count_lock); |
323 | if (lastclose) | | 323 | if (lastclose) |
324 | (void)drm_lastclose(dev); | | 324 | (void)drm_lastclose(dev); |
325 | fail1: drm_minor_release(dminor); | | 325 | fail1: drm_minor_release(dminor); |
326 | fail0: KASSERT(error); | | 326 | fail0: KASSERT(error); |
327 | return error; | | 327 | return error; |
328 | } | | 328 | } |
329 | | | 329 | |
330 | static int | | 330 | static int |
331 | drm_close(struct file *fp) | | 331 | drm_close(struct file *fp) |
332 | { | | 332 | { |
333 | struct drm_file *const file = fp->f_data; | | 333 | struct drm_file *const file = fp->f_data; |
334 | struct drm_minor *const dminor = file->minor; | | 334 | struct drm_minor *const dminor = file->minor; |
335 | struct drm_device *const dev = dminor->dev; | | 335 | struct drm_device *const dev = dminor->dev; |
336 | bool lastclose; | | 336 | bool lastclose; |
337 | | | 337 | |
338 | drm_close_file(file); | | 338 | drm_close_file(file); |
339 | kmem_free(file, sizeof(*file)); | | 339 | kmem_free(file, sizeof(*file)); |
340 | | | 340 | |
341 | spin_lock(&dev->count_lock); | | 341 | spin_lock(&dev->count_lock); |
342 | KASSERT(0 < dev->open_count); | | 342 | KASSERT(0 < dev->open_count); |
343 | --dev->open_count; | | 343 | --dev->open_count; |
344 | lastclose = (dev->open_count == 0); | | 344 | lastclose = (dev->open_count == 0); |
345 | spin_unlock(&dev->count_lock); | | 345 | spin_unlock(&dev->count_lock); |
346 | | | 346 | |
347 | if (lastclose) | | 347 | if (lastclose) |
348 | (void)drm_lastclose(dev); | | 348 | (void)drm_lastclose(dev); |
349 | | | 349 | |
350 | drm_minor_release(dminor); | | 350 | drm_minor_release(dminor); |
351 | | | 351 | |
352 | return 0; | | 352 | return 0; |
353 | } | | 353 | } |
354 | | | 354 | |
355 | static int | | 355 | static int |
356 | drm_firstopen(struct drm_device *dev) | | 356 | drm_firstopen(struct drm_device *dev) |
357 | { | | 357 | { |
358 | int ret; | | 358 | int ret; |
359 | | | 359 | |
360 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | | 360 | if (drm_core_check_feature(dev, DRIVER_MODESET)) |
361 | return 0; | | 361 | return 0; |
362 | | | 362 | |
363 | if (dev->driver->firstopen) { | | 363 | if (dev->driver->firstopen) { |
364 | ret = (*dev->driver->firstopen)(dev); | | 364 | ret = (*dev->driver->firstopen)(dev); |
365 | if (ret) | | 365 | if (ret) |
366 | goto fail0; | | 366 | goto fail0; |
367 | } | | 367 | } |
368 | | | 368 | |
369 | ret = drm_legacy_dma_setup(dev); | | 369 | ret = drm_legacy_dma_setup(dev); |
370 | if (ret) | | 370 | if (ret) |
371 | goto fail1; | | 371 | goto fail1; |
372 | | | 372 | |
373 | return 0; | | 373 | return 0; |
374 | | | 374 | |
375 | fail2: __unused | | 375 | fail2: __unused |
376 | drm_legacy_dma_takedown(dev); | | 376 | drm_legacy_dma_takedown(dev); |
377 | fail1: if (dev->driver->lastclose) | | 377 | fail1: if (dev->driver->lastclose) |
378 | (*dev->driver->lastclose)(dev); | | 378 | (*dev->driver->lastclose)(dev); |
379 | fail0: KASSERT(ret); | | 379 | fail0: KASSERT(ret); |
380 | return ret; | | 380 | return ret; |
381 | } | | 381 | } |
382 | | | 382 | |
383 | int | | 383 | int |
384 | drm_lastclose(struct drm_device *dev) | | 384 | drm_lastclose(struct drm_device *dev) |
385 | { | | 385 | { |
386 | struct drm_vma_entry *vma, *vma_temp; | | 386 | struct drm_vma_entry *vma, *vma_temp; |
387 | | | 387 | |
388 | /* XXX Order is sketchy here... */ | | 388 | /* XXX Order is sketchy here... */ |
389 | if (dev->driver->lastclose) | | 389 | if (dev->driver->lastclose) |
390 | (*dev->driver->lastclose)(dev); | | 390 | (*dev->driver->lastclose)(dev); |
391 | if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET)) | | 391 | if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET)) |
392 | drm_irq_uninstall(dev); | | 392 | drm_irq_uninstall(dev); |
393 | | | 393 | |
394 | mutex_lock(&dev->struct_mutex); | | 394 | mutex_lock(&dev->struct_mutex); |
395 | drm_agp_clear_hook(dev); | | 395 | drm_agp_clear_hook(dev); |
396 | drm_legacy_sg_cleanup(dev); | | 396 | drm_legacy_sg_cleanup(dev); |
397 | list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { | | 397 | list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { |
398 | list_del(&vma->head); | | 398 | list_del(&vma->head); |
399 | kfree(vma); | | 399 | kfree(vma); |
400 | } | | 400 | } |
401 | drm_legacy_dma_takedown(dev); | | 401 | drm_legacy_dma_takedown(dev); |
402 | mutex_unlock(&dev->struct_mutex); | | 402 | mutex_unlock(&dev->struct_mutex); |
403 | | | 403 | |
404 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) { | | 404 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) { |
405 | dev->sigdata.lock = NULL; | | 405 | dev->sigdata.lock = NULL; |
406 | dev->context_flag = 0; | | 406 | dev->context_flag = 0; |
407 | dev->last_context = 0; | | 407 | dev->last_context = 0; |
408 | dev->if_version = 0; | | 408 | dev->if_version = 0; |
409 | } | | 409 | } |
410 | | | 410 | |
411 | return 0; | | 411 | return 0; |
412 | } | | 412 | } |
413 | | | 413 | |
414 | static int | | 414 | static int |
415 | drm_read(struct file *fp, off_t *off, struct uio *uio, kauth_cred_t cred, | | 415 | drm_read(struct file *fp, off_t *off, struct uio *uio, kauth_cred_t cred, |
416 | int flags) | | 416 | int flags) |
417 | { | | 417 | { |
418 | struct drm_file *const file = fp->f_data; | | 418 | struct drm_file *const file = fp->f_data; |
419 | struct drm_pending_event *event; | | 419 | struct drm_pending_event *event; |
420 | bool first; | | 420 | bool first; |
421 | int error = 0; | | 421 | int error = 0; |
422 | | | 422 | |
423 | for (first = true; ; first = false) { | | 423 | for (first = true; ; first = false) { |
424 | int f = 0; | | 424 | int f = 0; |
425 | | | 425 | |
426 | if (!first || ISSET(fp->f_flag, FNONBLOCK)) | | 426 | if (!first || ISSET(fp->f_flag, FNONBLOCK)) |
427 | f |= FNONBLOCK; | | 427 | f |= FNONBLOCK; |
428 | | | 428 | |
429 | /* XXX errno Linux->NetBSD */ | | 429 | /* XXX errno Linux->NetBSD */ |
430 | error = -drm_dequeue_event(file, uio->uio_resid, &event, f); | | 430 | error = -drm_dequeue_event(file, uio->uio_resid, &event, f); |
431 | if (error) { | | 431 | if (error) { |
432 | if ((error == EWOULDBLOCK) && !first) | | 432 | if ((error == EWOULDBLOCK) && !first) |
433 | error = 0; | | 433 | error = 0; |
434 | break; | | 434 | break; |
435 | } | | 435 | } |
436 | if (event == NULL) | | 436 | if (event == NULL) |
437 | break; | | 437 | break; |
438 | error = uiomove(event->event, event->event->length, uio); | | 438 | error = uiomove(event->event, event->event->length, uio); |
439 | if (error) /* XXX Requeue the event? */ | | 439 | if (error) /* XXX Requeue the event? */ |
440 | break; | | 440 | break; |
441 | (*event->destroy)(event); | | 441 | (*event->destroy)(event); |
442 | } | | 442 | } |
443 | | | 443 | |
444 | /* Success! */ | | 444 | /* Success! */ |
445 | return error; | | 445 | return error; |
446 | } | | 446 | } |
447 | | | 447 | |
448 | static int | | 448 | static int |
449 | drm_dequeue_event(struct drm_file *file, size_t max_length, | | 449 | drm_dequeue_event(struct drm_file *file, size_t max_length, |
450 | struct drm_pending_event **eventp, int flags) | | 450 | struct drm_pending_event **eventp, int flags) |
451 | { | | 451 | { |
452 | struct drm_device *const dev = file->minor->dev; | | 452 | struct drm_device *const dev = file->minor->dev; |
453 | struct drm_pending_event *event = NULL; | | 453 | struct drm_pending_event *event = NULL; |
454 | unsigned long irqflags; | | 454 | unsigned long irqflags; |
455 | int ret = 0; | | 455 | int ret = 0; |
456 | | | 456 | |
457 | spin_lock_irqsave(&dev->event_lock, irqflags); | | 457 | spin_lock_irqsave(&dev->event_lock, irqflags); |
458 | | | 458 | |
459 | if (ISSET(flags, FNONBLOCK)) { | | 459 | if (ISSET(flags, FNONBLOCK)) { |
460 | if (list_empty(&file->event_list)) | | 460 | if (list_empty(&file->event_list)) |
461 | ret = -EWOULDBLOCK; | | 461 | ret = -EWOULDBLOCK; |
462 | } else { | | 462 | } else { |
463 | DRM_SPIN_WAIT_UNTIL(ret, &file->event_wait, &dev->event_lock, | | 463 | DRM_SPIN_WAIT_UNTIL(ret, &file->event_wait, &dev->event_lock, |
464 | !list_empty(&file->event_list)); | | 464 | !list_empty(&file->event_list)); |
465 | } | | 465 | } |
466 | if (ret) | | 466 | if (ret) |
467 | goto out; | | 467 | goto out; |
468 | | | 468 | |
469 | event = list_first_entry(&file->event_list, struct drm_pending_event, | | 469 | event = list_first_entry(&file->event_list, struct drm_pending_event, |
470 | link); | | 470 | link); |
471 | if (event->event->length > max_length) { | | 471 | if (event->event->length > max_length) { |
472 | ret = 0; | | 472 | ret = 0; |
473 | goto out; | | 473 | goto out; |
474 | } | | 474 | } |
475 | | | 475 | |
476 | file->event_space += event->event->length; | | 476 | file->event_space += event->event->length; |
477 | list_del(&event->link); | | 477 | list_del(&event->link); |
478 | | | 478 | |
479 | out: spin_unlock_irqrestore(&dev->event_lock, irqflags); | | 479 | out: spin_unlock_irqrestore(&dev->event_lock, irqflags); |
480 | *eventp = event; | | 480 | *eventp = event; |
481 | return ret; | | 481 | return ret; |
482 | } | | 482 | } |
483 | | | 483 | |
484 | static int | | 484 | static int |
485 | drm_poll(struct file *fp __unused, int events __unused) | | 485 | drm_poll(struct file *fp __unused, int events __unused) |
486 | { | | 486 | { |
487 | struct drm_file *const file = fp->f_data; | | 487 | struct drm_file *const file = fp->f_data; |
488 | struct drm_device *const dev = file->minor->dev; | | 488 | struct drm_device *const dev = file->minor->dev; |
489 | int revents = 0; | | 489 | int revents = 0; |
490 | unsigned long irqflags; | | 490 | unsigned long irqflags; |
491 | | | 491 | |
492 | if (!ISSET(events, (POLLIN | POLLRDNORM))) | | 492 | if (!ISSET(events, (POLLIN | POLLRDNORM))) |
493 | return 0; | | 493 | return 0; |
494 | | | 494 | |
495 | spin_lock_irqsave(&dev->event_lock, irqflags); | | 495 | spin_lock_irqsave(&dev->event_lock, irqflags); |
496 | if (list_empty(&file->event_list)) | | 496 | if (list_empty(&file->event_list)) |
497 | selrecord(curlwp, &file->event_selq); | | 497 | selrecord(curlwp, &file->event_selq); |
498 | else | | 498 | else |
499 | revents |= (events & (POLLIN | POLLRDNORM)); | | 499 | revents |= (events & (POLLIN | POLLRDNORM)); |
500 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | | 500 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
501 | | | 501 | |
502 | return revents; | | 502 | return revents; |
503 | } | | 503 | } |
504 | | | 504 | |
505 | static void filt_drm_detach(struct knote *); | | 505 | static void filt_drm_detach(struct knote *); |
506 | static int filt_drm_event(struct knote *, long); | | 506 | static int filt_drm_event(struct knote *, long); |
507 | | | 507 | |
508 | static const struct filterops drm_filtops = | | 508 | static const struct filterops drm_filtops = |
509 | { 1, NULL, filt_drm_detach, filt_drm_event }; | | 509 | { 1, NULL, filt_drm_detach, filt_drm_event }; |
510 | | | 510 | |
511 | static int | | 511 | static int |
512 | drm_kqfilter(struct file *fp, struct knote *kn) | | 512 | drm_kqfilter(struct file *fp, struct knote *kn) |
513 | { | | 513 | { |
514 | struct drm_file *const file = fp->f_data; | | 514 | struct drm_file *const file = fp->f_data; |
515 | struct drm_device *const dev = file->minor->dev; | | 515 | struct drm_device *const dev = file->minor->dev; |
516 | unsigned long irqflags; | | 516 | unsigned long irqflags; |
517 | | | 517 | |
518 | switch (kn->kn_filter) { | | 518 | switch (kn->kn_filter) { |
519 | case EVFILT_READ: | | 519 | case EVFILT_READ: |
520 | kn->kn_fop = &drm_filtops; | | 520 | kn->kn_fop = &drm_filtops; |
521 | kn->kn_hook = file; | | 521 | kn->kn_hook = file; |
522 | spin_lock_irqsave(&dev->event_lock, irqflags); | | 522 | spin_lock_irqsave(&dev->event_lock, irqflags); |
523 | SLIST_INSERT_HEAD(&file->event_selq.sel_klist, kn, kn_selnext); | | 523 | SLIST_INSERT_HEAD(&file->event_selq.sel_klist, kn, kn_selnext); |
524 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | | 524 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
525 | return 0; | | 525 | return 0; |
526 | case EVFILT_WRITE: | | 526 | case EVFILT_WRITE: |
527 | default: | | 527 | default: |
528 | return EINVAL; | | 528 | return EINVAL; |
529 | } | | 529 | } |
530 | } | | 530 | } |
531 | | | 531 | |
532 | static void | | 532 | static void |
533 | filt_drm_detach(struct knote *kn) | | 533 | filt_drm_detach(struct knote *kn) |
534 | { | | 534 | { |
535 | struct drm_file *const file = kn->kn_hook; | | 535 | struct drm_file *const file = kn->kn_hook; |
536 | struct drm_device *const dev = file->minor->dev; | | 536 | struct drm_device *const dev = file->minor->dev; |
537 | unsigned long irqflags; | | 537 | unsigned long irqflags; |
538 | | | 538 | |
539 | spin_lock_irqsave(&dev->event_lock, irqflags); | | 539 | spin_lock_irqsave(&dev->event_lock, irqflags); |
540 | SLIST_REMOVE(&file->event_selq.sel_klist, kn, knote, kn_selnext); | | 540 | SLIST_REMOVE(&file->event_selq.sel_klist, kn, knote, kn_selnext); |
541 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | | 541 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
542 | } | | 542 | } |
543 | | | 543 | |
544 | static int | | 544 | static int |
545 | filt_drm_event(struct knote *kn, long hint) | | 545 | filt_drm_event(struct knote *kn, long hint) |
546 | { | | 546 | { |
547 | struct drm_file *const file = kn->kn_hook; | | 547 | struct drm_file *const file = kn->kn_hook; |
548 | struct drm_device *const dev = file->minor->dev; | | 548 | struct drm_device *const dev = file->minor->dev; |
549 | unsigned long irqflags; | | 549 | unsigned long irqflags; |
550 | int ret; | | 550 | int ret; |
551 | | | 551 | |
552 | if (hint == NOTE_SUBMIT) | | 552 | if (hint == NOTE_SUBMIT) |
553 | KASSERT(spin_is_locked(&dev->event_lock)); | | 553 | KASSERT(spin_is_locked(&dev->event_lock)); |
554 | else | | 554 | else |
555 | spin_lock_irqsave(&dev->event_lock, irqflags); | | 555 | spin_lock_irqsave(&dev->event_lock, irqflags); |
556 | if (list_empty(&file->event_list)) { | | 556 | if (list_empty(&file->event_list)) { |
557 | ret = 0; | | 557 | ret = 0; |
558 | } else { | | 558 | } else { |
559 | struct drm_pending_event *const event = | | 559 | struct drm_pending_event *const event = |
560 | list_first_entry(&file->event_list, | | 560 | list_first_entry(&file->event_list, |
561 | struct drm_pending_event, link); | | 561 | struct drm_pending_event, link); |
562 | kn->kn_data = event->event->length; | | 562 | kn->kn_data = event->event->length; |
563 | ret = 1; | | 563 | ret = 1; |
564 | } | | 564 | } |
565 | if (hint == NOTE_SUBMIT) | | 565 | if (hint == NOTE_SUBMIT) |
566 | KASSERT(spin_is_locked(&dev->event_lock)); | | 566 | KASSERT(spin_is_locked(&dev->event_lock)); |
567 | else | | 567 | else |
568 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | | 568 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
569 | | | 569 | |
570 | return ret; | | 570 | return ret; |
571 | } | | 571 | } |
572 | | | 572 | |
573 | static int | | 573 | static int |
574 | drm_stat(struct file *fp, struct stat *st) | | 574 | drm_stat(struct file *fp, struct stat *st) |
575 | { | | 575 | { |
576 | struct drm_file *const file = fp->f_data; | | 576 | struct drm_file *const file = fp->f_data; |
577 | struct drm_minor *const dminor = file->minor; | | 577 | struct drm_minor *const dminor = file->minor; |
578 | const dev_t devno = makedev(cdevsw_lookup_major(&drm_cdevsw), | | 578 | const dev_t devno = makedev(cdevsw_lookup_major(&drm_cdevsw), |
579 | 64*dminor->index + dminor->type); | | 579 | 64*dminor->index + dminor->type); |
580 | | | 580 | |
581 | (void)memset(st, 0, sizeof(*st)); | | 581 | (void)memset(st, 0, sizeof(*st)); |
582 | | | 582 | |
583 | st->st_dev = devno; | | 583 | st->st_dev = devno; |
584 | st->st_ino = 0; /* XXX (dev,ino) uniqueness bleh */ | | 584 | st->st_ino = 0; /* XXX (dev,ino) uniqueness bleh */ |
585 | st->st_uid = kauth_cred_geteuid(fp->f_cred); | | 585 | st->st_uid = kauth_cred_geteuid(fp->f_cred); |
586 | st->st_gid = kauth_cred_getegid(fp->f_cred); | | 586 | st->st_gid = kauth_cred_getegid(fp->f_cred); |
587 | st->st_mode = S_IFCHR; /* XXX what? */ | | 587 | st->st_mode = S_IFCHR; /* XXX what? */ |
588 | st->st_rdev = devno; | | 588 | st->st_rdev = devno; |
589 | /* XXX what else? */ | | 589 | /* XXX what else? */ |
590 | | | 590 | |
591 | return 0; | | 591 | return 0; |
592 | } | | 592 | } |
593 | | | 593 | |
594 | static int | | 594 | static int |
595 | drm_ioctl(struct file *fp, unsigned long cmd, void *data) | | 595 | drm_ioctl(struct file *fp, unsigned long cmd, void *data) |
596 | { | | 596 | { |
597 | struct drm_file *const file = fp->f_data; | | 597 | struct drm_file *const file = fp->f_data; |
598 | const unsigned int nr = DRM_IOCTL_NR(cmd); | | 598 | const unsigned int nr = DRM_IOCTL_NR(cmd); |
599 | int error; | | 599 | int error; |
600 | | | 600 | |
601 | switch (cmd) { | | 601 | switch (cmd) { |
602 | case FIONBIO: | | 602 | case FIONBIO: |
603 | case FIOASYNC: | | 603 | case FIOASYNC: |
604 | return 0; | | 604 | return 0; |
605 | | | 605 | |
606 | #if 0 /* XXX why? */ | | 606 | #if 0 /* XXX why? */ |
607 | case SIOCSPGRP: | | 607 | case SIOCSPGRP: |
608 | case TIOCSPGRP: | | 608 | case TIOCSPGRP: |
609 | case FIOSETOWN: | | 609 | case FIOSETOWN: |
610 | return fsetown(&dev->buf_pgid, cmd, data); | | 610 | return fsetown(&dev->buf_pgid, cmd, data); |
611 | | | 611 | |
612 | case SIOCGPGRP: | | 612 | case SIOCGPGRP: |
613 | case TIOCGPGRP: | | 613 | case TIOCGPGRP: |
614 | case FIOGETOWN: | | 614 | case FIOGETOWN: |
615 | return fgetown(&dev->buf_pgid, cmd, data); | | 615 | return fgetown(&dev->buf_pgid, cmd, data); |
616 | #endif | | 616 | #endif |
617 | | | 617 | |
618 | default: | | 618 | default: |
619 | break; | | 619 | break; |
620 | } | | 620 | } |
621 | | | 621 | |
622 | if (IOCGROUP(cmd) != DRM_IOCTL_BASE) | | 622 | if (IOCGROUP(cmd) != DRM_IOCTL_BASE) |
623 | return EINVAL; | | 623 | return EINVAL; |
624 | | | 624 | |
625 | KASSERT(file != NULL); | | 625 | KASSERT(file != NULL); |
626 | KASSERT(file->minor != NULL); | | 626 | KASSERT(file->minor != NULL); |
627 | KASSERT(file->minor->dev != NULL); | | 627 | KASSERT(file->minor->dev != NULL); |
628 | struct drm_device *const dev = file->minor->dev; | | 628 | struct drm_device *const dev = file->minor->dev; |
629 | const struct drm_ioctl_desc *ioctl; | | 629 | const struct drm_ioctl_desc *ioctl; |
630 | | | 630 | |
631 | if ((DRM_COMMAND_BASE <= nr) && (nr < DRM_COMMAND_END)) { | | 631 | if ((DRM_COMMAND_BASE <= nr) && (nr < DRM_COMMAND_END)) { |
632 | const unsigned int driver_nr = nr - DRM_COMMAND_BASE; | | 632 | const unsigned int driver_nr = nr - DRM_COMMAND_BASE; |
633 | if (driver_nr >= dev->driver->num_ioctls) | | 633 | if (driver_nr >= dev->driver->num_ioctls) |
634 | return EINVAL; | | 634 | return EINVAL; |
635 | ioctl = &dev->driver->ioctls[driver_nr]; | | 635 | ioctl = &dev->driver->ioctls[driver_nr]; |
636 | } else if (nr < __arraycount(drm_ioctls)) { | | 636 | } else if (nr < __arraycount(drm_ioctls)) { |
637 | ioctl = &drm_ioctls[nr]; | | 637 | ioctl = &drm_ioctls[nr]; |
638 | } else { | | 638 | } else { |
639 | ioctl = NULL; | | 639 | ioctl = NULL; |
640 | } | | 640 | } |
641 | | | 641 | |
642 | if ((ioctl == NULL) || (ioctl->func == NULL)) | | 642 | if ((ioctl == NULL) || (ioctl->func == NULL)) |
643 | return EINVAL; | | 643 | return EINVAL; |
644 | | | 644 | |
| | | 645 | /* XXX Synchronize with drm_ioctl_permit in upstream drm_drv.c. */ |
645 | if (ISSET(ioctl->flags, DRM_ROOT_ONLY) && !DRM_SUSER()) | | 646 | if (ISSET(ioctl->flags, DRM_ROOT_ONLY) && !DRM_SUSER()) |
646 | return EACCES; | | 647 | return EACCES; |
647 | | | 648 | |
648 | if (ISSET(ioctl->flags, DRM_AUTH) && !file->authenticated) | | 649 | if (ISSET(ioctl->flags, DRM_AUTH) && |
| | | 650 | (file->minor->type != DRM_MINOR_RENDER) && |
| | | 651 | !file->authenticated) |
649 | return EACCES; | | 652 | return EACCES; |
650 | | | 653 | |
651 | if (ISSET(ioctl->flags, DRM_MASTER) && (file->master == NULL)) | | 654 | if (ISSET(ioctl->flags, DRM_MASTER) && |
| | | 655 | (file->master == NULL) && |
| | | 656 | (file->minor->type != DRM_MINOR_CONTROL)) |
652 | return EACCES; | | 657 | return EACCES; |
653 | | | 658 | |
654 | if (!ISSET(ioctl->flags, DRM_CONTROL_ALLOW) && | | 659 | if (!ISSET(ioctl->flags, DRM_CONTROL_ALLOW) && |
655 | (file->minor->type == DRM_MINOR_CONTROL)) | | 660 | (file->minor->type == DRM_MINOR_CONTROL)) |
656 | return EACCES; | | 661 | return EACCES; |
657 | | | 662 | |
| | | 663 | if (!ISSET(ioctl->flags, DRM_RENDER_ALLOW) && |
| | | 664 | (file->minor->type == DRM_MINOR_RENDER)) |
| | | 665 | return EACCES; |
| | | 666 | |
658 | if (!ISSET(ioctl->flags, DRM_UNLOCKED)) | | 667 | if (!ISSET(ioctl->flags, DRM_UNLOCKED)) |
659 | mutex_lock(&drm_global_mutex); | | 668 | mutex_lock(&drm_global_mutex); |
660 | | | 669 | |
661 | /* XXX errno Linux->NetBSD */ | | 670 | /* XXX errno Linux->NetBSD */ |
662 | error = -(*ioctl->func)(dev, data, file); | | 671 | error = -(*ioctl->func)(dev, data, file); |
663 | | | 672 | |
664 | if (!ISSET(ioctl->flags, DRM_UNLOCKED)) | | 673 | if (!ISSET(ioctl->flags, DRM_UNLOCKED)) |
665 | mutex_unlock(&drm_global_mutex); | | 674 | mutex_unlock(&drm_global_mutex); |
666 | | | 675 | |
667 | return error; | | 676 | return error; |
668 | } | | 677 | } |
669 | | | 678 | |
670 | static int | | 679 | static int |
671 | drm_fop_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, | | 680 | drm_fop_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, |
672 | int *advicep, struct uvm_object **uobjp, int *maxprotp) | | 681 | int *advicep, struct uvm_object **uobjp, int *maxprotp) |
673 | { | | 682 | { |
674 | struct drm_file *const file = fp->f_data; | | 683 | struct drm_file *const file = fp->f_data; |
675 | struct drm_device *const dev = file->minor->dev; | | 684 | struct drm_device *const dev = file->minor->dev; |
676 | int error; | | 685 | int error; |
677 | | | 686 | |
678 | KASSERT(fp == file->filp); | | 687 | KASSERT(fp == file->filp); |
679 | error = (*dev->driver->mmap_object)(dev, *offp, len, prot, uobjp, | | 688 | error = (*dev->driver->mmap_object)(dev, *offp, len, prot, uobjp, |
680 | offp, file->filp); | | 689 | offp, file->filp); |
681 | *maxprotp = prot; | | 690 | *maxprotp = prot; |
682 | *advicep = UVM_ADV_RANDOM; | | 691 | *advicep = UVM_ADV_RANDOM; |
683 | return -error; | | 692 | return -error; |
684 | } | | 693 | } |
685 | | | 694 | |
686 | static int | | 695 | static int |
687 | drm_version_string(char *target, size_t *lenp, const char *source) | | 696 | drm_version_string(char *target, size_t *lenp, const char *source) |
688 | { | | 697 | { |
689 | const size_t len = strlen(source); | | 698 | const size_t len = strlen(source); |
690 | const size_t trunc_len = MIN(len, *lenp); | | 699 | const size_t trunc_len = MIN(len, *lenp); |
691 | | | 700 | |
692 | *lenp = len; | | 701 | *lenp = len; |
693 | if ((trunc_len > 0) && (target != NULL)) | | 702 | if ((trunc_len > 0) && (target != NULL)) |
694 | /* copyoutstr takes a buffer size, not a string length. */ | | 703 | /* copyoutstr takes a buffer size, not a string length. */ |
695 | /* XXX errno NetBSD->Linux */ | | 704 | /* XXX errno NetBSD->Linux */ |
696 | return -copyoutstr(source, target, trunc_len+1, NULL); | | 705 | return -copyoutstr(source, target, trunc_len+1, NULL); |
697 | | | 706 | |
698 | return 0; | | 707 | return 0; |
699 | } | | 708 | } |
700 | | | 709 | |
701 | static int | | 710 | static int |
702 | drm_version(struct drm_device *dev, void *data, struct drm_file *file) | | 711 | drm_version(struct drm_device *dev, void *data, struct drm_file *file) |
703 | { | | 712 | { |
704 | struct drm_version *v = data; | | 713 | struct drm_version *v = data; |
705 | int error; | | 714 | int error; |
706 | | | 715 | |
707 | v->version_major = dev->driver->major; | | 716 | v->version_major = dev->driver->major; |
708 | v->version_minor = dev->driver->minor; | | 717 | v->version_minor = dev->driver->minor; |
709 | v->version_patchlevel = dev->driver->patchlevel; | | 718 | v->version_patchlevel = dev->driver->patchlevel; |
710 | | | 719 | |
711 | error = drm_version_string(v->name, &v->name_len, dev->driver->name); | | 720 | error = drm_version_string(v->name, &v->name_len, dev->driver->name); |
712 | if (error) | | 721 | if (error) |
713 | goto out; | | 722 | goto out; |
714 | error = drm_version_string(v->date, &v->date_len, dev->driver->date); | | 723 | error = drm_version_string(v->date, &v->date_len, dev->driver->date); |
715 | if (error) | | 724 | if (error) |
716 | goto out; | | 725 | goto out; |
717 | error = drm_version_string(v->desc, &v->desc_len, dev->driver->desc); | | 726 | error = drm_version_string(v->desc, &v->desc_len, dev->driver->desc); |
718 | if (error) | | 727 | if (error) |
719 | goto out; | | 728 | goto out; |
720 | | | 729 | |
721 | out: return error; | | 730 | out: return error; |
722 | } | | 731 | } |
723 | | | 732 | |
724 | static paddr_t | | 733 | static paddr_t |
725 | drm_mmap(dev_t d, off_t offset, int prot) | | 734 | drm_mmap(dev_t d, off_t offset, int prot) |
726 | { | | 735 | { |
727 | struct drm_minor *dminor; | | 736 | struct drm_minor *dminor; |
728 | paddr_t paddr; | | 737 | paddr_t paddr; |
729 | | | 738 | |
730 | dminor = drm_minor_acquire(minor(d)); | | 739 | dminor = drm_minor_acquire(minor(d)); |
731 | if (IS_ERR(dminor)) | | 740 | if (IS_ERR(dminor)) |
732 | return (paddr_t)-1; | | 741 | return (paddr_t)-1; |
733 | | | 742 | |
734 | paddr = drm_mmap_paddr(dminor->dev, offset, prot); | | 743 | paddr = drm_mmap_paddr(dminor->dev, offset, prot); |
735 | | | 744 | |
736 | drm_minor_release(dminor); | | 745 | drm_minor_release(dminor); |
737 | return paddr; | | 746 | return paddr; |
738 | } | | 747 | } |
739 | | | 748 | |
740 | static const struct drm_agp_hooks *volatile drm_current_agp_hooks; | | 749 | static const struct drm_agp_hooks *volatile drm_current_agp_hooks; |
741 | | | 750 | |
742 | int | | 751 | int |
743 | drm_agp_register(const struct drm_agp_hooks *hooks) | | 752 | drm_agp_register(const struct drm_agp_hooks *hooks) |
744 | { | | 753 | { |
745 | | | 754 | |
746 | membar_producer(); | | 755 | membar_producer(); |
747 | if (atomic_cas_ptr(&drm_current_agp_hooks, NULL, __UNCONST(hooks)) | | 756 | if (atomic_cas_ptr(&drm_current_agp_hooks, NULL, __UNCONST(hooks)) |
748 | != NULL) | | 757 | != NULL) |
749 | return EBUSY; | | 758 | return EBUSY; |
750 | | | 759 | |
751 | return 0; | | 760 | return 0; |
752 | } | | 761 | } |
753 | | | 762 | |
754 | void | | 763 | void |
755 | drm_agp_deregister(const struct drm_agp_hooks *hooks) | | 764 | drm_agp_deregister(const struct drm_agp_hooks *hooks) |
756 | { | | 765 | { |
757 | | | 766 | |
758 | if (atomic_cas_ptr(&drm_current_agp_hooks, __UNCONST(hooks), NULL) | | 767 | if (atomic_cas_ptr(&drm_current_agp_hooks, __UNCONST(hooks), NULL) |
759 | != hooks) | | 768 | != hooks) |
760 | panic("%s: wrong hooks: %p != %p", __func__, | | 769 | panic("%s: wrong hooks: %p != %p", __func__, |
761 | hooks, drm_current_agp_hooks); | | 770 | hooks, drm_current_agp_hooks); |
762 | } | | 771 | } |
763 | | | 772 | |
764 | static void __dead | | 773 | static void __dead |
765 | drm_noagp_panic(struct drm_device *dev) | | 774 | drm_noagp_panic(struct drm_device *dev) |
766 | { | | 775 | { |
767 | if ((dev != NULL) && | | 776 | if ((dev != NULL) && |
768 | (dev->control != NULL) && | | 777 | (dev->control != NULL) && |
769 | (dev->control->kdev != NULL)) | | 778 | (dev->control->kdev != NULL)) |
770 | panic("%s: no agp loaded", device_xname(dev->control->kdev)); | | 779 | panic("%s: no agp loaded", device_xname(dev->control->kdev)); |
771 | else | | 780 | else |
772 | panic("drm_device %p: no agp loaded", dev); | | 781 | panic("drm_device %p: no agp loaded", dev); |
773 | } | | 782 | } |
774 | | | 783 | |
775 | int | | 784 | int |
776 | drm_agp_release_hook(struct drm_device *dev) | | 785 | drm_agp_release_hook(struct drm_device *dev) |
777 | { | | 786 | { |
778 | const struct drm_agp_hooks *const hooks = drm_current_agp_hooks; | | 787 | const struct drm_agp_hooks *const hooks = drm_current_agp_hooks; |
779 | | | 788 | |
780 | if (hooks == NULL) | | 789 | if (hooks == NULL) |
781 | drm_noagp_panic(dev); | | 790 | drm_noagp_panic(dev); |
782 | membar_consumer(); | | 791 | membar_consumer(); |
783 | return (*hooks->agph_release)(dev); | | 792 | return (*hooks->agph_release)(dev); |
784 | } | | 793 | } |
785 | | | 794 | |
786 | void | | 795 | void |
787 | drm_agp_clear_hook(struct drm_device *dev) | | 796 | drm_agp_clear_hook(struct drm_device *dev) |
788 | { | | 797 | { |
789 | const struct drm_agp_hooks *const hooks = drm_current_agp_hooks; | | 798 | const struct drm_agp_hooks *const hooks = drm_current_agp_hooks; |
790 | | | 799 | |
791 | if (hooks == NULL) | | 800 | if (hooks == NULL) |
792 | drm_noagp_panic(dev); | | 801 | drm_noagp_panic(dev); |
793 | membar_consumer(); | | 802 | membar_consumer(); |
794 | (*hooks->agph_clear)(dev); | | 803 | (*hooks->agph_clear)(dev); |
795 | } | | 804 | } |
796 | | | 805 | |
797 | #define DEFINE_AGP_HOOK_IOCTL(NAME, HOOK) \ | | 806 | #define DEFINE_AGP_HOOK_IOCTL(NAME, HOOK) \ |
798 | static int \ | | 807 | static int \ |
799 | NAME(struct drm_device *dev, void *data, struct drm_file *file) \ | | 808 | NAME(struct drm_device *dev, void *data, struct drm_file *file) \ |
800 | { \ | | 809 | { \ |
801 | const struct drm_agp_hooks *const hooks = drm_current_agp_hooks; \ | | 810 | const struct drm_agp_hooks *const hooks = drm_current_agp_hooks; \ |
802 | \ | | 811 | \ |
803 | if (hooks == NULL) \ | | 812 | if (hooks == NULL) \ |
804 | return -ENODEV; \ | | 813 | return -ENODEV; \ |
805 | membar_consumer(); \ | | 814 | membar_consumer(); \ |
806 | return (*hooks->HOOK)(dev, data, file); \ | | 815 | return (*hooks->HOOK)(dev, data, file); \ |
807 | } | | 816 | } |
808 | | | 817 | |
809 | DEFINE_AGP_HOOK_IOCTL(drm_agp_acquire_hook_ioctl, agph_acquire_ioctl) | | 818 | DEFINE_AGP_HOOK_IOCTL(drm_agp_acquire_hook_ioctl, agph_acquire_ioctl) |
810 | DEFINE_AGP_HOOK_IOCTL(drm_agp_release_hook_ioctl, agph_release_ioctl) | | 819 | DEFINE_AGP_HOOK_IOCTL(drm_agp_release_hook_ioctl, agph_release_ioctl) |
811 | DEFINE_AGP_HOOK_IOCTL(drm_agp_enable_hook_ioctl, agph_enable_ioctl) | | 820 | DEFINE_AGP_HOOK_IOCTL(drm_agp_enable_hook_ioctl, agph_enable_ioctl) |
812 | DEFINE_AGP_HOOK_IOCTL(drm_agp_info_hook_ioctl, agph_info_ioctl) | | 821 | DEFINE_AGP_HOOK_IOCTL(drm_agp_info_hook_ioctl, agph_info_ioctl) |
813 | DEFINE_AGP_HOOK_IOCTL(drm_agp_alloc_hook_ioctl, agph_alloc_ioctl) | | 822 | DEFINE_AGP_HOOK_IOCTL(drm_agp_alloc_hook_ioctl, agph_alloc_ioctl) |
814 | DEFINE_AGP_HOOK_IOCTL(drm_agp_free_hook_ioctl, agph_free_ioctl) | | 823 | DEFINE_AGP_HOOK_IOCTL(drm_agp_free_hook_ioctl, agph_free_ioctl) |
815 | DEFINE_AGP_HOOK_IOCTL(drm_agp_bind_hook_ioctl, agph_bind_ioctl) | | 824 | DEFINE_AGP_HOOK_IOCTL(drm_agp_bind_hook_ioctl, agph_bind_ioctl) |
816 | DEFINE_AGP_HOOK_IOCTL(drm_agp_unbind_hook_ioctl, agph_unbind_ioctl) | | 825 | DEFINE_AGP_HOOK_IOCTL(drm_agp_unbind_hook_ioctl, agph_unbind_ioctl) |