1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * drm_irq.c -- IRQ IOCTL and function support 8 * Created: Fri Oct 18 2003 by anholt@FreeBSD.org 9 */ 10 /* 11 * Copyright 2003 Eric Anholt 12 * All Rights Reserved. 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a 15 * copy of this software and associated documentation files (the "Software"), 16 * to deal in the Software without restriction, including without limitation 17 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 * and/or sell copies of the Software, and to permit persons to whom the 19 * Software is furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice (including the next 22 * paragraph) shall be included in all copies or substantial portions of the 23 * Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 * 32 * Authors: 33 * Eric Anholt <anholt@FreeBSD.org> 34 * 35 */ 36 37 #pragma ident "%Z%%M% %I% %E% SMI" 38 39 #include "drmP.h" 40 #include "drm.h" 41 42 /*ARGSUSED*/ 43 int 44 drm_irq_by_busid(DRM_IOCTL_ARGS) 45 { 46 DRM_DEVICE; 47 drm_irq_busid_t irq; 48 49 DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof (irq)); 50 51 if ((irq.busnum >> 8) != dev->pci_domain || 52 (irq.busnum & 0xff) != dev->pci_bus || 53 irq.devnum != dev->pci_slot || 54 irq.funcnum != dev->pci_func) 55 return (DRM_ERR(EINVAL)); 56 57 irq.irq = dev->irq; 58 59 DRM_DEBUG("%x:%x:%x => IRQ %x\n", 60 irq.busnum, irq.devnum, irq.funcnum, irq.irq); 61 62 DRM_COPY_TO_USER_IOCTL((drm_irq_busid_t *)data, irq, sizeof (irq)); 63 64 return (0); 65 } 66 67 /*ARGSUSED*/ 68 static int 69 drm_install_irq_handle(drm_softstate_t *dev) 70 { 71 dev_info_t *dip = NULL; 72 73 dip = dev->dip; 74 if (dip == NULL) { 75 DRM_ERROR("drm_install_irq_handle: cannot get vgatext's dip"); 76 return (DDI_FAILURE); 77 } 78 79 if (ddi_intr_hilevel(dip, 0) != 0) { 80 DRM_ERROR("drm_install_irq_handle: " 81 "high-level interrupts are not supported"); 82 return (DDI_FAILURE); 83 } 84 85 if (ddi_get_iblock_cookie(dip, (uint_t)0, 86 &dev->intr_block) != DDI_SUCCESS) { 87 DRM_ERROR("drm_install_irq_handle: cannot get iblock cookie"); 88 return (DDI_FAILURE); 89 } 90 91 mutex_init(&dev->irq_lock, NULL, MUTEX_DRIVER, (void *)dev->intr_block); 92 93 /* setup the interrupt handler */ 94 95 if (ddi_add_intr(dip, 0, &dev->intr_block, 96 (ddi_idevice_cookie_t *)NULL, dev->irq_handler, 97 (caddr_t)dev) != DDI_SUCCESS) { 98 DRM_ERROR("drm_install_irq_handle: ddi_add_intr failed"); 99 return (DDI_FAILURE); 100 } 101 DRM_DEBUG("drm_install_irq_handle: add the intr handle successful"); 102 103 104 return (DDI_SUCCESS); 105 } 106 107 /*ARGSUSED*/ 108 int 109 drm_irq_install(drm_softstate_t *dev) 110 { 111 int ret; 112 113 if (dev->dev_private == NULL) { 114 DRM_ERROR("drm_irq_install: dev_private is NULL"); 115 return (DRM_ERR(EINVAL)); 116 } 117 118 if (dev->irq_enabled) { 119 DRM_ERROR("drm_irq_install: irq already enabled"); 120 return (DRM_ERR(EBUSY)); 121 } 122 123 dev->context_flag = 0; 124 125 /* before installing handler */ 126 dev->irq_preinstall(dev); 127 128 /* install handler */ 129 ret = drm_install_irq_handle(dev); 130 if (ret != DDI_SUCCESS) { 131 DRM_ERROR("drm_irq_install: drm_install_irq_handle failed"); 132 return (ret); 133 } 134 135 /* after installing handler */ 136 dev->irq_postinstall(dev); 137 138 dev->irq_enabled = 1; 139 140 return (DDI_SUCCESS); 141 } 142 143 static void 144 drm_uninstall_irq_handle(drm_device_t *dev) 145 { 146 ASSERT(dev->dip); 147 ddi_remove_intr(dev->dip, 0, dev->intr_block); 148 } 149 150 151 /*ARGSUSED*/ 152 int 153 drm_irq_uninstall(drm_softstate_t *dev) 154 { 155 156 dev->irq_enabled = 0; 157 158 dev->irq_uninstall(dev); 159 160 drm_uninstall_irq_handle(dev); 161 162 return (DDI_SUCCESS); 163 } 164 165 /*ARGSUSED*/ 166 int 167 drm_control(DRM_IOCTL_ARGS) 168 { 169 DRM_DEVICE; 170 drm_control_t ctl; 171 int err; 172 173 DRM_DEBUG("drm_control: install irq = %x\n", dev->irq); 174 DRM_COPY_FROM_USER_IOCTL(ctl, (drm_control_t *)data, sizeof (ctl)); 175 176 switch (ctl.func) { 177 case DRM_INST_HANDLER: 178 /* 179 * Handle drivers whose DRM used to require IRQ setup but the 180 * no longer does. 181 */ 182 return (drm_irq_install(dev)); 183 case DRM_UNINST_HANDLER: 184 err = drm_irq_uninstall(dev); 185 return (err); 186 default: 187 return (DRM_ERR(EINVAL)); 188 } 189 } 190 191 /*ARGSUSED*/ 192 int 193 drm_wait_vblank(DRM_IOCTL_ARGS) 194 { 195 return (0); 196 } 197