1450N/A/*
1450N/A * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
1450N/A *
1450N/A * Permission is hereby granted, free of charge, to any person obtaining a
1450N/A * copy of this software and associated documentation files (the "Software"),
1450N/A * to deal in the Software without restriction, including without limitation
1450N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1450N/A * and/or sell copies of the Software, and to permit persons to whom the
1450N/A * Software is furnished to do so, subject to the following conditions:
1450N/A *
1450N/A * The above copyright notice and this permission notice (including the next
1450N/A * paragraph) shall be included in all copies or substantial portions of the
1450N/A * Software.
1450N/A *
1450N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1450N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1450N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1450N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1450N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1450N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1450N/A * DEALINGS IN THE SOFTWARE.
1450N/A */
1450N/A
1450N/A/*
1450N/A * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
1450N/A */
1450N/A
1450N/A/*
1450N/A * Common misc module interfaces of DRM under Solaris
1450N/A */
1450N/A
1450N/A/*
1450N/A * This module calls into gfx and agpmaster misc modules respectively
1450N/A * for generic graphics operations and AGP master device support.
1450N/A */
1450N/A
1450N/A#include "drm_sunmod.h"
1450N/A#include "drm_sun_idr.h"
1450N/A#include <sys/modctl.h>
1450N/A#include <sys/kmem.h>
1450N/A#include <vm/seg_kmem.h>
1450N/A
1450N/Aint drm_debug_flag = 0;
1450N/Aint mdb_track_enable = B_FALSE;
1450N/A
1450N/A/* Identifier of this driver */
1450N/Astatic struct vis_identifier text_ident = { "SUNWdrm" };
1450N/A
1450N/Astatic ddi_device_acc_attr_t dev_attr = {
1450N/A DDI_DEVICE_ATTR_V0,
1450N/A DDI_NEVERSWAP_ACC,
1450N/A DDI_STRICTORDER_ACC,
1450N/A DDI_FLAGERR_ACC
1450N/A};
1450N/A
1450N/Astatic ddi_device_acc_attr_t gem_dev_attr = {
1450N/A DDI_DEVICE_ATTR_V0,
1450N/A DDI_NEVERSWAP_ACC,
1450N/A DDI_MERGING_OK_ACC,
1450N/A DDI_FLAGERR_ACC
1450N/A};
1450N/A
1450N/Aextern int __init drm_core_init(void);
1450N/Aextern void __exit drm_core_exit(void);
1450N/Aextern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
1450N/A
1450N/Astruct find_gem_object {
1450N/A offset_t offset;
1450N/A struct drm_gem_object *obj;
1450N/A};
1450N/A
1450N/Astatic int
1450N/Adrm_devmap_map(devmap_cookie_t dhc, dev_t dev_id, uint_t flags,
1450N/A offset_t offset, size_t len, void **new_priv)
1450N/A{
1450N/A _NOTE(ARGUNUSED(offset, len))
1450N/A
1450N/A devmap_handle_t *dhp;
1450N/A struct ddi_umem_cookie *cp;
1450N/A struct drm_minor *minor;
1450N/A struct drm_device *dev;
1450N/A int minor_id;
1450N/A
1450N/A minor_id = DRM_DEV2MINOR(dev_id);
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A dev = minor->dev;
1450N/A
1450N/A /*
1450N/A * This driver only supports MAP_SHARED,
1450N/A * and doesn't support MAP_PRIVATE
1450N/A */
1450N/A if (flags & MAP_PRIVATE) {
1450N/A DRM_ERROR("Not support MAP_PRIVATE");
1450N/A return (EINVAL);
1450N/A }
1450N/A
1450N/A mutex_enter(&dev->struct_mutex);
1450N/A dhp = (devmap_handle_t *)dhc;
1450N/A cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
1450N/A cp->cook_refcnt = 1;
1450N/A mutex_exit(&dev->struct_mutex);
1450N/A
1450N/A *new_priv = dev;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhc,
1450N/A void **new_pvtp)
1450N/A{
1450N/A _NOTE(ARGUNUSED(new_dhc))
1450N/A
1450N/A struct drm_device *dev = (struct drm_device *)pvtp;
1450N/A devmap_handle_t *dhp;
1450N/A struct ddi_umem_cookie *cp;
1450N/A
1450N/A mutex_enter(&dev->struct_mutex);
1450N/A dhp = (devmap_handle_t *)dhc;
1450N/A cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
1450N/A cp->cook_refcnt++;
1450N/A mutex_exit(&dev->struct_mutex);
1450N/A
1450N/A *new_pvtp = dev;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic void
1450N/Adrm_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len,
1450N/A devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2,
1450N/A void **new_pvtp2)
1450N/A{
1450N/A _NOTE(ARGUNUSED(off, len))
1450N/A
1450N/A struct drm_device *dev;
1450N/A devmap_handle_t *dhp;
1450N/A devmap_handle_t *ndhp;
1450N/A struct ddi_umem_cookie *cp;
1450N/A struct ddi_umem_cookie *ncp;
1450N/A
1450N/A dhp = (devmap_handle_t *)dhc;
1450N/A dev = (struct drm_device *)pvtp;
1450N/A
1450N/A mutex_enter(&dev->struct_mutex);
1450N/A
1450N/A cp = (struct ddi_umem_cookie *)dhp->dh_cookie;
1450N/A if (new_dhp1 != NULL) {
1450N/A ndhp = (devmap_handle_t *)new_dhp1;
1450N/A ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
1450N/A ncp->cook_refcnt++;
1450N/A *new_pvtp1 = dev;
1450N/A ASSERT(ncp == cp);
1450N/A }
1450N/A
1450N/A if (new_dhp2 != NULL) {
1450N/A ndhp = (devmap_handle_t *)new_dhp2;
1450N/A ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie;
1450N/A ncp->cook_refcnt++;
1450N/A *new_pvtp2 = dev;
1450N/A ASSERT(ncp == cp);
1450N/A }
1450N/A
1450N/A /* FIXME: dh_cookie should not be released here. */
1450N/A#if 0
1450N/A cp->cook_refcnt--;
1450N/A if (cp->cook_refcnt == 0) {
1450N/A gfxp_umem_cookie_destroy(dhp->dh_cookie);
1450N/A dhp->dh_cookie = NULL;
1450N/A }
1450N/A#endif
1450N/A
1450N/A mutex_exit(&dev->struct_mutex);
1450N/A}
1450N/A
1450N/Astatic struct devmap_callback_ctl drm_devmap_callbacks = {
1450N/A DEVMAP_OPS_REV, /* devmap_rev */
1450N/A drm_devmap_map, /* devmap_map */
1450N/A NULL, /* devmap_access */
1450N/A drm_devmap_dup, /* devmap_dup */
1450N/A drm_devmap_unmap /* devmap_unmap */
1450N/A};
1450N/A
1450N/Astatic struct drm_local_map *
1450N/A__find_local_map(struct drm_device *dev, offset_t offset)
1450N/A{
1450N/A struct drm_map_list *entry;
1450N/A
1450N/A entry = idr_find(&dev->map_idr, offset >> PAGE_SHIFT);
1450N/A if (entry)
1450N/A return (entry->map);
1450N/A
1450N/A return (NULL);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_gem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags, offset_t off,
1450N/A size_t len, void **pvtp)
1450N/A{
1450N/A _NOTE(ARGUNUSED(dhp, flags, len))
1450N/A
1450N/A struct drm_device *drm_dev;
1450N/A struct drm_minor *minor;
1450N/A int minor_id = DRM_DEV2MINOR(dev);
1450N/A drm_local_map_t *map = NULL;
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A drm_dev = minor->dev;
1450N/A
1450N/A mutex_enter(&drm_dev->struct_mutex);
1450N/A map = __find_local_map(drm_dev, off);
1450N/A if (!map) {
1450N/A mutex_exit(&drm_dev->struct_mutex);
1450N/A *pvtp = NULL;
1450N/A return (DDI_EINVAL);
1450N/A }
1450N/A
1450N/A mutex_exit(&drm_dev->struct_mutex);
1450N/A
1450N/A *pvtp = map->handle;
1450N/A
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_gem_map_access(devmap_cookie_t dhp, void *pvt, offset_t offset, size_t len,
1450N/A uint_t type, uint_t rw)
1450N/A{
1450N/A struct drm_device *dev;
1450N/A struct drm_gem_object *obj;
1450N/A struct gem_map_list *seg;
1450N/A
1450N/A obj = (struct drm_gem_object *)pvt;
1450N/A if (obj == NULL) {
1450N/A goto next;
1450N/A }
1450N/A
1450N/A dev = obj->dev;
1450N/A if (dev->driver->gem_fault != NULL)
1450N/A dev->driver->gem_fault(obj);
1450N/A
1450N/Anext:
1450N/A if (devmap_load(dhp, offset, len, type, rw)) {
1450N/A return (DDI_FAILURE);
1450N/A }
1450N/A if (obj != NULL) {
1450N/A seg = drm_alloc(sizeof (struct gem_map_list), DRM_MEM_MAPS);
1450N/A if (seg != NULL) {
1450N/A mutex_lock(&dev->page_fault_lock);
1450N/A seg->dhp = dhp;
1450N/A seg->mapoffset = offset;
1450N/A seg->maplen = len;
1450N/A list_add_tail(&seg->head, &obj->seg_list, (caddr_t)seg);
1450N/A mutex_unlock(&dev->page_fault_lock);
1450N/A }
1450N/A }
1450N/A return (DDI_SUCCESS);
1450N/A}
1450N/A
1450N/Astatic void
1450N/Adrm_gem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, size_t len,
1450N/A devmap_cookie_t new_dhp1, void **newpvtp1,
1450N/A devmap_cookie_t new_dhp2, void **newpvtp2)
1450N/A{
1450N/A struct drm_device *dev;
1450N/A struct drm_gem_object *obj;
1450N/A struct gem_map_list *entry, *temp;
1450N/A
1450N/A _NOTE(ARGUNUSED(dhp, pvtp, off, len, new_dhp1, newpvtp1))
1450N/A _NOTE(ARGUNUSED(new_dhp2, newpvtp2))
1450N/A
1450N/A obj = (struct drm_gem_object *)pvtp;
1450N/A if (obj == NULL)
1450N/A return;
1450N/A
1450N/A dev = obj->dev;
1450N/A
1450N/A mutex_lock(&dev->page_fault_lock);
1450N/A if (list_empty(&obj->seg_list)) {
1450N/A mutex_unlock(&dev->page_fault_lock);
1450N/A return;
1450N/A }
1450N/A
1450N/A list_for_each_entry_safe(entry, temp, struct gem_map_list,
1450N/A &obj->seg_list, head) {
1450N/A (void) devmap_unload(entry->dhp, entry->mapoffset,
1450N/A entry->maplen);
1450N/A list_del(&entry->head);
1450N/A drm_free(entry, sizeof (struct gem_map_list), DRM_MEM_MAPS);
1450N/A }
1450N/A
1450N/A mutex_unlock(&dev->page_fault_lock);
1450N/A}
1450N/A
1450N/Astatic struct devmap_callback_ctl drm_gem_map_ops = {
1450N/A DEVMAP_OPS_REV, /* devmap_ops version number */
1450N/A drm_gem_map, /* devmap_ops map routine */
1450N/A drm_gem_map_access, /* devmap_ops access routine */
1450N/A NULL, /* devmap_ops dup routine */
1450N/A drm_gem_unmap, /* devmap_ops unmap routine */
1450N/A};
1450N/A
1450N/Astatic int
1450N/A__devmap_general(struct drm_device *dev, devmap_cookie_t dhp,
1450N/A struct drm_local_map *map, size_t len, size_t *maplen)
1450N/A{
1450N/A off_t regoff;
1450N/A int regno, ret;
1450N/A
1450N/A regno = drm_get_pci_index_reg(dev->devinfo,
1450N/A map->offset, (uint_t)len, &regoff);
1450N/A if (regno < 0) {
1450N/A DRM_ERROR("drm_get_pci_index_reg() failed");
1450N/A return (-EINVAL);
1450N/A }
1450N/A
1450N/A ret = devmap_devmem_setup(dhp, dev->devinfo, NULL,
1450N/A regno, (offset_t)regoff, len, PROT_ALL,
1450N/A 0, &dev_attr);
1450N/A if (ret != DDI_SUCCESS) {
1450N/A DRM_ERROR("devmap_devmem_setup failed, ret=%d", ret);
1450N/A return (-EFAULT);
1450N/A }
1450N/A
1450N/A *maplen = len;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/A__devmap_shm(struct drm_device *dev, devmap_cookie_t dhp,
1450N/A struct drm_local_map *map, size_t len, size_t *maplen)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A if (!map->umem_cookie)
1450N/A return (-EINVAL);
1450N/A
1450N/A len = ptob(btopr(map->size));
1450N/A
1450N/A ret = devmap_umem_setup(dhp, dev->devinfo,
1450N/A NULL, map->umem_cookie, 0, len, PROT_ALL,
1450N/A IOMEM_DATA_CACHED, NULL);
1450N/A if (ret != DDI_SUCCESS) {
1450N/A DRM_ERROR("devmap_umem_setup failed, ret=%d", ret);
1450N/A return (-EFAULT);
1450N/A }
1450N/A
1450N/A *maplen = len;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/A__devmap_agp(struct drm_device *dev, devmap_cookie_t dhp,
1450N/A struct drm_local_map *map, size_t len, size_t *maplen)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A if (dev->agp == NULL) {
1450N/A DRM_ERROR("attempted to mmap AGP"
1450N/A "memory before AGP support is enabled");
1450N/A return (-ENODEV);
1450N/A }
1450N/A
1450N/A len = ptob(btopr(len));
1450N/A
1450N/A ret = devmap_umem_setup(dhp, dev->devinfo,
1450N/A &drm_devmap_callbacks, map->umem_cookie, 0, len, PROT_ALL,
1450N/A IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
1450N/A if (ret != DDI_SUCCESS) {
1450N/A DRM_ERROR("devmap_umem_setup() failed, ret=%d", ret);
1450N/A return (-EFAULT);
1450N/A }
1450N/A
1450N/A *maplen = len;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/A__devmap_sg(struct drm_device *dev, devmap_cookie_t dhp,
1450N/A struct drm_local_map *map, size_t len, size_t *maplen)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A len = ptob(btopr(len));
1450N/A if (len > map->size) {
1450N/A DRM_ERROR("offset=0x%lx, virtual=0x%p, "
1450N/A "mapsize=0x%lx, len=0x%lx",
1450N/A map->offset, dev->sg->virtual, map->size, len);
1450N/A return (-EINVAL);
1450N/A }
1450N/A
1450N/A ret = devmap_umem_setup(dhp, dev->devinfo,
1450N/A &drm_devmap_callbacks, map->umem_cookie, 0, len, PROT_ALL,
1450N/A IOMEM_DATA_UNCACHED | DEVMAP_ALLOW_REMAP, &dev_attr);
1450N/A if (ret != DDI_SUCCESS) {
1450N/A DRM_ERROR("devmap_umem_setup() fail");
1450N/A return (-EFAULT);
1450N/A }
1450N/A
1450N/A *maplen = len;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/A__devmap_gem(struct drm_device *dev, devmap_cookie_t dhp,
1450N/A struct drm_local_map *map, size_t *maplen)
1450N/A{
1450N/A struct devmap_callback_ctl *callbackops = NULL;
1450N/A int ret;
1450N/A
1450N/A if (map->callback == 1) {
1450N/A callbackops = &drm_gem_map_ops;
1450N/A }
1450N/A
1450N/A if (!map->umem_cookie)
1450N/A return (-EINVAL);
1450N/A
1450N/A ret = gfxp_devmap_umem_setup(dhp, dev->devinfo, callbackops,
1450N/A map->umem_cookie, 0, map->size, PROT_ALL,
1450N/A IOMEM_DATA_UC_WR_COMBINE | DEVMAP_ALLOW_REMAP, &gem_dev_attr);
1450N/A if (ret != DDI_SUCCESS) {
1450N/A DRM_ERROR("gfxp_devmap_umem_setup failed, ret=%d", ret);
1450N/A return (-EFAULT);
1450N/A }
1450N/A
1450N/A *maplen = map->size;
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_sun_open(dev_t *dev_id, int flag, int otyp, cred_t *credp)
1450N/A{
1450N/A _NOTE(ARGUNUSED(otyp))
1450N/A
1450N/A int minor_id = DRM_DEV2MINOR(*dev_id);
1450N/A struct drm_minor *minor;
1450N/A int clone_id;
1450N/A int ret;
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A /*
1450N/A * No operations for VGA & AGP mater devices, always return OK.
1450N/A */
1450N/A if (DRM_MINOR_IS_VGATEXT(minor_id))
1450N/A return (0);
1450N/A
1450N/A if (DRM_MINOR_IS_AGPMASTER(minor_id))
1450N/A return (0);
1450N/A
1450N/A /*
1450N/A * Drm driver implements a software lock to serialize access
1450N/A * to graphics hardware based on per-process granulation. Before
1450N/A * operating graphics hardware, all clients, including kernel
1450N/A * and applications, must acquire this lock via DRM_IOCTL_LOCK
1450N/A * ioctl, and release it via DRM_IOCTL_UNLOCK after finishing
1450N/A * operations. Drm driver will grant r/w permission to the
1450N/A * process which acquires this lock (Kernel is assumed to have
1450N/A * process ID 0).
1450N/A *
1450N/A * A process might be terminated without releasing drm lock, in
1450N/A * this case, drm driver is responsible for clearing the holding.
1450N/A * To be informed of process exiting, drm driver uses clone open
1450N/A * to guarantee that each call to open(9e) have one corresponding
1450N/A * call to close(9e). In most cases, a process will close drm
1450N/A * during process termination, so that drm driver could have a
1450N/A * chance to release drm lock.
1450N/A *
1450N/A * In fact, a driver cannot know exactly when a process exits.
1450N/A * Clone open doesn't address this issue completely: Because of
1450N/A * inheritance, child processes inherit file descriptors from
1450N/A * their parent. As a result, if the parent exits before its
1450N/A * children, drm close(9e) entrypoint won't be called until all
1450N/A * of its children terminate.
1450N/A *
1450N/A * Another issue brought up by inhertance is the process PID
1450N/A * that calls the drm close() entry point may not be the same
1450N/A * as the one who called open(). Per-process struct is allocated
1450N/A * when a process first open() drm, and released when the process
1450N/A * last close() drm. Since open()/close() may be not the same
1450N/A * process, PID cannot be used for key to lookup per-process
1450N/A * struct. So, we associate minor number with per-process struct
1450N/A * during open()'ing, and find corresponding process struct
1450N/A * via minor number when close() is called.
1450N/A */
1450N/A ret = idr_get_new_above(&minor->clone_idr, NULL, 0, &clone_id);
1450N/A if (ret)
1450N/A return (EMFILE);
1450N/A
1450N/A if (clone_id > DRM_CLONEID_MAX) {
1450N/A (void) idr_remove(&minor->clone_idr, clone_id);
1450N/A return (EMFILE);
1450N/A }
1450N/A
1450N/A ret = drm_open(minor, clone_id, flag, credp);
1450N/A if (ret) {
1450N/A (void) idr_remove(&minor->clone_idr, clone_id);
1450N/A return (-ret);
1450N/A }
1450N/A
1450N/A *dev_id = DRM_MAKEDEV(getmajor(*dev_id), minor_id, clone_id);
1450N/A
1450N/A return (-ret);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_sun_close(dev_t dev_id, int flag, int otyp, cred_t *credp)
1450N/A{
1450N/A _NOTE(ARGUNUSED(flag, otyp, credp))
1450N/A
1450N/A struct drm_minor *minor;
1450N/A struct drm_file *file_priv;
1450N/A int minor_id = DRM_DEV2MINOR(dev_id);
1450N/A int clone_id = DRM_DEV2CLONEID(dev_id);
1450N/A int ret = 0;
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A /*
1450N/A * No operations for VGA & AGP mater devices, always return OK.
1450N/A */
1450N/A if (DRM_MINOR_IS_VGATEXT(minor_id))
1450N/A return (0);
1450N/A
1450N/A if (DRM_MINOR_IS_AGPMASTER(minor_id))
1450N/A return (0);
1450N/A
1450N/A file_priv = idr_find(&minor->clone_idr, clone_id);
1450N/A if (!file_priv)
1450N/A return (EBADF);
1450N/A
1450N/A ret = drm_release(file_priv);
1450N/A if (ret)
1450N/A return (-ret);
1450N/A
1450N/A (void) idr_remove(&minor->clone_idr, clone_id);
1450N/A
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_sun_ioctl(dev_t dev_id, int cmd, intptr_t arg, int mode, cred_t *credp,
1450N/A int *rvalp)
1450N/A{
1450N/A struct drm_minor *minor;
1450N/A struct drm_file *file_priv;
1450N/A int minor_id = DRM_DEV2MINOR(dev_id);
1450N/A int clone_id = DRM_DEV2CLONEID(dev_id);
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A if (cmd == VIS_GETIDENTIFIER) {
1450N/A if (ddi_copyout(&text_ident, (void *)arg,
1450N/A sizeof (struct vis_identifier), mode))
1450N/A return (EFAULT);
1450N/A }
1450N/A
1450N/A if (DRM_MINOR_IS_VGATEXT(minor_id))
1450N/A return (gfxp_vgatext_ioctl(dev_id, cmd, arg, mode, credp,
1450N/A rvalp, minor->private));
1450N/A
1450N/A if (DRM_MINOR_IS_AGPMASTER(minor_id))
1450N/A return (agpmaster_ioctl(dev_id, cmd, arg, mode, credp,
1450N/A rvalp, minor->private));
1450N/A
1450N/A file_priv = idr_find(&minor->clone_idr, clone_id);
1450N/A if (!file_priv)
1450N/A return (EBADF);
1450N/A
1450N/A return (-(drm_ioctl(dev_id, file_priv, cmd, arg, mode, credp)));
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_sun_devmap(dev_t dev_id, devmap_cookie_t dhp, offset_t offset,
1450N/A size_t len, size_t *maplen, uint_t model)
1450N/A{
1450N/A struct drm_device *dev;
1450N/A struct drm_minor *minor;
1450N/A struct drm_file *file_priv;
1450N/A int minor_id = DRM_DEV2MINOR(dev_id);
1450N/A int clone_id = DRM_DEV2CLONEID(dev_id);
1450N/A drm_local_map_t *map = NULL;
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A dev = minor->dev;
1450N/A
1450N/A if (DRM_MINOR_IS_VGATEXT(minor_id))
1450N/A return (gfxp_vgatext_devmap(dev_id, dhp, offset, len,
1450N/A maplen, model, minor->private));
1450N/A
1450N/A if (DRM_MINOR_IS_AGPMASTER(minor_id))
1450N/A return (ENOTSUP);
1450N/A
1450N/A file_priv = idr_find(&minor->clone_idr, clone_id);
1450N/A if (!file_priv)
1450N/A return (EBADF);
1450N/A
1450N/A mutex_enter(&dev->struct_mutex);
1450N/A map = __find_local_map(dev, offset);
1450N/A if (!map) {
1450N/A mutex_exit(&dev->struct_mutex);
1450N/A return (EFAULT);
1450N/A }
1450N/A if (map->flags & _DRM_RESTRICTED) {
1450N/A mutex_exit(&dev->struct_mutex);
1450N/A return (ENOTSUP);
1450N/A }
1450N/A mutex_exit(&dev->struct_mutex);
1450N/A
1450N/A switch (map->type) {
1450N/A case _DRM_FRAME_BUFFER:
1450N/A case _DRM_REGISTERS:
1450N/A return (__devmap_general(dev, dhp, map, len, maplen));
1450N/A
1450N/A case _DRM_SHM:
1450N/A return (__devmap_shm(dev, dhp, map, len, maplen));
1450N/A
1450N/A case _DRM_AGP:
1450N/A return (__devmap_agp(dev, dhp, map, len, maplen));
1450N/A
1450N/A case _DRM_SCATTER_GATHER:
1450N/A return (__devmap_sg(dev, dhp, map, len, maplen));
1450N/A
1450N/A case _DRM_GEM:
1450N/A return (__devmap_gem(dev, dhp, map, maplen));
1450N/A }
1450N/A
1450N/A return (ENOTSUP);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_sun_read(dev_t dev_id, struct uio *uiop, cred_t *credp)
1450N/A{
1450N/A _NOTE(ARGUNUSED(credp))
1450N/A
1450N/A struct drm_minor *minor;
1450N/A struct drm_file *file_priv;
1450N/A int minor_id = DRM_DEV2MINOR(dev_id);
1450N/A int clone_id = DRM_DEV2CLONEID(dev_id);
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A /*
1450N/A * No operations for VGA & AGP master devices, always return OK.
1450N/A */
1450N/A if (DRM_MINOR_IS_VGATEXT(minor_id))
1450N/A return (0);
1450N/A
1450N/A if (DRM_MINOR_IS_AGPMASTER(minor_id))
1450N/A return (0);
1450N/A
1450N/A file_priv = idr_find(&minor->clone_idr, clone_id);
1450N/A if (!file_priv)
1450N/A return (EBADF);
1450N/A
1450N/A (void) drm_read(file_priv, uiop);
1450N/A return (0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Adrm_sun_chpoll(dev_t dev_id, short events, int anyyet, short *reventsp,
1450N/A struct pollhead **phpp)
1450N/A{
1450N/A struct drm_minor *minor;
1450N/A struct drm_file *file_priv;
1450N/A int minor_id = DRM_DEV2MINOR(dev_id);
1450N/A int clone_id = DRM_DEV2CLONEID(dev_id);
1450N/A
1450N/A minor = idr_find(&drm_minors_idr, minor_id);
1450N/A if (!minor)
1450N/A return (ENODEV);
1450N/A if (!minor->dev)
1450N/A return (ENODEV);
1450N/A
1450N/A /*
1450N/A * No operations for VGA & AGP master devices, always return OK.
1450N/A */
1450N/A if (DRM_MINOR_IS_VGATEXT(minor_id))
1450N/A return (0);
1450N/A
1450N/A if (DRM_MINOR_IS_AGPMASTER(minor_id))
1450N/A return (0);
1450N/A
1450N/A file_priv = idr_find(&minor->clone_idr, clone_id);
1450N/A if (!file_priv)
1450N/A return (EBADF);
1450N/A
1450N/A if (!anyyet) {
1450N/A *phpp = &file_priv->drm_pollhead;
1450N/A }
1450N/A
1450N/A *reventsp = drm_poll(file_priv, events);
1450N/A return (0);
1450N/A}
1450N/A
1450N/A/*
1450N/A * Common device operations structure for all DRM drivers
1450N/A */
1450N/Astruct cb_ops drm_cb_ops = {
1450N/A drm_sun_open, /* cb_open */
1450N/A drm_sun_close, /* cb_close */
1450N/A nodev, /* cb_strategy */
1450N/A nodev, /* cb_print */
1450N/A nodev, /* cb_dump */
1450N/A drm_sun_read, /* cb_read */
1450N/A nodev, /* cb_write */
1450N/A drm_sun_ioctl, /* cb_ioctl */
1450N/A drm_sun_devmap, /* cb_devmap */
1450N/A nodev, /* cb_mmap */
1450N/A NULL, /* cb_segmap */
1450N/A drm_sun_chpoll, /* cb_chpoll */
1450N/A ddi_prop_op, /* cb_prop_op */
1450N/A 0, /* cb_stream */
1450N/A D_NEW | D_MTSAFE | D_DEVMAP /* cb_flag */
1450N/A};
1450N/A
1450N/Astatic struct modlmisc modlmisc = {
1450N/A &mod_miscops, "DRM common interfaces"
1450N/A};
1450N/A
1450N/Astatic struct modlinkage modlinkage = {
1450N/A MODREV_1, (void *)&modlmisc, NULL
1450N/A};
1450N/A
1450N/Aint
1450N/A_init(void)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A ret = mod_install(&modlinkage);
1450N/A if (ret)
1450N/A return (ret);
1450N/A
1450N/A return (drm_core_init());
1450N/A}
1450N/A
1450N/Aint
1450N/A_fini(void)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A ret = mod_remove(&modlinkage);
1450N/A if (ret)
1450N/A return (ret);
1450N/A
1450N/A drm_core_exit();
1450N/A
1450N/A return (0);
1450N/A}
1450N/A
1450N/Aint
1450N/A_info(struct modinfo *modinfop)
1450N/A{
1450N/A return (mod_info(&modlinkage, modinfop));
1450N/A}
1450N/A
1450N/Astruct drm_local_map *
1450N/Adrm_core_findmap(struct drm_device *dev, unsigned int token)
1450N/A{
1450N/A struct drm_map_list *_entry;
1450N/A
1450N/A list_for_each_entry(_entry, struct drm_map_list, &dev->maplist, head) {
1450N/A if (_entry->user_token == token)
1450N/A return (_entry->map);
1450N/A }
1450N/A
1450N/A return (NULL);
1450N/A}