1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * drivers/uio/uio.c |
4 | * |
5 | * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de> |
6 | * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> |
7 | * Copyright(C) 2006, Hans J. Koch <hjk@hansjkoch.de> |
8 | * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com> |
9 | * |
10 | * Userspace IO |
11 | * |
12 | * Base Functions |
13 | */ |
14 | |
15 | #include <linux/module.h> |
16 | #include <linux/init.h> |
17 | #include <linux/poll.h> |
18 | #include <linux/device.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/mm.h> |
21 | #include <linux/idr.h> |
22 | #include <linux/sched/signal.h> |
23 | #include <linux/string.h> |
24 | #include <linux/kobject.h> |
25 | #include <linux/cdev.h> |
26 | #include <linux/uio_driver.h> |
27 | |
28 | #define UIO_MAX_DEVICES (1U << MINORBITS) |
29 | |
30 | static int uio_major; |
31 | static struct cdev *uio_cdev; |
32 | static DEFINE_IDR(uio_idr); |
33 | static const struct file_operations uio_fops; |
34 | |
35 | /* Protect idr accesses */ |
36 | static DEFINE_MUTEX(minor_lock); |
37 | |
38 | /* |
39 | * attributes |
40 | */ |
41 | |
42 | struct uio_map { |
43 | struct kobject kobj; |
44 | struct uio_mem *mem; |
45 | }; |
46 | #define to_map(map) container_of(map, struct uio_map, kobj) |
47 | |
48 | static ssize_t map_name_show(struct uio_mem *mem, char *buf) |
49 | { |
50 | if (unlikely(!mem->name)) |
51 | mem->name = "" ; |
52 | |
53 | return sprintf(buf, fmt: "%s\n" , mem->name); |
54 | } |
55 | |
56 | static ssize_t map_addr_show(struct uio_mem *mem, char *buf) |
57 | { |
58 | return sprintf(buf, fmt: "%pa\n" , &mem->addr); |
59 | } |
60 | |
61 | static ssize_t map_size_show(struct uio_mem *mem, char *buf) |
62 | { |
63 | return sprintf(buf, fmt: "%pa\n" , &mem->size); |
64 | } |
65 | |
66 | static ssize_t map_offset_show(struct uio_mem *mem, char *buf) |
67 | { |
68 | return sprintf(buf, fmt: "0x%llx\n" , (unsigned long long)mem->offs); |
69 | } |
70 | |
71 | struct map_sysfs_entry { |
72 | struct attribute attr; |
73 | ssize_t (*show)(struct uio_mem *, char *); |
74 | ssize_t (*store)(struct uio_mem *, const char *, size_t); |
75 | }; |
76 | |
77 | static struct map_sysfs_entry name_attribute = |
78 | __ATTR(name, S_IRUGO, map_name_show, NULL); |
79 | static struct map_sysfs_entry addr_attribute = |
80 | __ATTR(addr, S_IRUGO, map_addr_show, NULL); |
81 | static struct map_sysfs_entry size_attribute = |
82 | __ATTR(size, S_IRUGO, map_size_show, NULL); |
83 | static struct map_sysfs_entry offset_attribute = |
84 | __ATTR(offset, S_IRUGO, map_offset_show, NULL); |
85 | |
86 | static struct attribute *map_attrs[] = { |
87 | &name_attribute.attr, |
88 | &addr_attribute.attr, |
89 | &size_attribute.attr, |
90 | &offset_attribute.attr, |
91 | NULL, /* need to NULL terminate the list of attributes */ |
92 | }; |
93 | ATTRIBUTE_GROUPS(map); |
94 | |
95 | static void map_release(struct kobject *kobj) |
96 | { |
97 | struct uio_map *map = to_map(kobj); |
98 | kfree(objp: map); |
99 | } |
100 | |
101 | static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr, |
102 | char *buf) |
103 | { |
104 | struct uio_map *map = to_map(kobj); |
105 | struct uio_mem *mem = map->mem; |
106 | struct map_sysfs_entry *entry; |
107 | |
108 | entry = container_of(attr, struct map_sysfs_entry, attr); |
109 | |
110 | if (!entry->show) |
111 | return -EIO; |
112 | |
113 | return entry->show(mem, buf); |
114 | } |
115 | |
116 | static const struct sysfs_ops map_sysfs_ops = { |
117 | .show = map_type_show, |
118 | }; |
119 | |
120 | static struct kobj_type map_attr_type = { |
121 | .release = map_release, |
122 | .sysfs_ops = &map_sysfs_ops, |
123 | .default_groups = map_groups, |
124 | }; |
125 | |
126 | struct uio_portio { |
127 | struct kobject kobj; |
128 | struct uio_port *port; |
129 | }; |
130 | #define to_portio(portio) container_of(portio, struct uio_portio, kobj) |
131 | |
132 | static ssize_t portio_name_show(struct uio_port *port, char *buf) |
133 | { |
134 | if (unlikely(!port->name)) |
135 | port->name = "" ; |
136 | |
137 | return sprintf(buf, fmt: "%s\n" , port->name); |
138 | } |
139 | |
140 | static ssize_t portio_start_show(struct uio_port *port, char *buf) |
141 | { |
142 | return sprintf(buf, fmt: "0x%lx\n" , port->start); |
143 | } |
144 | |
145 | static ssize_t portio_size_show(struct uio_port *port, char *buf) |
146 | { |
147 | return sprintf(buf, fmt: "0x%lx\n" , port->size); |
148 | } |
149 | |
150 | static ssize_t portio_porttype_show(struct uio_port *port, char *buf) |
151 | { |
152 | const char *porttypes[] = {"none" , "x86" , "gpio" , "other" }; |
153 | |
154 | if ((port->porttype < 0) || (port->porttype > UIO_PORT_OTHER)) |
155 | return -EINVAL; |
156 | |
157 | return sprintf(buf, fmt: "port_%s\n" , porttypes[port->porttype]); |
158 | } |
159 | |
160 | struct portio_sysfs_entry { |
161 | struct attribute attr; |
162 | ssize_t (*show)(struct uio_port *, char *); |
163 | ssize_t (*store)(struct uio_port *, const char *, size_t); |
164 | }; |
165 | |
166 | static struct portio_sysfs_entry portio_name_attribute = |
167 | __ATTR(name, S_IRUGO, portio_name_show, NULL); |
168 | static struct portio_sysfs_entry portio_start_attribute = |
169 | __ATTR(start, S_IRUGO, portio_start_show, NULL); |
170 | static struct portio_sysfs_entry portio_size_attribute = |
171 | __ATTR(size, S_IRUGO, portio_size_show, NULL); |
172 | static struct portio_sysfs_entry portio_porttype_attribute = |
173 | __ATTR(porttype, S_IRUGO, portio_porttype_show, NULL); |
174 | |
175 | static struct attribute *portio_attrs[] = { |
176 | &portio_name_attribute.attr, |
177 | &portio_start_attribute.attr, |
178 | &portio_size_attribute.attr, |
179 | &portio_porttype_attribute.attr, |
180 | NULL, |
181 | }; |
182 | ATTRIBUTE_GROUPS(portio); |
183 | |
184 | static void portio_release(struct kobject *kobj) |
185 | { |
186 | struct uio_portio *portio = to_portio(kobj); |
187 | kfree(objp: portio); |
188 | } |
189 | |
190 | static ssize_t portio_type_show(struct kobject *kobj, struct attribute *attr, |
191 | char *buf) |
192 | { |
193 | struct uio_portio *portio = to_portio(kobj); |
194 | struct uio_port *port = portio->port; |
195 | struct portio_sysfs_entry *entry; |
196 | |
197 | entry = container_of(attr, struct portio_sysfs_entry, attr); |
198 | |
199 | if (!entry->show) |
200 | return -EIO; |
201 | |
202 | return entry->show(port, buf); |
203 | } |
204 | |
205 | static const struct sysfs_ops portio_sysfs_ops = { |
206 | .show = portio_type_show, |
207 | }; |
208 | |
209 | static struct kobj_type portio_attr_type = { |
210 | .release = portio_release, |
211 | .sysfs_ops = &portio_sysfs_ops, |
212 | .default_groups = portio_groups, |
213 | }; |
214 | |
215 | static ssize_t name_show(struct device *dev, |
216 | struct device_attribute *attr, char *buf) |
217 | { |
218 | struct uio_device *idev = dev_get_drvdata(dev); |
219 | int ret; |
220 | |
221 | mutex_lock(&idev->info_lock); |
222 | if (!idev->info) { |
223 | ret = -EINVAL; |
224 | dev_err(dev, "the device has been unregistered\n" ); |
225 | goto out; |
226 | } |
227 | |
228 | ret = sprintf(buf, fmt: "%s\n" , idev->info->name); |
229 | |
230 | out: |
231 | mutex_unlock(lock: &idev->info_lock); |
232 | return ret; |
233 | } |
234 | static DEVICE_ATTR_RO(name); |
235 | |
236 | static ssize_t version_show(struct device *dev, |
237 | struct device_attribute *attr, char *buf) |
238 | { |
239 | struct uio_device *idev = dev_get_drvdata(dev); |
240 | int ret; |
241 | |
242 | mutex_lock(&idev->info_lock); |
243 | if (!idev->info) { |
244 | ret = -EINVAL; |
245 | dev_err(dev, "the device has been unregistered\n" ); |
246 | goto out; |
247 | } |
248 | |
249 | ret = sprintf(buf, fmt: "%s\n" , idev->info->version); |
250 | |
251 | out: |
252 | mutex_unlock(lock: &idev->info_lock); |
253 | return ret; |
254 | } |
255 | static DEVICE_ATTR_RO(version); |
256 | |
257 | static ssize_t event_show(struct device *dev, |
258 | struct device_attribute *attr, char *buf) |
259 | { |
260 | struct uio_device *idev = dev_get_drvdata(dev); |
261 | return sprintf(buf, fmt: "%u\n" , (unsigned int)atomic_read(v: &idev->event)); |
262 | } |
263 | static DEVICE_ATTR_RO(event); |
264 | |
265 | static struct attribute *uio_attrs[] = { |
266 | &dev_attr_name.attr, |
267 | &dev_attr_version.attr, |
268 | &dev_attr_event.attr, |
269 | NULL, |
270 | }; |
271 | ATTRIBUTE_GROUPS(uio); |
272 | |
273 | /* UIO class infrastructure */ |
274 | static struct class uio_class = { |
275 | .name = "uio" , |
276 | .dev_groups = uio_groups, |
277 | }; |
278 | |
279 | static bool uio_class_registered; |
280 | |
281 | /* |
282 | * device functions |
283 | */ |
284 | static int uio_dev_add_attributes(struct uio_device *idev) |
285 | { |
286 | int ret; |
287 | int mi, pi; |
288 | int map_found = 0; |
289 | int portio_found = 0; |
290 | struct uio_mem *mem; |
291 | struct uio_map *map; |
292 | struct uio_port *port; |
293 | struct uio_portio *portio; |
294 | |
295 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { |
296 | mem = &idev->info->mem[mi]; |
297 | if (mem->size == 0) |
298 | break; |
299 | if (!map_found) { |
300 | map_found = 1; |
301 | idev->map_dir = kobject_create_and_add(name: "maps" , |
302 | parent: &idev->dev.kobj); |
303 | if (!idev->map_dir) { |
304 | ret = -ENOMEM; |
305 | goto err_map; |
306 | } |
307 | } |
308 | map = kzalloc(size: sizeof(*map), GFP_KERNEL); |
309 | if (!map) { |
310 | ret = -ENOMEM; |
311 | goto err_map; |
312 | } |
313 | kobject_init(kobj: &map->kobj, ktype: &map_attr_type); |
314 | map->mem = mem; |
315 | mem->map = map; |
316 | ret = kobject_add(kobj: &map->kobj, parent: idev->map_dir, fmt: "map%d" , mi); |
317 | if (ret) |
318 | goto err_map_kobj; |
319 | ret = kobject_uevent(kobj: &map->kobj, action: KOBJ_ADD); |
320 | if (ret) |
321 | goto err_map_kobj; |
322 | } |
323 | |
324 | for (pi = 0; pi < MAX_UIO_PORT_REGIONS; pi++) { |
325 | port = &idev->info->port[pi]; |
326 | if (port->size == 0) |
327 | break; |
328 | if (!portio_found) { |
329 | portio_found = 1; |
330 | idev->portio_dir = kobject_create_and_add(name: "portio" , |
331 | parent: &idev->dev.kobj); |
332 | if (!idev->portio_dir) { |
333 | ret = -ENOMEM; |
334 | goto err_portio; |
335 | } |
336 | } |
337 | portio = kzalloc(size: sizeof(*portio), GFP_KERNEL); |
338 | if (!portio) { |
339 | ret = -ENOMEM; |
340 | goto err_portio; |
341 | } |
342 | kobject_init(kobj: &portio->kobj, ktype: &portio_attr_type); |
343 | portio->port = port; |
344 | port->portio = portio; |
345 | ret = kobject_add(kobj: &portio->kobj, parent: idev->portio_dir, |
346 | fmt: "port%d" , pi); |
347 | if (ret) |
348 | goto err_portio_kobj; |
349 | ret = kobject_uevent(kobj: &portio->kobj, action: KOBJ_ADD); |
350 | if (ret) |
351 | goto err_portio_kobj; |
352 | } |
353 | |
354 | return 0; |
355 | |
356 | err_portio: |
357 | pi--; |
358 | err_portio_kobj: |
359 | for (; pi >= 0; pi--) { |
360 | port = &idev->info->port[pi]; |
361 | portio = port->portio; |
362 | kobject_put(kobj: &portio->kobj); |
363 | } |
364 | kobject_put(kobj: idev->portio_dir); |
365 | err_map: |
366 | mi--; |
367 | err_map_kobj: |
368 | for (; mi >= 0; mi--) { |
369 | mem = &idev->info->mem[mi]; |
370 | map = mem->map; |
371 | kobject_put(kobj: &map->kobj); |
372 | } |
373 | kobject_put(kobj: idev->map_dir); |
374 | dev_err(&idev->dev, "error creating sysfs files (%d)\n" , ret); |
375 | return ret; |
376 | } |
377 | |
378 | static void uio_dev_del_attributes(struct uio_device *idev) |
379 | { |
380 | int i; |
381 | struct uio_mem *mem; |
382 | struct uio_port *port; |
383 | |
384 | for (i = 0; i < MAX_UIO_MAPS; i++) { |
385 | mem = &idev->info->mem[i]; |
386 | if (mem->size == 0) |
387 | break; |
388 | kobject_put(kobj: &mem->map->kobj); |
389 | } |
390 | kobject_put(kobj: idev->map_dir); |
391 | |
392 | for (i = 0; i < MAX_UIO_PORT_REGIONS; i++) { |
393 | port = &idev->info->port[i]; |
394 | if (port->size == 0) |
395 | break; |
396 | kobject_put(kobj: &port->portio->kobj); |
397 | } |
398 | kobject_put(kobj: idev->portio_dir); |
399 | } |
400 | |
401 | static int uio_get_minor(struct uio_device *idev) |
402 | { |
403 | int retval; |
404 | |
405 | mutex_lock(&minor_lock); |
406 | retval = idr_alloc(&uio_idr, ptr: idev, start: 0, UIO_MAX_DEVICES, GFP_KERNEL); |
407 | if (retval >= 0) { |
408 | idev->minor = retval; |
409 | retval = 0; |
410 | } else if (retval == -ENOSPC) { |
411 | dev_err(&idev->dev, "too many uio devices\n" ); |
412 | retval = -EINVAL; |
413 | } |
414 | mutex_unlock(lock: &minor_lock); |
415 | return retval; |
416 | } |
417 | |
418 | static void uio_free_minor(unsigned long minor) |
419 | { |
420 | mutex_lock(&minor_lock); |
421 | idr_remove(&uio_idr, id: minor); |
422 | mutex_unlock(lock: &minor_lock); |
423 | } |
424 | |
425 | /** |
426 | * uio_event_notify - trigger an interrupt event |
427 | * @info: UIO device capabilities |
428 | */ |
429 | void uio_event_notify(struct uio_info *info) |
430 | { |
431 | struct uio_device *idev = info->uio_dev; |
432 | |
433 | atomic_inc(v: &idev->event); |
434 | wake_up_interruptible(&idev->wait); |
435 | kill_fasync(&idev->async_queue, SIGIO, POLL_IN); |
436 | } |
437 | EXPORT_SYMBOL_GPL(uio_event_notify); |
438 | |
439 | /** |
440 | * uio_interrupt - hardware interrupt handler |
441 | * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer |
442 | * @dev_id: Pointer to the devices uio_device structure |
443 | */ |
444 | static irqreturn_t uio_interrupt(int irq, void *dev_id) |
445 | { |
446 | struct uio_device *idev = (struct uio_device *)dev_id; |
447 | irqreturn_t ret; |
448 | |
449 | ret = idev->info->handler(irq, idev->info); |
450 | if (ret == IRQ_HANDLED) |
451 | uio_event_notify(idev->info); |
452 | |
453 | return ret; |
454 | } |
455 | |
456 | struct uio_listener { |
457 | struct uio_device *dev; |
458 | s32 event_count; |
459 | }; |
460 | |
461 | static int uio_open(struct inode *inode, struct file *filep) |
462 | { |
463 | struct uio_device *idev; |
464 | struct uio_listener *listener; |
465 | int ret = 0; |
466 | |
467 | mutex_lock(&minor_lock); |
468 | idev = idr_find(&uio_idr, id: iminor(inode)); |
469 | mutex_unlock(lock: &minor_lock); |
470 | if (!idev) { |
471 | ret = -ENODEV; |
472 | goto out; |
473 | } |
474 | |
475 | get_device(dev: &idev->dev); |
476 | |
477 | if (!try_module_get(module: idev->owner)) { |
478 | ret = -ENODEV; |
479 | goto err_module_get; |
480 | } |
481 | |
482 | listener = kmalloc(size: sizeof(*listener), GFP_KERNEL); |
483 | if (!listener) { |
484 | ret = -ENOMEM; |
485 | goto err_alloc_listener; |
486 | } |
487 | |
488 | listener->dev = idev; |
489 | listener->event_count = atomic_read(v: &idev->event); |
490 | filep->private_data = listener; |
491 | |
492 | mutex_lock(&idev->info_lock); |
493 | if (!idev->info) { |
494 | mutex_unlock(lock: &idev->info_lock); |
495 | ret = -EINVAL; |
496 | goto err_infoopen; |
497 | } |
498 | |
499 | if (idev->info->open) |
500 | ret = idev->info->open(idev->info, inode); |
501 | mutex_unlock(lock: &idev->info_lock); |
502 | if (ret) |
503 | goto err_infoopen; |
504 | |
505 | return 0; |
506 | |
507 | err_infoopen: |
508 | kfree(objp: listener); |
509 | |
510 | err_alloc_listener: |
511 | module_put(module: idev->owner); |
512 | |
513 | err_module_get: |
514 | put_device(dev: &idev->dev); |
515 | |
516 | out: |
517 | return ret; |
518 | } |
519 | |
520 | static int uio_fasync(int fd, struct file *filep, int on) |
521 | { |
522 | struct uio_listener *listener = filep->private_data; |
523 | struct uio_device *idev = listener->dev; |
524 | |
525 | return fasync_helper(fd, filep, on, &idev->async_queue); |
526 | } |
527 | |
528 | static int uio_release(struct inode *inode, struct file *filep) |
529 | { |
530 | int ret = 0; |
531 | struct uio_listener *listener = filep->private_data; |
532 | struct uio_device *idev = listener->dev; |
533 | |
534 | mutex_lock(&idev->info_lock); |
535 | if (idev->info && idev->info->release) |
536 | ret = idev->info->release(idev->info, inode); |
537 | mutex_unlock(lock: &idev->info_lock); |
538 | |
539 | module_put(module: idev->owner); |
540 | kfree(objp: listener); |
541 | put_device(dev: &idev->dev); |
542 | return ret; |
543 | } |
544 | |
545 | static __poll_t uio_poll(struct file *filep, poll_table *wait) |
546 | { |
547 | struct uio_listener *listener = filep->private_data; |
548 | struct uio_device *idev = listener->dev; |
549 | __poll_t ret = 0; |
550 | |
551 | mutex_lock(&idev->info_lock); |
552 | if (!idev->info || !idev->info->irq) |
553 | ret = -EIO; |
554 | mutex_unlock(lock: &idev->info_lock); |
555 | |
556 | if (ret) |
557 | return ret; |
558 | |
559 | poll_wait(filp: filep, wait_address: &idev->wait, p: wait); |
560 | if (listener->event_count != atomic_read(v: &idev->event)) |
561 | return EPOLLIN | EPOLLRDNORM; |
562 | return 0; |
563 | } |
564 | |
565 | static ssize_t uio_read(struct file *filep, char __user *buf, |
566 | size_t count, loff_t *ppos) |
567 | { |
568 | struct uio_listener *listener = filep->private_data; |
569 | struct uio_device *idev = listener->dev; |
570 | DECLARE_WAITQUEUE(wait, current); |
571 | ssize_t retval = 0; |
572 | s32 event_count; |
573 | |
574 | if (count != sizeof(s32)) |
575 | return -EINVAL; |
576 | |
577 | add_wait_queue(wq_head: &idev->wait, wq_entry: &wait); |
578 | |
579 | do { |
580 | mutex_lock(&idev->info_lock); |
581 | if (!idev->info || !idev->info->irq) { |
582 | retval = -EIO; |
583 | mutex_unlock(lock: &idev->info_lock); |
584 | break; |
585 | } |
586 | mutex_unlock(lock: &idev->info_lock); |
587 | |
588 | set_current_state(TASK_INTERRUPTIBLE); |
589 | |
590 | event_count = atomic_read(v: &idev->event); |
591 | if (event_count != listener->event_count) { |
592 | __set_current_state(TASK_RUNNING); |
593 | if (copy_to_user(to: buf, from: &event_count, n: count)) |
594 | retval = -EFAULT; |
595 | else { |
596 | listener->event_count = event_count; |
597 | retval = count; |
598 | } |
599 | break; |
600 | } |
601 | |
602 | if (filep->f_flags & O_NONBLOCK) { |
603 | retval = -EAGAIN; |
604 | break; |
605 | } |
606 | |
607 | if (signal_pending(current)) { |
608 | retval = -ERESTARTSYS; |
609 | break; |
610 | } |
611 | schedule(); |
612 | } while (1); |
613 | |
614 | __set_current_state(TASK_RUNNING); |
615 | remove_wait_queue(wq_head: &idev->wait, wq_entry: &wait); |
616 | |
617 | return retval; |
618 | } |
619 | |
620 | static ssize_t uio_write(struct file *filep, const char __user *buf, |
621 | size_t count, loff_t *ppos) |
622 | { |
623 | struct uio_listener *listener = filep->private_data; |
624 | struct uio_device *idev = listener->dev; |
625 | ssize_t retval; |
626 | s32 irq_on; |
627 | |
628 | if (count != sizeof(s32)) |
629 | return -EINVAL; |
630 | |
631 | if (copy_from_user(to: &irq_on, from: buf, n: count)) |
632 | return -EFAULT; |
633 | |
634 | mutex_lock(&idev->info_lock); |
635 | if (!idev->info) { |
636 | retval = -EINVAL; |
637 | goto out; |
638 | } |
639 | |
640 | if (!idev->info->irq) { |
641 | retval = -EIO; |
642 | goto out; |
643 | } |
644 | |
645 | if (!idev->info->irqcontrol) { |
646 | retval = -ENOSYS; |
647 | goto out; |
648 | } |
649 | |
650 | retval = idev->info->irqcontrol(idev->info, irq_on); |
651 | |
652 | out: |
653 | mutex_unlock(lock: &idev->info_lock); |
654 | return retval ? retval : sizeof(s32); |
655 | } |
656 | |
657 | static int uio_find_mem_index(struct vm_area_struct *vma) |
658 | { |
659 | struct uio_device *idev = vma->vm_private_data; |
660 | |
661 | if (vma->vm_pgoff < MAX_UIO_MAPS) { |
662 | if (idev->info->mem[vma->vm_pgoff].size == 0) |
663 | return -1; |
664 | return (int)vma->vm_pgoff; |
665 | } |
666 | return -1; |
667 | } |
668 | |
669 | static vm_fault_t uio_vma_fault(struct vm_fault *vmf) |
670 | { |
671 | struct uio_device *idev = vmf->vma->vm_private_data; |
672 | struct page *page; |
673 | unsigned long offset; |
674 | void *addr; |
675 | vm_fault_t ret = 0; |
676 | int mi; |
677 | |
678 | mutex_lock(&idev->info_lock); |
679 | if (!idev->info) { |
680 | ret = VM_FAULT_SIGBUS; |
681 | goto out; |
682 | } |
683 | |
684 | mi = uio_find_mem_index(vma: vmf->vma); |
685 | if (mi < 0) { |
686 | ret = VM_FAULT_SIGBUS; |
687 | goto out; |
688 | } |
689 | |
690 | /* |
691 | * We need to subtract mi because userspace uses offset = N*PAGE_SIZE |
692 | * to use mem[N]. |
693 | */ |
694 | offset = (vmf->pgoff - mi) << PAGE_SHIFT; |
695 | |
696 | addr = (void *)(unsigned long)idev->info->mem[mi].addr + offset; |
697 | if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) |
698 | page = virt_to_page(addr); |
699 | else |
700 | page = vmalloc_to_page(addr); |
701 | get_page(page); |
702 | vmf->page = page; |
703 | |
704 | out: |
705 | mutex_unlock(lock: &idev->info_lock); |
706 | |
707 | return ret; |
708 | } |
709 | |
710 | static const struct vm_operations_struct uio_logical_vm_ops = { |
711 | .fault = uio_vma_fault, |
712 | }; |
713 | |
714 | static int uio_mmap_logical(struct vm_area_struct *vma) |
715 | { |
716 | vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); |
717 | vma->vm_ops = &uio_logical_vm_ops; |
718 | return 0; |
719 | } |
720 | |
721 | static const struct vm_operations_struct uio_physical_vm_ops = { |
722 | #ifdef CONFIG_HAVE_IOREMAP_PROT |
723 | .access = generic_access_phys, |
724 | #endif |
725 | }; |
726 | |
727 | static int uio_mmap_physical(struct vm_area_struct *vma) |
728 | { |
729 | struct uio_device *idev = vma->vm_private_data; |
730 | int mi = uio_find_mem_index(vma); |
731 | struct uio_mem *mem; |
732 | |
733 | if (mi < 0) |
734 | return -EINVAL; |
735 | mem = idev->info->mem + mi; |
736 | |
737 | if (mem->addr & ~PAGE_MASK) |
738 | return -ENODEV; |
739 | if (vma->vm_end - vma->vm_start > mem->size) |
740 | return -EINVAL; |
741 | |
742 | vma->vm_ops = &uio_physical_vm_ops; |
743 | if (idev->info->mem[mi].memtype == UIO_MEM_PHYS) |
744 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
745 | |
746 | /* |
747 | * We cannot use the vm_iomap_memory() helper here, |
748 | * because vma->vm_pgoff is the map index we looked |
749 | * up above in uio_find_mem_index(), rather than an |
750 | * actual page offset into the mmap. |
751 | * |
752 | * So we just do the physical mmap without a page |
753 | * offset. |
754 | */ |
755 | return remap_pfn_range(vma, |
756 | addr: vma->vm_start, |
757 | pfn: mem->addr >> PAGE_SHIFT, |
758 | size: vma->vm_end - vma->vm_start, |
759 | vma->vm_page_prot); |
760 | } |
761 | |
762 | static int uio_mmap(struct file *filep, struct vm_area_struct *vma) |
763 | { |
764 | struct uio_listener *listener = filep->private_data; |
765 | struct uio_device *idev = listener->dev; |
766 | int mi; |
767 | unsigned long requested_pages, actual_pages; |
768 | int ret = 0; |
769 | |
770 | if (vma->vm_end < vma->vm_start) |
771 | return -EINVAL; |
772 | |
773 | vma->vm_private_data = idev; |
774 | |
775 | mutex_lock(&idev->info_lock); |
776 | if (!idev->info) { |
777 | ret = -EINVAL; |
778 | goto out; |
779 | } |
780 | |
781 | mi = uio_find_mem_index(vma); |
782 | if (mi < 0) { |
783 | ret = -EINVAL; |
784 | goto out; |
785 | } |
786 | |
787 | requested_pages = vma_pages(vma); |
788 | actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK) |
789 | + idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT; |
790 | if (requested_pages > actual_pages) { |
791 | ret = -EINVAL; |
792 | goto out; |
793 | } |
794 | |
795 | if (idev->info->mmap) { |
796 | ret = idev->info->mmap(idev->info, vma); |
797 | goto out; |
798 | } |
799 | |
800 | switch (idev->info->mem[mi].memtype) { |
801 | case UIO_MEM_IOVA: |
802 | case UIO_MEM_PHYS: |
803 | ret = uio_mmap_physical(vma); |
804 | break; |
805 | case UIO_MEM_LOGICAL: |
806 | case UIO_MEM_VIRTUAL: |
807 | ret = uio_mmap_logical(vma); |
808 | break; |
809 | default: |
810 | ret = -EINVAL; |
811 | } |
812 | |
813 | out: |
814 | mutex_unlock(lock: &idev->info_lock); |
815 | return ret; |
816 | } |
817 | |
818 | static const struct file_operations uio_fops = { |
819 | .owner = THIS_MODULE, |
820 | .open = uio_open, |
821 | .release = uio_release, |
822 | .read = uio_read, |
823 | .write = uio_write, |
824 | .mmap = uio_mmap, |
825 | .poll = uio_poll, |
826 | .fasync = uio_fasync, |
827 | .llseek = noop_llseek, |
828 | }; |
829 | |
830 | static int uio_major_init(void) |
831 | { |
832 | static const char name[] = "uio" ; |
833 | struct cdev *cdev = NULL; |
834 | dev_t uio_dev = 0; |
835 | int result; |
836 | |
837 | result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name); |
838 | if (result) |
839 | goto out; |
840 | |
841 | result = -ENOMEM; |
842 | cdev = cdev_alloc(); |
843 | if (!cdev) |
844 | goto out_unregister; |
845 | |
846 | cdev->owner = THIS_MODULE; |
847 | cdev->ops = &uio_fops; |
848 | kobject_set_name(kobj: &cdev->kobj, name: "%s" , name); |
849 | |
850 | result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES); |
851 | if (result) |
852 | goto out_put; |
853 | |
854 | uio_major = MAJOR(uio_dev); |
855 | uio_cdev = cdev; |
856 | return 0; |
857 | out_put: |
858 | kobject_put(kobj: &cdev->kobj); |
859 | out_unregister: |
860 | unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES); |
861 | out: |
862 | return result; |
863 | } |
864 | |
865 | static void uio_major_cleanup(void) |
866 | { |
867 | unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES); |
868 | cdev_del(uio_cdev); |
869 | } |
870 | |
871 | static int init_uio_class(void) |
872 | { |
873 | int ret; |
874 | |
875 | /* This is the first time in here, set everything up properly */ |
876 | ret = uio_major_init(); |
877 | if (ret) |
878 | goto exit; |
879 | |
880 | ret = class_register(class: &uio_class); |
881 | if (ret) { |
882 | printk(KERN_ERR "class_register failed for uio\n" ); |
883 | goto err_class_register; |
884 | } |
885 | |
886 | uio_class_registered = true; |
887 | |
888 | return 0; |
889 | |
890 | err_class_register: |
891 | uio_major_cleanup(); |
892 | exit: |
893 | return ret; |
894 | } |
895 | |
896 | static void release_uio_class(void) |
897 | { |
898 | uio_class_registered = false; |
899 | class_unregister(class: &uio_class); |
900 | uio_major_cleanup(); |
901 | } |
902 | |
903 | static void uio_device_release(struct device *dev) |
904 | { |
905 | struct uio_device *idev = dev_get_drvdata(dev); |
906 | |
907 | kfree(objp: idev); |
908 | } |
909 | |
910 | /** |
911 | * __uio_register_device - register a new userspace IO device |
912 | * @owner: module that creates the new device |
913 | * @parent: parent device |
914 | * @info: UIO device capabilities |
915 | * |
916 | * returns zero on success or a negative error code. |
917 | */ |
918 | int __uio_register_device(struct module *owner, |
919 | struct device *parent, |
920 | struct uio_info *info) |
921 | { |
922 | struct uio_device *idev; |
923 | int ret = 0; |
924 | |
925 | if (!uio_class_registered) |
926 | return -EPROBE_DEFER; |
927 | |
928 | if (!parent || !info || !info->name || !info->version) |
929 | return -EINVAL; |
930 | |
931 | info->uio_dev = NULL; |
932 | |
933 | idev = kzalloc(size: sizeof(*idev), GFP_KERNEL); |
934 | if (!idev) { |
935 | return -ENOMEM; |
936 | } |
937 | |
938 | idev->owner = owner; |
939 | idev->info = info; |
940 | mutex_init(&idev->info_lock); |
941 | init_waitqueue_head(&idev->wait); |
942 | atomic_set(v: &idev->event, i: 0); |
943 | |
944 | ret = uio_get_minor(idev); |
945 | if (ret) { |
946 | kfree(objp: idev); |
947 | return ret; |
948 | } |
949 | |
950 | device_initialize(dev: &idev->dev); |
951 | idev->dev.devt = MKDEV(uio_major, idev->minor); |
952 | idev->dev.class = &uio_class; |
953 | idev->dev.parent = parent; |
954 | idev->dev.release = uio_device_release; |
955 | dev_set_drvdata(dev: &idev->dev, data: idev); |
956 | |
957 | ret = dev_set_name(dev: &idev->dev, name: "uio%d" , idev->minor); |
958 | if (ret) |
959 | goto err_device_create; |
960 | |
961 | ret = device_add(dev: &idev->dev); |
962 | if (ret) |
963 | goto err_device_create; |
964 | |
965 | ret = uio_dev_add_attributes(idev); |
966 | if (ret) |
967 | goto err_uio_dev_add_attributes; |
968 | |
969 | info->uio_dev = idev; |
970 | |
971 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { |
972 | /* |
973 | * Note that we deliberately don't use devm_request_irq |
974 | * here. The parent module can unregister the UIO device |
975 | * and call pci_disable_msi, which requires that this |
976 | * irq has been freed. However, the device may have open |
977 | * FDs at the time of unregister and therefore may not be |
978 | * freed until they are released. |
979 | */ |
980 | ret = request_irq(irq: info->irq, handler: uio_interrupt, |
981 | flags: info->irq_flags, name: info->name, dev: idev); |
982 | if (ret) { |
983 | info->uio_dev = NULL; |
984 | goto err_request_irq; |
985 | } |
986 | } |
987 | |
988 | return 0; |
989 | |
990 | err_request_irq: |
991 | uio_dev_del_attributes(idev); |
992 | err_uio_dev_add_attributes: |
993 | device_del(dev: &idev->dev); |
994 | err_device_create: |
995 | uio_free_minor(minor: idev->minor); |
996 | put_device(dev: &idev->dev); |
997 | return ret; |
998 | } |
999 | EXPORT_SYMBOL_GPL(__uio_register_device); |
1000 | |
1001 | static void devm_uio_unregister_device(struct device *dev, void *res) |
1002 | { |
1003 | uio_unregister_device(info: *(struct uio_info **)res); |
1004 | } |
1005 | |
1006 | /** |
1007 | * __devm_uio_register_device - Resource managed uio_register_device() |
1008 | * @owner: module that creates the new device |
1009 | * @parent: parent device |
1010 | * @info: UIO device capabilities |
1011 | * |
1012 | * returns zero on success or a negative error code. |
1013 | */ |
1014 | int __devm_uio_register_device(struct module *owner, |
1015 | struct device *parent, |
1016 | struct uio_info *info) |
1017 | { |
1018 | struct uio_info **ptr; |
1019 | int ret; |
1020 | |
1021 | ptr = devres_alloc(devm_uio_unregister_device, sizeof(*ptr), |
1022 | GFP_KERNEL); |
1023 | if (!ptr) |
1024 | return -ENOMEM; |
1025 | |
1026 | *ptr = info; |
1027 | ret = __uio_register_device(owner, parent, info); |
1028 | if (ret) { |
1029 | devres_free(res: ptr); |
1030 | return ret; |
1031 | } |
1032 | |
1033 | devres_add(dev: parent, res: ptr); |
1034 | |
1035 | return 0; |
1036 | } |
1037 | EXPORT_SYMBOL_GPL(__devm_uio_register_device); |
1038 | |
1039 | /** |
1040 | * uio_unregister_device - unregister a industrial IO device |
1041 | * @info: UIO device capabilities |
1042 | * |
1043 | */ |
1044 | void uio_unregister_device(struct uio_info *info) |
1045 | { |
1046 | struct uio_device *idev; |
1047 | unsigned long minor; |
1048 | |
1049 | if (!info || !info->uio_dev) |
1050 | return; |
1051 | |
1052 | idev = info->uio_dev; |
1053 | minor = idev->minor; |
1054 | |
1055 | mutex_lock(&idev->info_lock); |
1056 | uio_dev_del_attributes(idev); |
1057 | |
1058 | if (info->irq && info->irq != UIO_IRQ_CUSTOM) |
1059 | free_irq(info->irq, idev); |
1060 | |
1061 | idev->info = NULL; |
1062 | mutex_unlock(lock: &idev->info_lock); |
1063 | |
1064 | wake_up_interruptible(&idev->wait); |
1065 | kill_fasync(&idev->async_queue, SIGIO, POLL_HUP); |
1066 | |
1067 | device_unregister(dev: &idev->dev); |
1068 | |
1069 | uio_free_minor(minor); |
1070 | |
1071 | return; |
1072 | } |
1073 | EXPORT_SYMBOL_GPL(uio_unregister_device); |
1074 | |
1075 | static int __init uio_init(void) |
1076 | { |
1077 | return init_uio_class(); |
1078 | } |
1079 | |
1080 | static void __exit uio_exit(void) |
1081 | { |
1082 | release_uio_class(); |
1083 | idr_destroy(&uio_idr); |
1084 | } |
1085 | |
1086 | module_init(uio_init) |
1087 | module_exit(uio_exit) |
1088 | MODULE_LICENSE("GPL v2" ); |
1089 | |