15320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie/* 25320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * Copyright (C) 2012 Red Hat 35320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * 45320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * This file is subject to the terms and conditions of the GNU General Public 55320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * License v2. See the file COPYING in the main directory of this archive for 65320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie * more details. 75320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie */ 85320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 95320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include <linux/module.h> 105320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "drm_usb.h" 115320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "drm_crtc_helper.h" 125320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie#include "udl_drv.h" 135320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 145320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic struct drm_driver driver; 155320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 168d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie/* 178d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie * There are many DisplayLink-based graphics products, all with unique PIDs. 188d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff) 198d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie * We also require a match on SubClass (0x00) and Protocol (0x00), 208d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie * which is compatible with all known USB 2.0 era graphics chips and firmware, 218d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie * but allows DisplayLink to increment those for any future incompatible chips 228d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie */ 235320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic struct usb_device_id id_table[] = { 248d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie {.idVendor = 0x17e9, .bInterfaceClass = 0xff, 258d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie .bInterfaceSubClass = 0x00, 268d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie .bInterfaceProtocol = 0x00, 278d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie .match_flags = USB_DEVICE_ID_MATCH_VENDOR | 288d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie USB_DEVICE_ID_MATCH_INT_CLASS | 298d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie USB_DEVICE_ID_MATCH_INT_SUBCLASS | 308d96bccced28ba3c12ffb923aa264aa6b0d604a1Dave Airlie USB_DEVICE_ID_MATCH_INT_PROTOCOL,}, 315320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie {}, 325320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 335320918b9a87865223fd6b228e530bf30bc64d9dDave AirlieMODULE_DEVICE_TABLE(usb, id_table); 345320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 355320918b9a87865223fd6b228e530bf30bc64d9dDave AirlieMODULE_LICENSE("GPL"); 365320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 375320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic int udl_usb_probe(struct usb_interface *interface, 385320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie const struct usb_device_id *id) 395320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 405320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return drm_get_usb_dev(interface, id, &driver); 415320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 425320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 435320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic void udl_usb_disconnect(struct usb_interface *interface) 445320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 455320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie struct drm_device *dev = usb_get_intfdata(interface); 465320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 475320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_kms_helper_poll_disable(dev); 485320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_connector_unplug_all(dev); 495320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie udl_fbdev_unplug(dev); 505320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie udl_drop_usb(dev); 515320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_unplug_dev(dev); 525320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 535320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 545320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic struct vm_operations_struct udl_gem_vm_ops = { 555320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .fault = udl_gem_fault, 565320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .open = drm_gem_vm_open, 575320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .close = drm_gem_vm_close, 585320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 595320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 605320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic const struct file_operations udl_driver_fops = { 615320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .owner = THIS_MODULE, 625320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .open = drm_open, 63fa9e855025b19e96e493ee00de7d933a9794f742Konstantin Khlebnikov .mmap = udl_drm_gem_mmap, 645320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .poll = drm_poll, 655320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .read = drm_read, 665320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .unlocked_ioctl = drm_ioctl, 675320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .release = drm_release, 685320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .fasync = drm_fasync, 695320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .llseek = noop_llseek, 705320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 715320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 725320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic struct drm_driver driver = { 735320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .driver_features = DRIVER_MODESET | DRIVER_GEM, 745320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .load = udl_driver_load, 755320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .unload = udl_driver_unload, 765320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 775320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie /* gem hooks */ 785320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .gem_init_object = udl_gem_init_object, 795320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .gem_free_object = udl_gem_free_object, 805320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .gem_vm_ops = &udl_gem_vm_ops, 815320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 825320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .dumb_create = udl_dumb_create, 835320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .dumb_map_offset = udl_gem_mmap, 845320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .dumb_destroy = udl_dumb_destroy, 855320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .fops = &udl_driver_fops, 865320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .name = DRIVER_NAME, 875320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .desc = DRIVER_DESC, 885320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .date = DRIVER_DATE, 895320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .major = DRIVER_MAJOR, 905320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .minor = DRIVER_MINOR, 915320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .patchlevel = DRIVER_PATCHLEVEL, 925320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 935320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 945320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic struct usb_driver udl_driver = { 955320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .name = "udl", 965320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .probe = udl_usb_probe, 975320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .disconnect = udl_usb_disconnect, 985320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie .id_table = id_table, 995320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie}; 1005320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1015320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic int __init udl_init(void) 1025320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 1035320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie return drm_usb_init(&driver, &udl_driver); 1045320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 1055320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1065320918b9a87865223fd6b228e530bf30bc64d9dDave Airliestatic void __exit udl_exit(void) 1075320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie{ 1085320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie drm_usb_exit(&driver, &udl_driver); 1095320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie} 1105320918b9a87865223fd6b228e530bf30bc64d9dDave Airlie 1115320918b9a87865223fd6b228e530bf30bc64d9dDave Airliemodule_init(udl_init); 1125320918b9a87865223fd6b228e530bf30bc64d9dDave Airliemodule_exit(udl_exit); 113