0039-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. From e52d7ce66319f6687da3531b00cfec3001aec7a8 Mon Sep 17 00:00:00 2001
  2. From: Luke Wren <luke@raspberrypi.org>
  3. Date: Fri, 21 Aug 2015 23:14:48 +0100
  4. Subject: [PATCH] Add /dev/gpiomem device for rootless user GPIO access
  5. Signed-off-by: Luke Wren <luke@raspberrypi.org>
  6. bcm2835-gpiomem: Fix for ARCH_BCM2835 builds
  7. Build on ARCH_BCM2835, and fail to probe if no IO resource.
  8. See: https://github.com/raspberrypi/linux/issues/1154
  9. ---
  10. drivers/char/broadcom/Kconfig | 9 ++
  11. drivers/char/broadcom/Makefile | 3 +
  12. drivers/char/broadcom/bcm2835-gpiomem.c | 260 ++++++++++++++++++++++++++++++++
  13. 3 files changed, 272 insertions(+)
  14. create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c
  15. --- a/drivers/char/broadcom/Kconfig
  16. +++ b/drivers/char/broadcom/Kconfig
  17. @@ -32,3 +32,12 @@ config BCM_VC_SM
  18. help
  19. Support for the VC shared memory on the Broadcom reference
  20. design. Uses the VCHIQ stack.
  21. +
  22. +config BCM2835_DEVGPIOMEM
  23. + tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835"
  24. + default m
  25. + help
  26. + Provides users with root-free access to the GPIO registers
  27. + on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
  28. + register page to the user's pointer.
  29. +
  30. --- a/drivers/char/broadcom/Makefile
  31. +++ b/drivers/char/broadcom/Makefile
  32. @@ -1,3 +1,6 @@
  33. obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
  34. obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
  35. obj-$(CONFIG_BCM_VC_SM) += vc_sm/
  36. +
  37. +obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
  38. +
  39. --- /dev/null
  40. +++ b/drivers/char/broadcom/bcm2835-gpiomem.c
  41. @@ -0,0 +1,260 @@
  42. +/**
  43. + * GPIO memory device driver
  44. + *
  45. + * Creates a chardev /dev/gpiomem which will provide user access to
  46. + * the BCM2835's GPIO registers when it is mmap()'d.
  47. + * No longer need root for user GPIO access, but without relaxing permissions
  48. + * on /dev/mem.
  49. + *
  50. + * Written by Luke Wren <luke@raspberrypi.org>
  51. + * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
  52. + *
  53. + * Redistribution and use in source and binary forms, with or without
  54. + * modification, are permitted provided that the following conditions
  55. + * are met:
  56. + * 1. Redistributions of source code must retain the above copyright
  57. + * notice, this list of conditions, and the following disclaimer,
  58. + * without modification.
  59. + * 2. Redistributions in binary form must reproduce the above copyright
  60. + * notice, this list of conditions and the following disclaimer in the
  61. + * documentation and/or other materials provided with the distribution.
  62. + * 3. The names of the above-listed copyright holders may not be used
  63. + * to endorse or promote products derived from this software without
  64. + * specific prior written permission.
  65. + *
  66. + * ALTERNATIVELY, this software may be distributed under the terms of the
  67. + * GNU General Public License ("GPL") version 2, as published by the Free
  68. + * Software Foundation.
  69. + *
  70. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  71. + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  72. + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  73. + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  74. + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  75. + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  76. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  77. + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  78. + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  79. + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  80. + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  81. + */
  82. +
  83. +#include <linux/kernel.h>
  84. +#include <linux/module.h>
  85. +#include <linux/of.h>
  86. +#include <linux/platform_device.h>
  87. +#include <linux/mm.h>
  88. +#include <linux/slab.h>
  89. +#include <linux/cdev.h>
  90. +#include <linux/pagemap.h>
  91. +#include <linux/io.h>
  92. +
  93. +#define DEVICE_NAME "bcm2835-gpiomem"
  94. +#define DRIVER_NAME "gpiomem-bcm2835"
  95. +#define DEVICE_MINOR 0
  96. +
  97. +struct bcm2835_gpiomem_instance {
  98. + unsigned long gpio_regs_phys;
  99. + struct device *dev;
  100. +};
  101. +
  102. +static struct cdev bcm2835_gpiomem_cdev;
  103. +static dev_t bcm2835_gpiomem_devid;
  104. +static struct class *bcm2835_gpiomem_class;
  105. +static struct device *bcm2835_gpiomem_dev;
  106. +static struct bcm2835_gpiomem_instance *inst;
  107. +
  108. +
  109. +/****************************************************************************
  110. +*
  111. +* GPIO mem chardev file ops
  112. +*
  113. +***************************************************************************/
  114. +
  115. +static int bcm2835_gpiomem_open(struct inode *inode, struct file *file)
  116. +{
  117. + int dev = iminor(inode);
  118. + int ret = 0;
  119. +
  120. + dev_info(inst->dev, "gpiomem device opened.");
  121. +
  122. + if (dev != DEVICE_MINOR) {
  123. + dev_err(inst->dev, "Unknown minor device: %d", dev);
  124. + ret = -ENXIO;
  125. + }
  126. + return ret;
  127. +}
  128. +
  129. +static int bcm2835_gpiomem_release(struct inode *inode, struct file *file)
  130. +{
  131. + int dev = iminor(inode);
  132. + int ret = 0;
  133. +
  134. + if (dev != DEVICE_MINOR) {
  135. + dev_err(inst->dev, "Unknown minor device %d", dev);
  136. + ret = -ENXIO;
  137. + }
  138. + return ret;
  139. +}
  140. +
  141. +static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = {
  142. +#ifdef CONFIG_HAVE_IOREMAP_PROT
  143. + .access = generic_access_phys
  144. +#endif
  145. +};
  146. +
  147. +static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
  148. +{
  149. + /* Ignore what the user says - they're getting the GPIO regs
  150. + whether they like it or not! */
  151. + unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT;
  152. +
  153. + vma->vm_page_prot = phys_mem_access_prot(file, gpio_page,
  154. + PAGE_SIZE,
  155. + vma->vm_page_prot);
  156. + vma->vm_ops = &bcm2835_gpiomem_vm_ops;
  157. + if (remap_pfn_range(vma, vma->vm_start,
  158. + gpio_page,
  159. + PAGE_SIZE,
  160. + vma->vm_page_prot)) {
  161. + return -EAGAIN;
  162. + }
  163. + return 0;
  164. +}
  165. +
  166. +static const struct file_operations
  167. +bcm2835_gpiomem_fops = {
  168. + .owner = THIS_MODULE,
  169. + .open = bcm2835_gpiomem_open,
  170. + .release = bcm2835_gpiomem_release,
  171. + .mmap = bcm2835_gpiomem_mmap,
  172. +};
  173. +
  174. +
  175. + /****************************************************************************
  176. +*
  177. +* Probe and remove functions
  178. +*
  179. +***************************************************************************/
  180. +
  181. +
  182. +static int bcm2835_gpiomem_probe(struct platform_device *pdev)
  183. +{
  184. + int err;
  185. + void *ptr_err;
  186. + struct device *dev = &pdev->dev;
  187. + struct resource *ioresource;
  188. +
  189. + /* Allocate buffers and instance data */
  190. +
  191. + inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL);
  192. +
  193. + if (!inst) {
  194. + err = -ENOMEM;
  195. + goto failed_inst_alloc;
  196. + }
  197. +
  198. + inst->dev = dev;
  199. +
  200. + ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  201. + if (ioresource) {
  202. + inst->gpio_regs_phys = ioresource->start;
  203. + } else {
  204. + dev_err(inst->dev, "failed to get IO resource");
  205. + err = -ENOENT;
  206. + goto failed_get_resource;
  207. + }
  208. +
  209. + /* Create character device entries */
  210. +
  211. + err = alloc_chrdev_region(&bcm2835_gpiomem_devid,
  212. + DEVICE_MINOR, 1, DEVICE_NAME);
  213. + if (err != 0) {
  214. + dev_err(inst->dev, "unable to allocate device number");
  215. + goto failed_alloc_chrdev;
  216. + }
  217. + cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops);
  218. + bcm2835_gpiomem_cdev.owner = THIS_MODULE;
  219. + err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1);
  220. + if (err != 0) {
  221. + dev_err(inst->dev, "unable to register device");
  222. + goto failed_cdev_add;
  223. + }
  224. +
  225. + /* Create sysfs entries */
  226. +
  227. + bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME);
  228. + ptr_err = bcm2835_gpiomem_class;
  229. + if (IS_ERR(ptr_err))
  230. + goto failed_class_create;
  231. +
  232. + bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL,
  233. + bcm2835_gpiomem_devid, NULL,
  234. + "gpiomem");
  235. + ptr_err = bcm2835_gpiomem_dev;
  236. + if (IS_ERR(ptr_err))
  237. + goto failed_device_create;
  238. +
  239. + dev_info(inst->dev, "Initialised: Registers at 0x%08lx",
  240. + inst->gpio_regs_phys);
  241. +
  242. + return 0;
  243. +
  244. +failed_device_create:
  245. + class_destroy(bcm2835_gpiomem_class);
  246. +failed_class_create:
  247. + cdev_del(&bcm2835_gpiomem_cdev);
  248. + err = PTR_ERR(ptr_err);
  249. +failed_cdev_add:
  250. + unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
  251. +failed_alloc_chrdev:
  252. +failed_get_resource:
  253. + kfree(inst);
  254. +failed_inst_alloc:
  255. + dev_err(inst->dev, "could not load bcm2835_gpiomem");
  256. + return err;
  257. +}
  258. +
  259. +static int bcm2835_gpiomem_remove(struct platform_device *pdev)
  260. +{
  261. + struct device *dev = inst->dev;
  262. +
  263. + kfree(inst);
  264. + device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid);
  265. + class_destroy(bcm2835_gpiomem_class);
  266. + cdev_del(&bcm2835_gpiomem_cdev);
  267. + unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
  268. +
  269. + dev_info(dev, "GPIO mem driver removed - OK");
  270. + return 0;
  271. +}
  272. +
  273. + /****************************************************************************
  274. +*
  275. +* Register the driver with device tree
  276. +*
  277. +***************************************************************************/
  278. +
  279. +static const struct of_device_id bcm2835_gpiomem_of_match[] = {
  280. + {.compatible = "brcm,bcm2835-gpiomem",},
  281. + { /* sentinel */ },
  282. +};
  283. +
  284. +MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match);
  285. +
  286. +static struct platform_driver bcm2835_gpiomem_driver = {
  287. + .probe = bcm2835_gpiomem_probe,
  288. + .remove = bcm2835_gpiomem_remove,
  289. + .driver = {
  290. + .name = DRIVER_NAME,
  291. + .owner = THIS_MODULE,
  292. + .of_match_table = bcm2835_gpiomem_of_match,
  293. + },
  294. +};
  295. +
  296. +module_platform_driver(bcm2835_gpiomem_driver);
  297. +
  298. +MODULE_ALIAS("platform:gpiomem-bcm2835");
  299. +MODULE_LICENSE("GPL");
  300. +MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace");
  301. +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");