15320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie/* 25320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * Copyright (C) 2012 Red Hat 35320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * based in parts on udlfb.c: 45320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> 55320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> 65320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> 75320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * 85320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * This file is subject to the terms and conditions of the GNU General Public 95320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * License v2. See the file COPYING in the main directory of this archive for 105320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * more details. 115320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie */ 125320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 135320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "drmP.h" 145320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "drm_crtc.h" 155320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "drm_edid.h" 165320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "drm_crtc_helper.h" 175320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "udl_drv.h" 185320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 195320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie/* dummy connector to just get EDID, 205320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie all UDL appear to have a DVI-D */ 215320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 225320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic u8 *udl_get_edid(struct udl_device *udl) 235320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 245320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie u8 *block; 255320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie char rbuf[3]; 265320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie int ret, i; 275320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 285320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie block = kmalloc(EDID_LENGTH, GFP_KERNEL); 295320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie if (block == NULL) 305320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return NULL; 315320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 325320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie for (i = 0; i < EDID_LENGTH; i++) { 335320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie ret = usb_control_msg(udl->ddev->usbdev, 345320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), 355320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2, 365320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie HZ); 375320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie if (ret < 1) { 385320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); 395320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie i--; 405320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie goto error; 415320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie } 425320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie block[i] = rbuf[1]; 435320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie } 445320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 455320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return block; 465320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 475320918b9a87865223fd6b228e530bf30bc64d9dDave Airlieerror: 485320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie kfree(block); 495320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return NULL; 505320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 515320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 525320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic int udl_get_modes(struct drm_connector *connector) 535320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 545320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct udl_device *udl = connector->dev->dev_private; 555320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct edid *edid; 565320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie int ret; 575320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 585320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie edid = (struct edid *)udl_get_edid(udl); 595320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 605320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie connector->display_info.raw_edid = (char *)edid; 615320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 625320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_mode_connector_update_edid_property(connector, edid); 635320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie ret = drm_add_edid_modes(connector, edid); 645320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie connector->display_info.raw_edid = NULL; 655320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie kfree(edid); 665320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return ret; 675320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 685320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 695320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic int udl_mode_valid(struct drm_connector *connector, 705320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct drm_display_mode *mode) 715320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 725320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return 0; 735320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 745320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 755320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic enum drm_connector_status 765320918b9a87865223fd6b228e530bf30bc64d9dDave Airlieudl_detect(struct drm_connector *connector, bool force) 775320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 785320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie if (drm_device_is_unplugged(connector->dev)) 795320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return connector_status_disconnected; 805320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return connector_status_connected; 815320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 825320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 835320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestruct drm_encoder *udl_best_single_encoder(struct drm_connector *connector) 845320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 855320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie int enc_id = connector->encoder_ids[0]; 865320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct drm_mode_object *obj; 875320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct drm_encoder *encoder; 885320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 895320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); 905320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie if (!obj) 915320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return NULL; 925320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie encoder = obj_to_encoder(obj); 935320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return encoder; 945320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 955320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 965320918b9a87865223fd6b228e530bf30bc64d9dDave Airlieint udl_connector_set_property(struct drm_connector *connector, struct drm_property *property, 975320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie uint64_t val) 985320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 995320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return 0; 1005320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 1015320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1025320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic void udl_connector_destroy(struct drm_connector *connector) 1035320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 1045320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_sysfs_connector_remove(connector); 1055320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_connector_cleanup(connector); 1065320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie kfree(connector); 1075320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 1085320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1095320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestruct drm_connector_helper_funcs udl_connector_helper_funcs = { 1105320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .get_modes = udl_get_modes, 1115320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .mode_valid = udl_mode_valid, 1125320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .best_encoder = udl_best_single_encoder, 1135320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 1145320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1155320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestruct drm_connector_funcs udl_connector_funcs = { 1165320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .dpms = drm_helper_connector_dpms, 1175320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .detect = udl_detect, 1185320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .fill_modes = drm_helper_probe_single_connector_modes, 1195320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .destroy = udl_connector_destroy, 1205320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .set_property = udl_connector_set_property, 1215320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 1225320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1235320918b9a87865223fd6b228e530bf30bc64d9dDave Airlieint udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder) 1245320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 1255320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct drm_connector *connector; 1265320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1275320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL); 1285320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie if (!connector) 1295320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return -ENOMEM; 1305320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1315320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_DVII); 1325320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_connector_helper_add(connector, &udl_connector_helper_funcs); 1335320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1345320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_sysfs_connector_add(connector); 1355320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_mode_connector_attach_encoder(connector, encoder); 1365320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1375320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_connector_attach_property(connector, 1385320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie dev->mode_config.dirty_info_property, 1395320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1); 1405320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return 0; 1415320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 142