2019-05-29 07:12:36 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2010-12-15 07:14:24 +10:00
/*
* Copyright ( C ) 2012 Red Hat
*/
# include <linux/module.h>
2019-07-16 08:42:09 +02:00
2012-10-02 18:01:07 +01:00
# include <drm/drm_crtc_helper.h>
2019-07-16 08:42:09 +02:00
# include <drm/drm_drv.h>
2019-11-14 13:51:04 +01:00
# include <drm/drm_fb_helper.h>
2019-07-16 08:42:09 +02:00
# include <drm/drm_file.h>
2019-11-07 10:43:06 +01:00
# include <drm/drm_gem_shmem_helper.h>
2020-03-23 15:49:05 +01:00
# include <drm/drm_managed.h>
2019-07-16 08:42:09 +02:00
# include <drm/drm_ioctl.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2019-07-16 08:42:09 +02:00
# include <drm/drm_print.h>
2010-12-15 07:14:24 +10:00
# include "udl_drv.h"
2016-08-30 14:50:21 -07:00
static int udl_usb_suspend ( struct usb_interface * interface ,
pm_message_t message )
{
2017-10-12 17:13:49 -07:00
struct drm_device * dev = usb_get_intfdata ( interface ) ;
2019-12-10 09:48:59 +01:00
return drm_mode_config_helper_suspend ( dev ) ;
2016-08-30 14:50:21 -07:00
}
static int udl_usb_resume ( struct usb_interface * interface )
{
struct drm_device * dev = usb_get_intfdata ( interface ) ;
2019-12-10 09:48:59 +01:00
return drm_mode_config_helper_resume ( dev ) ;
2016-08-30 14:50:21 -07:00
}
2019-11-07 10:43:06 +01:00
DEFINE_DRM_GEM_FOPS ( udl_driver_fops ) ;
2010-12-15 07:14:24 +10:00
2019-04-05 13:17:15 +10:00
static void udl_driver_release ( struct drm_device * dev )
{
udl_fini ( dev ) ;
udl_modeset_cleanup ( dev ) ;
drm_dev_fini ( dev ) ;
}
2010-12-15 07:14:24 +10:00
static struct drm_driver driver = {
2019-12-10 09:48:58 +01:00
. driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET ,
2019-04-05 13:17:13 +10:00
. release = udl_driver_release ,
2010-12-15 07:14:24 +10:00
/* gem hooks */
2019-11-07 10:43:05 +01:00
. gem_create_object = udl_driver_gem_create_object ,
2010-12-15 07:14:24 +10:00
. fops = & udl_driver_fops ,
2019-11-07 10:43:06 +01:00
DRM_GEM_SHMEM_DRIVER_OPS ,
2011-12-21 11:23:44 +00:00
2010-12-15 07:14:24 +10:00
. name = DRIVER_NAME ,
. desc = DRIVER_DESC ,
. date = DRIVER_DATE ,
. major = DRIVER_MAJOR ,
. minor = DRIVER_MINOR ,
. patchlevel = DRIVER_PATCHLEVEL ,
} ;
2019-04-05 13:17:15 +10:00
static struct udl_device * udl_driver_create ( struct usb_interface * interface )
{
struct usb_device * udev = interface_to_usbdev ( interface ) ;
struct udl_device * udl ;
int r ;
udl = kzalloc ( sizeof ( * udl ) , GFP_KERNEL ) ;
if ( ! udl )
return ERR_PTR ( - ENOMEM ) ;
r = drm_dev_init ( & udl - > drm , & driver , & interface - > dev ) ;
if ( r ) {
kfree ( udl ) ;
return ERR_PTR ( r ) ;
}
udl - > udev = udev ;
udl - > drm . dev_private = udl ;
2020-03-23 15:49:05 +01:00
drmm_add_final_kfree ( & udl - > drm , udl ) ;
2019-04-05 13:17:15 +10:00
r = udl_init ( udl ) ;
if ( r ) {
2020-03-23 15:49:05 +01:00
drm_dev_put ( & udl - > drm ) ;
2019-04-05 13:17:15 +10:00
return ERR_PTR ( r ) ;
}
usb_set_intfdata ( interface , udl ) ;
return udl ;
}
2014-08-29 12:12:45 +02:00
static int udl_usb_probe ( struct usb_interface * interface ,
const struct usb_device_id * id )
{
int r ;
2019-04-05 13:17:15 +10:00
struct udl_device * udl ;
2014-08-29 12:12:45 +02:00
2019-04-05 13:17:15 +10:00
udl = udl_driver_create ( interface ) ;
if ( IS_ERR ( udl ) )
return PTR_ERR ( udl ) ;
2014-08-29 12:12:45 +02:00
2019-04-05 13:17:15 +10:00
r = drm_dev_register ( & udl - > drm , 0 ) ;
2014-08-29 12:12:45 +02:00
if ( r )
goto err_free ;
2019-04-05 13:17:15 +10:00
DRM_INFO ( " Initialized udl on minor %d \n " , udl - > drm . primary - > index ) ;
2014-08-29 12:12:45 +02:00
2019-12-10 09:49:01 +01:00
r = drm_fbdev_generic_setup ( & udl - > drm , 0 ) ;
2019-11-14 13:51:04 +01:00
if ( r )
goto err_drm_dev_unregister ;
2014-08-29 12:12:45 +02:00
return 0 ;
2019-11-14 13:51:04 +01:00
err_drm_dev_unregister :
drm_dev_unregister ( & udl - > drm ) ;
2014-08-29 12:12:45 +02:00
err_free :
2019-04-05 13:17:15 +10:00
drm_dev_put ( & udl - > drm ) ;
2014-08-29 12:12:45 +02:00
return r ;
}
static void udl_usb_disconnect ( struct usb_interface * interface )
{
struct drm_device * dev = usb_get_intfdata ( interface ) ;
drm_kms_helper_poll_disable ( dev ) ;
udl_drop_usb ( dev ) ;
2017-08-02 13:56:02 +02:00
drm_dev_unplug ( dev ) ;
2019-02-08 15:01:03 +01:00
drm_dev_put ( dev ) ;
2014-08-29 12:12:45 +02:00
}
/*
* There are many DisplayLink - based graphics products , all with unique PIDs .
* So we match on DisplayLink ' s VID + Vendor - Defined Interface Class ( 0xff )
* We also require a match on SubClass ( 0x00 ) and Protocol ( 0x00 ) ,
* which is compatible with all known USB 2.0 era graphics chips and firmware ,
* but allows DisplayLink to increment those for any future incompatible chips
*/
2017-08-12 14:05:19 +05:30
static const struct usb_device_id id_table [ ] = {
2014-08-29 12:12:45 +02:00
{ . idVendor = 0x17e9 , . bInterfaceClass = 0xff ,
. bInterfaceSubClass = 0x00 ,
. bInterfaceProtocol = 0x00 ,
. match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
USB_DEVICE_ID_MATCH_INT_PROTOCOL , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , id_table ) ;
2010-12-15 07:14:24 +10:00
static struct usb_driver udl_driver = {
. name = " udl " ,
. probe = udl_usb_probe ,
. disconnect = udl_usb_disconnect ,
2016-08-30 14:50:21 -07:00
. suspend = udl_usb_suspend ,
. resume = udl_usb_resume ,
2010-12-15 07:14:24 +10:00
. id_table = id_table ,
} ;
2016-02-17 17:43:27 +05:30
module_usb_driver ( udl_driver ) ;
2014-08-29 12:12:45 +02:00
MODULE_LICENSE ( " GPL " ) ;