1 /* 2 * Copyright © 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Rafael Antognolli <rafael.antognolli@intel.com> 25 * 26 */ 27 28 #include <linux/device.h> 29 #include <linux/fs.h> 30 #include <drm/drmP.h> 31 #include <linux/slab.h> 32 #include <linux/kernel.h> 33 #include <linux/module.h> 34 #include <linux/uaccess.h> 35 #include <drm/drm_dp_helper.h> 36 #include <drm/drm_crtc.h> 37 38 struct drm_dp_aux_dev { 39 unsigned index; 40 struct drm_dp_aux *aux; 41 struct device *dev; 42 struct kref refcount; 43 atomic_t usecount; 44 }; 45 46 #define DRM_AUX_MINORS 256 47 #define AUX_MAX_OFFSET (1 << 20) 48 #if 0 49 static DEFINE_IDR(aux_idr); 50 static DEFINE_MUTEX(aux_idr_mutex); 51 static struct class *drm_dp_aux_dev_class; 52 static int drm_dev_major = -1; 53 54 static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_minor(unsigned index) 55 { 56 struct drm_dp_aux_dev *aux_dev = NULL; 57 58 mutex_lock(&aux_idr_mutex); 59 aux_dev = idr_find(&aux_idr, index); 60 if (!kref_get_unless_zero(&aux_dev->refcount)) 61 aux_dev = NULL; 62 mutex_unlock(&aux_idr_mutex); 63 64 return aux_dev; 65 } 66 67 static struct drm_dp_aux_dev *alloc_drm_dp_aux_dev(struct drm_dp_aux *aux) 68 { 69 struct drm_dp_aux_dev *aux_dev; 70 int index; 71 72 aux_dev = kzalloc(sizeof(*aux_dev), GFP_KERNEL); 73 if (!aux_dev) 74 return ERR_PTR(-ENOMEM); 75 aux_dev->aux = aux; 76 atomic_set(&aux_dev->usecount, 1); 77 kref_init(&aux_dev->refcount); 78 79 mutex_lock(&aux_idr_mutex); 80 index = idr_alloc_cyclic(&aux_idr, aux_dev, 0, DRM_AUX_MINORS, 81 GFP_KERNEL); 82 mutex_unlock(&aux_idr_mutex); 83 if (index < 0) { 84 kfree(aux_dev); 85 return ERR_PTR(index); 86 } 87 aux_dev->index = index; 88 89 return aux_dev; 90 } 91 92 static void release_drm_dp_aux_dev(struct kref *ref) 93 { 94 struct drm_dp_aux_dev *aux_dev = 95 container_of(ref, struct drm_dp_aux_dev, refcount); 96 97 kfree(aux_dev); 98 } 99 100 static ssize_t name_show(struct device *dev, 101 struct device_attribute *attr, char *buf) 102 { 103 ssize_t res; 104 struct drm_dp_aux_dev *aux_dev = 105 drm_dp_aux_dev_get_by_minor(MINOR(dev->devt)); 106 107 if (!aux_dev) 108 return -ENODEV; 109 110 res = sprintf(buf, "%s\n", aux_dev->aux->name); 111 kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); 112 113 return res; 114 } 115 static DEVICE_ATTR_RO(name); 116 117 static struct attribute *drm_dp_aux_attrs[] = { 118 &dev_attr_name.attr, 119 NULL, 120 }; 121 ATTRIBUTE_GROUPS(drm_dp_aux); 122 123 static int auxdev_open(struct inode *inode, struct file *file) 124 { 125 unsigned int minor = iminor(inode); 126 struct drm_dp_aux_dev *aux_dev; 127 128 aux_dev = drm_dp_aux_dev_get_by_minor(minor); 129 if (!aux_dev) 130 return -ENODEV; 131 132 file->private_data = aux_dev; 133 return 0; 134 } 135 136 static loff_t auxdev_llseek(struct file *file, loff_t offset, int whence) 137 { 138 return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET); 139 } 140 141 static ssize_t auxdev_read(struct file *file, char __user *buf, size_t count, 142 loff_t *offset) 143 { 144 size_t bytes_pending, num_bytes_processed = 0; 145 struct drm_dp_aux_dev *aux_dev = file->private_data; 146 ssize_t res = 0; 147 148 if (!atomic_inc_not_zero(&aux_dev->usecount)) 149 return -ENODEV; 150 151 bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - (*offset)); 152 153 if (!access_ok(VERIFY_WRITE, buf, bytes_pending)) { 154 res = -EFAULT; 155 goto out; 156 } 157 158 while (bytes_pending > 0) { 159 uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES]; 160 ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf)); 161 162 if (signal_pending(current)) { 163 res = num_bytes_processed ? 164 num_bytes_processed : -ERESTARTSYS; 165 goto out; 166 } 167 168 res = drm_dp_dpcd_read(aux_dev->aux, *offset, localbuf, todo); 169 if (res <= 0) { 170 res = num_bytes_processed ? num_bytes_processed : res; 171 goto out; 172 } 173 if (__copy_to_user(buf + num_bytes_processed, localbuf, res)) { 174 res = num_bytes_processed ? 175 num_bytes_processed : -EFAULT; 176 goto out; 177 } 178 bytes_pending -= res; 179 *offset += res; 180 num_bytes_processed += res; 181 res = num_bytes_processed; 182 } 183 184 out: 185 atomic_dec(&aux_dev->usecount); 186 wake_up_atomic_t(&aux_dev->usecount); 187 return res; 188 } 189 190 static ssize_t auxdev_write(struct file *file, const char __user *buf, 191 size_t count, loff_t *offset) 192 { 193 size_t bytes_pending, num_bytes_processed = 0; 194 struct drm_dp_aux_dev *aux_dev = file->private_data; 195 ssize_t res = 0; 196 197 if (!atomic_inc_not_zero(&aux_dev->usecount)) 198 return -ENODEV; 199 200 bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - *offset); 201 202 if (!access_ok(VERIFY_READ, buf, bytes_pending)) { 203 res = -EFAULT; 204 goto out; 205 } 206 207 while (bytes_pending > 0) { 208 uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES]; 209 ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf)); 210 211 if (signal_pending(current)) { 212 res = num_bytes_processed ? 213 num_bytes_processed : -ERESTARTSYS; 214 goto out; 215 } 216 217 if (__copy_from_user(localbuf, 218 buf + num_bytes_processed, todo)) { 219 res = num_bytes_processed ? 220 num_bytes_processed : -EFAULT; 221 goto out; 222 } 223 224 res = drm_dp_dpcd_write(aux_dev->aux, *offset, localbuf, todo); 225 if (res <= 0) { 226 res = num_bytes_processed ? num_bytes_processed : res; 227 goto out; 228 } 229 bytes_pending -= res; 230 *offset += res; 231 num_bytes_processed += res; 232 res = num_bytes_processed; 233 } 234 235 out: 236 atomic_dec(&aux_dev->usecount); 237 wake_up_atomic_t(&aux_dev->usecount); 238 return res; 239 } 240 241 static int auxdev_release(struct inode *inode, struct file *file) 242 { 243 struct drm_dp_aux_dev *aux_dev = file->private_data; 244 245 kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); 246 return 0; 247 } 248 249 static const struct file_operations auxdev_fops = { 250 .owner = THIS_MODULE, 251 .llseek = auxdev_llseek, 252 .read = auxdev_read, 253 .write = auxdev_write, 254 .open = auxdev_open, 255 .release = auxdev_release, 256 }; 257 258 #define to_auxdev(d) container_of(d, struct drm_dp_aux_dev, aux) 259 260 static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_aux(struct drm_dp_aux *aux) 261 { 262 struct drm_dp_aux_dev *iter, *aux_dev = NULL; 263 int id; 264 265 /* don't increase kref count here because this function should only be 266 * used by drm_dp_aux_unregister_devnode. Thus, it will always have at 267 * least one reference - the one that drm_dp_aux_register_devnode 268 * created 269 */ 270 mutex_lock(&aux_idr_mutex); 271 idr_for_each_entry(&aux_idr, iter, id) { 272 if (iter->aux == aux) { 273 aux_dev = iter; 274 break; 275 } 276 } 277 mutex_unlock(&aux_idr_mutex); 278 return aux_dev; 279 } 280 281 static int auxdev_wait_atomic_t(atomic_t *p) 282 { 283 schedule(); 284 return 0; 285 } 286 /** 287 * drm_dp_aux_unregister_devnode() - unregister a devnode for this aux channel 288 * @aux: DisplayPort AUX channel 289 * 290 * Returns 0 on success or a negative error code on failure. 291 */ 292 void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) 293 { 294 struct drm_dp_aux_dev *aux_dev; 295 unsigned int minor; 296 297 aux_dev = drm_dp_aux_dev_get_by_aux(aux); 298 if (!aux_dev) /* attach must have failed */ 299 return; 300 301 mutex_lock(&aux_idr_mutex); 302 idr_remove(&aux_idr, aux_dev->index); 303 mutex_unlock(&aux_idr_mutex); 304 305 atomic_dec(&aux_dev->usecount); 306 wait_on_atomic_t(&aux_dev->usecount, auxdev_wait_atomic_t, 307 TASK_UNINTERRUPTIBLE); 308 309 minor = aux_dev->index; 310 if (aux_dev->dev) 311 device_destroy(drm_dp_aux_dev_class, 312 MKDEV(drm_dev_major, minor)); 313 314 DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name); 315 kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); 316 } 317 EXPORT_SYMBOL(drm_dp_aux_unregister_devnode); 318 319 /** 320 * drm_dp_aux_register_devnode() - register a devnode for this aux channel 321 * @aux: DisplayPort AUX channel 322 * 323 * Returns 0 on success or a negative error code on failure. 324 */ 325 int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) 326 { 327 struct drm_dp_aux_dev *aux_dev; 328 int res; 329 330 aux_dev = alloc_drm_dp_aux_dev(aux); 331 if (IS_ERR(aux_dev)) 332 return PTR_ERR(aux_dev); 333 334 aux_dev->dev = device_create(drm_dp_aux_dev_class, aux->dev, 335 MKDEV(drm_dev_major, aux_dev->index), NULL, 336 "drm_dp_aux%d", aux_dev->index); 337 if (IS_ERR(aux_dev->dev)) { 338 res = PTR_ERR(aux_dev->dev); 339 aux_dev->dev = NULL; 340 goto error; 341 } 342 343 DRM_DEBUG("drm_dp_aux_dev: aux [%s] registered as minor %d\n", 344 aux->name, aux_dev->index); 345 return 0; 346 error: 347 drm_dp_aux_unregister_devnode(aux); 348 return res; 349 } 350 EXPORT_SYMBOL(drm_dp_aux_register_devnode); 351 352 int drm_dp_aux_dev_init(void) 353 { 354 int res; 355 356 drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev"); 357 if (IS_ERR(drm_dp_aux_dev_class)) { 358 res = PTR_ERR(drm_dp_aux_dev_class); 359 goto out; 360 } 361 drm_dp_aux_dev_class->dev_groups = drm_dp_aux_groups; 362 363 res = register_chrdev(0, "aux", &auxdev_fops); 364 if (res < 0) 365 goto out; 366 drm_dev_major = res; 367 368 return 0; 369 out: 370 class_destroy(drm_dp_aux_dev_class); 371 return res; 372 } 373 EXPORT_SYMBOL(drm_dp_aux_dev_init); 374 375 void drm_dp_aux_dev_exit(void) 376 { 377 unregister_chrdev(drm_dev_major, "aux"); 378 class_destroy(drm_dp_aux_dev_class); 379 } 380 EXPORT_SYMBOL(drm_dp_aux_dev_exit); 381 #endif 382