Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10-rc6 366 lines 9.1 kB view raw
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 <linux/slab.h> 31#include <linux/init.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#include <drm/drmP.h> 38 39#include "drm_crtc_helper_internal.h" 40 41struct drm_dp_aux_dev { 42 unsigned index; 43 struct drm_dp_aux *aux; 44 struct device *dev; 45 struct kref refcount; 46 atomic_t usecount; 47}; 48 49#define DRM_AUX_MINORS 256 50#define AUX_MAX_OFFSET (1 << 20) 51static DEFINE_IDR(aux_idr); 52static DEFINE_MUTEX(aux_idr_mutex); 53static struct class *drm_dp_aux_dev_class; 54static int drm_dev_major = -1; 55 56static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_minor(unsigned index) 57{ 58 struct drm_dp_aux_dev *aux_dev = NULL; 59 60 mutex_lock(&aux_idr_mutex); 61 aux_dev = idr_find(&aux_idr, index); 62 if (!kref_get_unless_zero(&aux_dev->refcount)) 63 aux_dev = NULL; 64 mutex_unlock(&aux_idr_mutex); 65 66 return aux_dev; 67} 68 69static struct drm_dp_aux_dev *alloc_drm_dp_aux_dev(struct drm_dp_aux *aux) 70{ 71 struct drm_dp_aux_dev *aux_dev; 72 int index; 73 74 aux_dev = kzalloc(sizeof(*aux_dev), GFP_KERNEL); 75 if (!aux_dev) 76 return ERR_PTR(-ENOMEM); 77 aux_dev->aux = aux; 78 atomic_set(&aux_dev->usecount, 1); 79 kref_init(&aux_dev->refcount); 80 81 mutex_lock(&aux_idr_mutex); 82 index = idr_alloc_cyclic(&aux_idr, aux_dev, 0, DRM_AUX_MINORS, 83 GFP_KERNEL); 84 mutex_unlock(&aux_idr_mutex); 85 if (index < 0) { 86 kfree(aux_dev); 87 return ERR_PTR(index); 88 } 89 aux_dev->index = index; 90 91 return aux_dev; 92} 93 94static void release_drm_dp_aux_dev(struct kref *ref) 95{ 96 struct drm_dp_aux_dev *aux_dev = 97 container_of(ref, struct drm_dp_aux_dev, refcount); 98 99 kfree(aux_dev); 100} 101 102static ssize_t name_show(struct device *dev, 103 struct device_attribute *attr, char *buf) 104{ 105 ssize_t res; 106 struct drm_dp_aux_dev *aux_dev = 107 drm_dp_aux_dev_get_by_minor(MINOR(dev->devt)); 108 109 if (!aux_dev) 110 return -ENODEV; 111 112 res = sprintf(buf, "%s\n", aux_dev->aux->name); 113 kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); 114 115 return res; 116} 117static DEVICE_ATTR_RO(name); 118 119static struct attribute *drm_dp_aux_attrs[] = { 120 &dev_attr_name.attr, 121 NULL, 122}; 123ATTRIBUTE_GROUPS(drm_dp_aux); 124 125static int auxdev_open(struct inode *inode, struct file *file) 126{ 127 unsigned int minor = iminor(inode); 128 struct drm_dp_aux_dev *aux_dev; 129 130 aux_dev = drm_dp_aux_dev_get_by_minor(minor); 131 if (!aux_dev) 132 return -ENODEV; 133 134 file->private_data = aux_dev; 135 return 0; 136} 137 138static loff_t auxdev_llseek(struct file *file, loff_t offset, int whence) 139{ 140 return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET); 141} 142 143static ssize_t auxdev_read(struct file *file, char __user *buf, size_t count, 144 loff_t *offset) 145{ 146 size_t bytes_pending, num_bytes_processed = 0; 147 struct drm_dp_aux_dev *aux_dev = file->private_data; 148 ssize_t res = 0; 149 150 if (!atomic_inc_not_zero(&aux_dev->usecount)) 151 return -ENODEV; 152 153 bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - (*offset)); 154 155 if (!access_ok(VERIFY_WRITE, buf, bytes_pending)) { 156 res = -EFAULT; 157 goto out; 158 } 159 160 while (bytes_pending > 0) { 161 uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES]; 162 ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf)); 163 164 if (signal_pending(current)) { 165 res = num_bytes_processed ? 166 num_bytes_processed : -ERESTARTSYS; 167 goto out; 168 } 169 170 res = drm_dp_dpcd_read(aux_dev->aux, *offset, localbuf, todo); 171 if (res <= 0) { 172 res = num_bytes_processed ? num_bytes_processed : res; 173 goto out; 174 } 175 if (__copy_to_user(buf + num_bytes_processed, localbuf, res)) { 176 res = num_bytes_processed ? 177 num_bytes_processed : -EFAULT; 178 goto out; 179 } 180 bytes_pending -= res; 181 *offset += res; 182 num_bytes_processed += res; 183 res = num_bytes_processed; 184 } 185 186out: 187 atomic_dec(&aux_dev->usecount); 188 wake_up_atomic_t(&aux_dev->usecount); 189 return res; 190} 191 192static ssize_t auxdev_write(struct file *file, const char __user *buf, 193 size_t count, loff_t *offset) 194{ 195 size_t bytes_pending, num_bytes_processed = 0; 196 struct drm_dp_aux_dev *aux_dev = file->private_data; 197 ssize_t res = 0; 198 199 if (!atomic_inc_not_zero(&aux_dev->usecount)) 200 return -ENODEV; 201 202 bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - *offset); 203 204 if (!access_ok(VERIFY_READ, buf, bytes_pending)) { 205 res = -EFAULT; 206 goto out; 207 } 208 209 while (bytes_pending > 0) { 210 uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES]; 211 ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf)); 212 213 if (signal_pending(current)) { 214 res = num_bytes_processed ? 215 num_bytes_processed : -ERESTARTSYS; 216 goto out; 217 } 218 219 if (__copy_from_user(localbuf, 220 buf + num_bytes_processed, todo)) { 221 res = num_bytes_processed ? 222 num_bytes_processed : -EFAULT; 223 goto out; 224 } 225 226 res = drm_dp_dpcd_write(aux_dev->aux, *offset, localbuf, todo); 227 if (res <= 0) { 228 res = num_bytes_processed ? num_bytes_processed : res; 229 goto out; 230 } 231 bytes_pending -= res; 232 *offset += res; 233 num_bytes_processed += res; 234 res = num_bytes_processed; 235 } 236 237out: 238 atomic_dec(&aux_dev->usecount); 239 wake_up_atomic_t(&aux_dev->usecount); 240 return res; 241} 242 243static int auxdev_release(struct inode *inode, struct file *file) 244{ 245 struct drm_dp_aux_dev *aux_dev = file->private_data; 246 247 kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); 248 return 0; 249} 250 251static const struct file_operations auxdev_fops = { 252 .owner = THIS_MODULE, 253 .llseek = auxdev_llseek, 254 .read = auxdev_read, 255 .write = auxdev_write, 256 .open = auxdev_open, 257 .release = auxdev_release, 258}; 259 260#define to_auxdev(d) container_of(d, struct drm_dp_aux_dev, aux) 261 262static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_aux(struct drm_dp_aux *aux) 263{ 264 struct drm_dp_aux_dev *iter, *aux_dev = NULL; 265 int id; 266 267 /* don't increase kref count here because this function should only be 268 * used by drm_dp_aux_unregister_devnode. Thus, it will always have at 269 * least one reference - the one that drm_dp_aux_register_devnode 270 * created 271 */ 272 mutex_lock(&aux_idr_mutex); 273 idr_for_each_entry(&aux_idr, iter, id) { 274 if (iter->aux == aux) { 275 aux_dev = iter; 276 break; 277 } 278 } 279 mutex_unlock(&aux_idr_mutex); 280 return aux_dev; 281} 282 283static int auxdev_wait_atomic_t(atomic_t *p) 284{ 285 schedule(); 286 return 0; 287} 288 289void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) 290{ 291 struct drm_dp_aux_dev *aux_dev; 292 unsigned int minor; 293 294 aux_dev = drm_dp_aux_dev_get_by_aux(aux); 295 if (!aux_dev) /* attach must have failed */ 296 return; 297 298 mutex_lock(&aux_idr_mutex); 299 idr_remove(&aux_idr, aux_dev->index); 300 mutex_unlock(&aux_idr_mutex); 301 302 atomic_dec(&aux_dev->usecount); 303 wait_on_atomic_t(&aux_dev->usecount, auxdev_wait_atomic_t, 304 TASK_UNINTERRUPTIBLE); 305 306 minor = aux_dev->index; 307 if (aux_dev->dev) 308 device_destroy(drm_dp_aux_dev_class, 309 MKDEV(drm_dev_major, minor)); 310 311 DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name); 312 kref_put(&aux_dev->refcount, release_drm_dp_aux_dev); 313} 314 315int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) 316{ 317 struct drm_dp_aux_dev *aux_dev; 318 int res; 319 320 aux_dev = alloc_drm_dp_aux_dev(aux); 321 if (IS_ERR(aux_dev)) 322 return PTR_ERR(aux_dev); 323 324 aux_dev->dev = device_create(drm_dp_aux_dev_class, aux->dev, 325 MKDEV(drm_dev_major, aux_dev->index), NULL, 326 "drm_dp_aux%d", aux_dev->index); 327 if (IS_ERR(aux_dev->dev)) { 328 res = PTR_ERR(aux_dev->dev); 329 aux_dev->dev = NULL; 330 goto error; 331 } 332 333 DRM_DEBUG("drm_dp_aux_dev: aux [%s] registered as minor %d\n", 334 aux->name, aux_dev->index); 335 return 0; 336error: 337 drm_dp_aux_unregister_devnode(aux); 338 return res; 339} 340 341int drm_dp_aux_dev_init(void) 342{ 343 int res; 344 345 drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev"); 346 if (IS_ERR(drm_dp_aux_dev_class)) { 347 return PTR_ERR(drm_dp_aux_dev_class); 348 } 349 drm_dp_aux_dev_class->dev_groups = drm_dp_aux_groups; 350 351 res = register_chrdev(0, "aux", &auxdev_fops); 352 if (res < 0) 353 goto out; 354 drm_dev_major = res; 355 356 return 0; 357out: 358 class_destroy(drm_dp_aux_dev_class); 359 return res; 360} 361 362void drm_dp_aux_dev_exit(void) 363{ 364 unregister_chrdev(drm_dev_major, "aux"); 365 class_destroy(drm_dp_aux_dev_class); 366}