/*
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
*/
/*
* radeon_drv.c -- ATI Radeon driver -*- linux-c -*-
* Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
*/
/*
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Gareth Hughes <gareth@valinux.com>
*
*/
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
#include "drm_pciids.h"
#ifdef __sparc
#include "efb.h"
#endif /* sparc */
int radeon_no_wb = 1;
/*
* cb_ops entrypoint
*/
extern struct cb_ops drm_cb_ops;
/* drv_PCI_IDs comes from drm_pciids.h */
static const drm_pci_id_list_t radeon_pciidlist[] = {
radeon_PCI_IDS
};
/*
* module entrypoint
*/
static int radeon_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
static int radeon_attach(dev_info_t *, ddi_attach_cmd_t);
static int radeon_detach(dev_info_t *, ddi_detach_cmd_t);
extern void radeon_init_ioctl_arrays(void);
extern uint_t radeon_driver_irq_handler(caddr_t);
extern int drm_get_pci_index_reg(dev_info_t *, uint_t, uint_t, off_t *);
/*
* Local routines
*/
static void radeon_configure(drm_driver_t *);
/*
* DRM driver
*/
static drm_driver_t radeon_driver = {0};
/*
* Common device operations structure for all DRM drivers
*/
#ifdef __sparc
static struct cb_ops efb_cb_ops = {
nodev, /* cb_open */
nodev, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
efb_ioctl, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
NULL, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
0, /* cb_stream */
D_NEW | D_MTSAFE |D_DEVMAP /* cb_flag */
};
static struct dev_ops efb_dev_ops = {
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
radeon_info, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
radeon_attach, /* devo_attach */
radeon_detach, /* devo_detach */
nodev, /* devo_reset */
&efb_cb_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
NULL /* power */
};
static struct modldrv modldrv = {
&mod_driverops, /* drv_modops */
"efb DRM driver 1.4", /* drv_linkinfo */
&efb_dev_ops, /* drv_dev_ops */
};
#else
static struct dev_ops radeon_dev_ops = {
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
radeon_info, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
radeon_attach, /* devo_attach */
radeon_detach, /* devo_detach */
nodev, /* devo_reset */
&drm_cb_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
NULL /* power */
};
static struct modldrv modldrv = {
&mod_driverops, /* drv_modops */
"radeon DRM driver 1.4", /* drv_linkinfo */
&radeon_dev_ops, /* drv_dev_ops */
};
#endif
static struct modlinkage modlinkage = {
MODREV_1, (void *) &modldrv, NULL
};
/*
* softstate head
*/
void *radeon_statep;
int
_init(void)
{
int error;
radeon_configure(&radeon_driver);
if ((error = ddi_soft_state_init(&radeon_statep,
sizeof (drm_device_t), DRM_MAX_INSTANCES)) != 0)
return (error);
#ifdef __sparc
efb_init(radeon_statep, &efb_cb_ops, &radeon_driver);
#endif /* sparc */
if ((error = mod_install(&modlinkage)) != 0) {
ddi_soft_state_fini(&radeon_statep);
return (error);
}
return (error);
} /* _init() */
int
_fini(void)
{
int error;
if ((error = mod_remove(&modlinkage)) != 0)
return (error);
(void) ddi_soft_state_fini(&radeon_statep);
return (0);
} /* _fini() */
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
} /* _info() */
static int
radeon_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
drm_device_t *statep;
void *handle;
int unit;
if (cmd != DDI_ATTACH) {
DRM_ERROR("radeon_attach: only attach op supported");
return (DDI_FAILURE);
}
unit = ddi_get_instance(dip);
if (ddi_soft_state_zalloc(radeon_statep, unit) != DDI_SUCCESS) {
cmn_err(CE_WARN,
"radeon_attach: alloc softstate failed unit=%d", unit);
return (DDI_FAILURE);
}
statep = ddi_get_soft_state(radeon_statep, unit);
statep->dip = dip;
statep->driver = &radeon_driver;
/*
* Call drm_supp_register to create minor nodes for us
*/
handle = drm_supp_register(dip, statep);
if (handle == NULL) {
DRM_ERROR("radeon_attach: drm_supp_register failed");
goto err_exit1;
}
statep->drm_handle = handle;
/*
* After drm_supp_register, we can call drm_xxx routine
*/
statep->drm_supported = DRM_UNSUPPORT;
if (drm_probe(statep, radeon_pciidlist) != DDI_SUCCESS) {
DRM_ERROR("radeon_open: "
"DRM current don't support this graphics card");
goto err_exit2;
}
statep->drm_supported = DRM_SUPPORT;
/* call common attach code */
if (drm_attach(statep) != DDI_SUCCESS) {
DRM_ERROR("radeon_attach: drm_attach failed");
goto err_exit2;
}
#ifdef __sparc
if (efb_attach(statep) != DDI_SUCCESS) {
goto err_exit2;
}
#endif /* sparc */
return (DDI_SUCCESS);
err_exit2:
(void) drm_supp_unregister(handle);
err_exit1:
(void) ddi_soft_state_free(radeon_statep, unit);
return (DDI_FAILURE);
} /* radeon_attach() */
static int
radeon_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
drm_device_t *statep;
int unit;
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
unit = ddi_get_instance(dip);
statep = ddi_get_soft_state(radeon_statep, unit);
if (statep == NULL)
return (DDI_FAILURE);
#ifdef __sparc
(void) efb_detach(statep);
#endif /* sparc */
(void) drm_detach(statep);
(void) drm_supp_unregister(statep->drm_handle);
(void) ddi_soft_state_free(radeon_statep, unit);
return (DDI_SUCCESS);
} /* radeon_detach() */
/*ARGSUSED*/
static int
radeon_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
drm_device_t *statep;
int error = DDI_SUCCESS;
int unit;
unit = drm_dev_to_instance((dev_t)arg);
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
statep = ddi_get_soft_state(radeon_statep, unit);
if (statep == NULL || statep->dip == NULL) {
error = DDI_FAILURE;
} else {
*result = (void *) statep->dip;
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)(uintptr_t)unit;
error = DDI_SUCCESS;
break;
default:
error = DDI_FAILURE;
break;
}
return (error);
} /* radeon_info() */
static void
radeon_configure(drm_driver_t *driver)
{
driver->buf_priv_size = sizeof (drm_radeon_buf_priv_t);
driver->load = radeon_driver_load;
driver->unload = radeon_driver_unload;
driver->firstopen = radeon_driver_firstopen;
driver->open = radeon_driver_open;
driver->preclose = radeon_driver_preclose;
driver->postclose = radeon_driver_postclose;
driver->lastclose = radeon_driver_lastclose;
driver->vblank_wait = radeon_driver_vblank_wait;
driver->vblank_wait2 = radeon_driver_vblank_wait2;
driver->irq_preinstall = radeon_driver_irq_preinstall;
driver->irq_postinstall = radeon_driver_irq_postinstall;
driver->irq_uninstall = radeon_driver_irq_uninstall;
driver->irq_handler = radeon_driver_irq_handler;
driver->dma_ioctl = radeon_cp_buffers;
driver->driver_ioctls = radeon_ioctls;
driver->max_driver_ioctl = radeon_max_ioctl;
driver->driver_name = DRIVER_NAME;
driver->driver_desc = DRIVER_DESC;
driver->driver_date = DRIVER_DATE;
driver->driver_major = DRIVER_MAJOR;
driver->driver_minor = DRIVER_MINOR;
driver->driver_patchlevel = DRIVER_PATCHLEVEL;
driver->use_agp = 1;
driver->use_mtrr = 1;
driver->use_pci_dma = 1;
driver->use_sg = 1;
driver->use_dma = 1;
driver->use_irq = 1;
driver->use_vbl_irq = 1;
driver->use_vbl_irq2 = 1;
} /* radeon_configure() */