]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/drm/drm_irq.h
move ptr deref's to after null checks
[FreeBSD/FreeBSD.git] / sys / dev / drm / drm_irq.h
1 /* drm_dma.c -- DMA IOCTL and function support
2  * Created: Fri Oct 18 2003 by anholt@FreeBSD.org */
3 /*-
4  * Copyright 2003 Eric Anholt
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * Authors:
27  *    Eric Anholt <anholt@FreeBSD.org>
28  *
29  * $FreeBSD$
30  */
31
32 int DRM(irq_by_busid)( DRM_IOCTL_ARGS )
33 {
34         DRM_DEVICE;
35         drm_irq_busid_t irq;
36
37         DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq));
38
39         if ((irq.busnum >> 8) != dev->pci_domain ||
40             (irq.busnum & 0xff) != dev->pci_bus ||
41             irq.devnum != dev->pci_slot ||
42             irq.funcnum != dev->pci_func)
43                 return EINVAL;
44
45         irq.irq = dev->irq;
46
47         DRM_DEBUG("%d:%d:%d => IRQ %d\n",
48                   irq.busnum, irq.devnum, irq.funcnum, irq.irq);
49
50         DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) );
51
52         return 0;
53 }
54
55 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
56 static irqreturn_t
57 DRM(irq_handler_wrap)(DRM_IRQ_ARGS)
58 {
59         drm_device_t *dev = (drm_device_t *)arg;
60
61         DRM_SPINLOCK(&dev->irq_lock);
62         DRM(irq_handler)(arg);
63         DRM_SPINUNLOCK(&dev->irq_lock);
64 }
65 #endif
66
67 int DRM(irq_install)(drm_device_t *dev)
68 {
69         int retcode;
70
71         if (dev->irq == 0 || dev->dev_private == NULL)
72                 return DRM_ERR(EINVAL);
73
74         DRM_LOCK();
75         if (dev->irq_enabled) {
76                 DRM_UNLOCK();
77                 return DRM_ERR(EBUSY);
78         }
79         dev->irq_enabled = 1;
80         DRM_UNLOCK();
81
82         DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
83
84         dev->context_flag = 0;
85
86         dev->dma->next_buffer = NULL;
87         dev->dma->this_buffer = NULL;
88
89 #if __HAVE_IRQ_BH
90         TASK_INIT(&dev->task, 0, DRM(dma_immediate_bh), dev);
91 #endif
92
93         DRM_SPININIT(dev->irq_lock, "DRM IRQ lock");
94
95                                 /* Before installing handler */
96         DRM(driver_irq_preinstall)( dev );
97
98                                 /* Install handler */
99 #ifdef __FreeBSD__
100         dev->irqrid = 0;
101         dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ, 
102                                       &dev->irqrid, RF_SHAREABLE);
103         if (!dev->irqr) {
104                 retcode = ENOENT;
105                 goto err;
106         }
107 #if __FreeBSD_version < 500000
108         retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY,
109                                  DRM(irq_handler), dev, &dev->irqh);
110 #else
111         retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE,
112                                  DRM(irq_handler_wrap), dev, &dev->irqh);
113 #endif
114         if (retcode != 0)
115                 goto err;
116 #elif defined(__NetBSD__)
117         if (pci_intr_map(&dev->pa, &dev->ih) != 0) {
118                 retcode = ENOENT;
119                 goto err;
120         }
121         dev->irqh = pci_intr_establish(&dev->pa.pa_pc, dev->ih, IPL_TTY,
122             (irqreturn_t (*)(DRM_IRQ_ARGS))DRM(irq_handler), dev);
123         if (!dev->irqh) {
124                 retcode = ENOENT;
125                 goto err;
126         }
127 #endif
128
129                                 /* After installing handler */
130         DRM(driver_irq_postinstall)( dev );
131
132         return 0;
133 err:
134         DRM_LOCK();
135         dev->irq_enabled = 0;
136 #ifdef ___FreeBSD__
137         if (dev->irqrid != 0) {
138                 bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
139                     dev->irqr);
140                 dev->irqrid = 0;
141         }
142 #endif
143         DRM_SPINUNINIT(dev->irq_lock);
144         DRM_UNLOCK();
145         return retcode;
146 }
147
148 /* XXX: This function needs to be called with the device lock held.  In some
149  * cases it isn't, so far.
150  */
151 int DRM(irq_uninstall)( drm_device_t *dev )
152 {
153         int irqrid;
154
155         if (!dev->irq_enabled)
156                 return DRM_ERR(EINVAL);
157
158         dev->irq_enabled = 0;
159         irqrid = dev->irqrid;
160         dev->irqrid = 0;
161
162         DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
163
164         DRM(driver_irq_uninstall)( dev );
165
166 #ifdef __FreeBSD__
167         bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
168         bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr);
169 #elif defined(__NetBSD__)
170         pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
171 #endif
172         DRM_SPINUNINIT(dev->irq_lock);
173
174         return 0;
175 }
176
177 int DRM(control)( DRM_IOCTL_ARGS )
178 {
179         DRM_DEVICE;
180         drm_control_t ctl;
181         int err;
182
183         DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
184
185         switch ( ctl.func ) {
186         case DRM_INST_HANDLER:
187                 if (dev->if_version < DRM_IF_VERSION(1, 2) &&
188                     ctl.irq != dev->irq)
189                         return DRM_ERR(EINVAL);
190                 return DRM(irq_install)(dev);
191         case DRM_UNINST_HANDLER:
192                 DRM_LOCK();
193                 err = DRM(irq_uninstall)( dev );
194                 DRM_UNLOCK();
195                 return err;
196         default:
197                 return DRM_ERR(EINVAL);
198         }
199 }
200
201 #if __HAVE_VBL_IRQ
202 int DRM(wait_vblank)( DRM_IOCTL_ARGS )
203 {
204         DRM_DEVICE;
205         drm_wait_vblank_t vblwait;
206         struct timeval now;
207         int ret;
208
209         if (!dev->irq_enabled)
210                 return DRM_ERR(EINVAL);
211
212         DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
213                                   sizeof(vblwait) );
214
215         if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
216                 vblwait.request.sequence += atomic_read(&dev->vbl_received);
217                 vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
218         }
219
220         flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
221         if (flags & _DRM_VBLANK_SIGNAL) {
222 #if 0 /* disabled */
223                 drm_vbl_sig_t *vbl_sig = DRM_MALLOC(sizeof(drm_vbl_sig_t));
224                 if (vbl_sig == NULL)
225                         return ENOMEM;
226                 bzero(vbl_sig, sizeof(*vbl_sig));
227                 
228                 vbl_sig->sequence = vblwait.request.sequence;
229                 vbl_sig->signo = vblwait.request.signal;
230                 vbl_sig->pid = DRM_CURRENTPID;
231
232                 vblwait.reply.sequence = atomic_read(&dev->vbl_received);
233                 
234                 DRM_SPINLOCK(&dev->irq_lock);
235                 TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
236                 DRM_SPINUNLOCK(&dev->irq_lock);
237                 ret = 0;
238 #endif
239                 ret = EINVAL;
240         } else {
241                 ret = DRM(vblank_wait)(dev, &vblwait.request.sequence);
242                 
243                 microtime(&now);
244                 vblwait.reply.tval_sec = now.tv_sec;
245                 vblwait.reply.tval_usec = now.tv_usec;
246         }
247
248         DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
249                                 sizeof(vblwait) );
250
251         return ret;
252 }
253
254 void DRM(vbl_send_signals)(drm_device_t *dev)
255 {
256 }
257
258 #if 0 /* disabled */
259 void DRM(vbl_send_signals)( drm_device_t *dev )
260 {
261         drm_vbl_sig_t *vbl_sig;
262         unsigned int vbl_seq = atomic_read( &dev->vbl_received );
263         struct proc *p;
264
265         vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
266         while (vbl_sig != NULL) {
267                 drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
268
269                 if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
270                         p = pfind(vbl_sig->pid);
271                         if (p != NULL)
272                                 psignal(p, vbl_sig->signo);
273
274                         TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
275                         DRM_FREE(vbl_sig,sizeof(*vbl_sig));
276                 }
277                 vbl_sig = next;
278         }
279 }
280 #endif
281
282 #endif /*  __HAVE_VBL_IRQ */