LCOV - code coverage report
Current view: top level - drivers/char/broadcom - vcio.c (source / functions) Hit Total Coverage
Test: Real Lines: 15 58 25.9 %
Date: 2020-10-17 15:46:16 Functions: 0 6 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  Copyright (C) 2010 Broadcom
       3                 :            :  *  Copyright (C) 2015 Noralf Trønnes
       4                 :            :  *
       5                 :            :  * This program is free software; you can redistribute it and/or modify
       6                 :            :  * it under the terms of the GNU General Public License version 2 as
       7                 :            :  * published by the Free Software Foundation.
       8                 :            :  *
       9                 :            :  */
      10                 :            : 
      11                 :            : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      12                 :            : 
      13                 :            : #include <linux/cdev.h>
      14                 :            : #include <linux/device.h>
      15                 :            : #include <linux/fs.h>
      16                 :            : #include <linux/init.h>
      17                 :            : #include <linux/ioctl.h>
      18                 :            : #include <linux/module.h>
      19                 :            : #include <linux/slab.h>
      20                 :            : #include <linux/uaccess.h>
      21                 :            : #include <soc/bcm2835/raspberrypi-firmware.h>
      22                 :            : 
      23                 :            : #define MBOX_CHAN_PROPERTY 8
      24                 :            : 
      25                 :            : #define VCIO_IOC_MAGIC 100
      26                 :            : #define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
      27                 :            : #ifdef CONFIG_COMPAT
      28                 :            : #define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
      29                 :            : #endif
      30                 :            : 
      31                 :            : static struct {
      32                 :            :         dev_t devt;
      33                 :            :         struct cdev cdev;
      34                 :            :         struct class *class;
      35                 :            :         struct rpi_firmware *fw;
      36                 :            : } vcio;
      37                 :            : 
      38                 :          0 : static int vcio_user_property_list(void *user)
      39                 :            : {
      40                 :            :         u32 *buf, size;
      41                 :            :         int ret;
      42                 :            : 
      43                 :            :         /* The first 32-bit is the size of the buffer */
      44                 :          0 :         if (copy_from_user(&size, user, sizeof(size)))
      45                 :            :                 return -EFAULT;
      46                 :            : 
      47                 :          0 :         buf = kmalloc(size, GFP_KERNEL);
      48                 :          0 :         if (!buf)
      49                 :            :                 return -ENOMEM;
      50                 :            : 
      51                 :          0 :         if (copy_from_user(buf, user, size)) {
      52                 :          0 :                 kfree(buf);
      53                 :          0 :                 return -EFAULT;
      54                 :            :         }
      55                 :            : 
      56                 :            :         /* Strip off protocol encapsulation */
      57                 :          0 :         ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
      58                 :          0 :         if (ret) {
      59                 :          0 :                 kfree(buf);
      60                 :          0 :                 return ret;
      61                 :            :         }
      62                 :            : 
      63                 :          0 :         buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
      64                 :          0 :         if (copy_to_user(user, buf, size))
      65                 :            :                 ret = -EFAULT;
      66                 :            : 
      67                 :          0 :         kfree(buf);
      68                 :            : 
      69                 :          0 :         return ret;
      70                 :            : }
      71                 :            : 
      72                 :          0 : static int vcio_device_open(struct inode *inode, struct file *file)
      73                 :            : {
      74                 :          0 :         try_module_get(THIS_MODULE);
      75                 :            : 
      76                 :          0 :         return 0;
      77                 :            : }
      78                 :            : 
      79                 :          0 : static int vcio_device_release(struct inode *inode, struct file *file)
      80                 :            : {
      81                 :          0 :         module_put(THIS_MODULE);
      82                 :            : 
      83                 :          0 :         return 0;
      84                 :            : }
      85                 :            : 
      86                 :          0 : static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
      87                 :            :                               unsigned long ioctl_param)
      88                 :            : {
      89                 :          0 :         switch (ioctl_num) {
      90                 :            :         case IOCTL_MBOX_PROPERTY:
      91                 :          0 :                 return vcio_user_property_list((void *)ioctl_param);
      92                 :            :         default:
      93                 :          0 :                 pr_err("unknown ioctl: %x\n", ioctl_num);
      94                 :          0 :                 return -EINVAL;
      95                 :            :         }
      96                 :            : }
      97                 :            : 
      98                 :            : #ifdef CONFIG_COMPAT
      99                 :            : static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
     100                 :            :                                      unsigned long ioctl_param)
     101                 :            : {
     102                 :            :         switch (ioctl_num) {
     103                 :            :         case IOCTL_MBOX_PROPERTY32:
     104                 :            :                 return vcio_user_property_list(compat_ptr(ioctl_param));
     105                 :            :         default:
     106                 :            :                 pr_err("unknown ioctl: %x\n", ioctl_num);
     107                 :            :                 return -EINVAL;
     108                 :            :         }
     109                 :            : }
     110                 :            : #endif
     111                 :            : 
     112                 :            : const struct file_operations vcio_fops = {
     113                 :            :         .unlocked_ioctl = vcio_device_ioctl,
     114                 :            : #ifdef CONFIG_COMPAT
     115                 :            :         .compat_ioctl = vcio_device_compat_ioctl,
     116                 :            : #endif
     117                 :            :         .open = vcio_device_open,
     118                 :            :         .release = vcio_device_release,
     119                 :            : };
     120                 :            : 
     121                 :          3 : static int __init vcio_init(void)
     122                 :            : {
     123                 :            :         struct device_node *np;
     124                 :            :         static struct device *dev;
     125                 :            :         int ret;
     126                 :            : 
     127                 :          3 :         np = of_find_compatible_node(NULL, NULL,
     128                 :            :                                      "raspberrypi,bcm2835-firmware");
     129                 :          3 :         if (!of_device_is_available(np))
     130                 :            :                 return -ENODEV;
     131                 :            : 
     132                 :          3 :         vcio.fw = rpi_firmware_get(np);
     133                 :          3 :         if (!vcio.fw)
     134                 :            :                 return -ENODEV;
     135                 :            : 
     136                 :          3 :         ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
     137                 :          3 :         if (ret) {
     138                 :          0 :                 pr_err("failed to allocate device number\n");
     139                 :          0 :                 return ret;
     140                 :            :         }
     141                 :            : 
     142                 :          3 :         cdev_init(&vcio.cdev, &vcio_fops);
     143                 :          3 :         vcio.cdev.owner = THIS_MODULE;
     144                 :          3 :         ret = cdev_add(&vcio.cdev, vcio.devt, 1);
     145                 :          3 :         if (ret) {
     146                 :          0 :                 pr_err("failed to register device\n");
     147                 :          0 :                 goto err_unregister_chardev;
     148                 :            :         }
     149                 :            : 
     150                 :            :         /*
     151                 :            :          * Create sysfs entries
     152                 :            :          * 'bcm2708_vcio' is used for backwards compatibility so we don't break
     153                 :            :          * userspace. Raspian has a udev rule that changes the permissions.
     154                 :            :          */
     155                 :          3 :         vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
     156                 :          3 :         if (IS_ERR(vcio.class)) {
     157                 :            :                 ret = PTR_ERR(vcio.class);
     158                 :          0 :                 pr_err("failed to create class\n");
     159                 :          0 :                 goto err_cdev_del;
     160                 :            :         }
     161                 :            : 
     162                 :          3 :         dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
     163                 :          3 :         if (IS_ERR(dev)) {
     164                 :            :                 ret = PTR_ERR(dev);
     165                 :          0 :                 pr_err("failed to create device\n");
     166                 :            :                 goto err_class_destroy;
     167                 :            :         }
     168                 :            : 
     169                 :            :         return 0;
     170                 :            : 
     171                 :            : err_class_destroy:
     172                 :          0 :         class_destroy(vcio.class);
     173                 :            : err_cdev_del:
     174                 :          0 :         cdev_del(&vcio.cdev);
     175                 :            : err_unregister_chardev:
     176                 :          0 :         unregister_chrdev_region(vcio.devt, 1);
     177                 :            : 
     178                 :          0 :         return ret;
     179                 :            : }
     180                 :            : module_init(vcio_init);
     181                 :            : 
     182                 :          0 : static void __exit vcio_exit(void)
     183                 :            : {
     184                 :          0 :         device_destroy(vcio.class, vcio.devt);
     185                 :          0 :         class_destroy(vcio.class);
     186                 :          0 :         cdev_del(&vcio.cdev);
     187                 :          0 :         unregister_chrdev_region(vcio.devt, 1);
     188                 :          0 : }
     189                 :            : module_exit(vcio_exit);
     190                 :            : 
     191                 :            : MODULE_AUTHOR("Gray Girling");
     192                 :            : MODULE_AUTHOR("Noralf Trønnes");
     193                 :            : MODULE_DESCRIPTION("Mailbox userspace access");
     194                 :            : MODULE_LICENSE("GPL");
    

Generated by: LCOV version 1.14