Create a gist now

Instantly share code, notes, and snippets.

Toggle GPIO with IOCTL and Micropython
obj-m += pyb_gpio.o
ksrc = "$(LINUX_DIR)"
sysr = "$(PWD)/../deploy"
mdir = "extra"
all:
make -C $(ksrc) M=$(PWD) modules
modules_install:
make -C $(ksrc) M=$(PWD) INSTALL_MOD_PATH=$(sysr) INSTALL_MOD_DIR=$(mdir) modules_install
clean:
make -C $(ksrc) M=$(PWD) clean
##
# The MIT License (MIT)
#
# Copyright (c) 2014 Stefan Wendler
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
##
"""
Simple wrapper to libc open/read/write/seek/ioctl functions using FFI on
micropython.
"""
__author__ = 'Stefan Wendler, sw@kaltpost.de'
import ffi
import _libc
libc = _libc.get()
open = libc.func("i", "open", "si")
close = libc.func("i", "close", "i")
read = libc.func("i", "read", "isi")
write = libc.func("i", "write", "isi")
lseek = libc.func("i", "lseek", "iii")
ioctl = libc.func("i", "ioctl", "iis")
'''
Open Flags
'''
O_ACCMODE = 3
O_RDONLY = 0
O_WRONLY = 1
O_RDWR = 2
O_CREAT = 100
O_EXCL = 200
O_NOCTTY = 400
O_TRUNC = 1000
O_APPEND = 2000
O_NONBLOCK = 4000
O_NDELAY = O_NONBLOCK
O_SYNC = 4010000
O_FSYNC = O_SYNC
O_ASYNC = 20000
'''
Some common error codes
'''
EPERM = 1 # Operation not permitted
ENOENT = 2 # No such file or directory
EIO = 5 # I/O error
EAGAIN = 11 # Try again
ENOMEM = 12 # Out of memory
EACCES = 13 # Permission denied
EEXIST = 17 # File exists
EISDIR = 21 # Is a directory
EMFILE = 24 # Too many open files
ETXTBSY = 26 # Text file busy
EFBIG = 27 # File too large
ENOSPC = 28 # No space left on device
EROFS= 30 # Read-only file system
'''
Seek values
'''
SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2
def bytebuffer(size):
'''
Create a bytebuffer of given size (e.g. for use with read)
'''
return ('\0' * size)
_IOC_NRBITS = 8
_IOC_TYPEBITS = 8
_IOC_SIZEBITS = 14
_IOC_DIRBITS = 2
_IOC_NRMASK = ((1 << _IOC_NRBITS) - 1)
_IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1)
_IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1)
_IOC_DIRMASK = ((1 << _IOC_DIRBITS) - 1)
_IOC_NRSHIFT = 0
_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
_IOC_DIRSHIFT = (_IOC_SIZESHIFT + _IOC_SIZEBITS)
_IOC_NONE = 0
_IOC_READ = 1
_IOC_WRITE = 2
def _IOC(dir, type, nr, size):
return (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))
def _IO(type, nr):
return _IOC(_IOC_NONE, type, nr, 0)
def _IOR(type, nr, size):
return _IOC(_IOC_READ, type, nr, size)
def _IOW(type, nr, size):
return _IOC(_IOC_WRITE, type, nr, size)
def _IOWR(type, nr, size):
return _IOC(_IOC_READ | _IOC_WRITE, type, nr, size)
/*
* Linux Kernel module for simple GPIO access through IOCTL.
*
* Author:
* Stefan Wendler (devnull@kaltpost.de)
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#define MAJOR_NUM 100
#define IOCTL_GPIO_OUTPUT _IOR(MAJOR_NUM, 0, int)
#define IOCTL_GPIO_SET _IOR(MAJOR_NUM, 1, int)
#define IOCTL_GPIO_CLEAR _IOR(MAJOR_NUM, 2, int)
#define DEVICE_FILE_NAME "/dev/pyb_gpio"
#define SUCCESS 0
#define DEVICE_NAME "char_dev"
#define BUF_LEN 80
static int is_open = 0;
/*
* This is called whenever a process attempts to open the device file
*/
static int device_open(struct inode *inode, struct file *file)
{
if(is_open)
return -EBUSY;
is_open++;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int device_release(struct inode *inode, struct file *file)
{
is_open--;
module_put(THIS_MODULE);
return SUCCESS;
}
long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
switch (ioctl_num) {
case IOCTL_GPIO_OUTPUT:
gpio_request_one(ioctl_param, GPIOF_DIR_OUT, "pyb_gpio");
break;
case IOCTL_GPIO_SET:
gpio_set_value(ioctl_param, 1);
break;
case IOCTL_GPIO_CLEAR:
gpio_set_value(ioctl_param, 0);
break;
}
return SUCCESS;
}
struct file_operations Fops = {
.unlocked_ioctl = device_ioctl,
.open = device_open,
.release = device_release, /* a.k.a. close */
};
static int __init mod_init(void)
{
int ret;
ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
if (ret < 0)
{
printk(KERN_ALERT "%s failed with %d\n",
"Unable registering character device ", ret);
return ret;
}
printk(KERN_INFO "major device number is %d.\n", MAJOR_NUM);
printk(KERN_INFO "create device node with: mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
return 0;
}
static void __exit mod_exit(void)
{
unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stefan Wendler");
MODULE_DESCRIPTION("GPIO access through IOCTL");
module_init(mod_init);
module_exit(mod_exit);
##
# The MIT License (MIT)
#
# Copyright (c) 2014 Stefan Wendler
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
##
"""
Toggle GPIO with IOCTL and micropython
"""
__author__ = 'Stefan Wendler, sw@kaltpost.de'
import sys
import nio
import time
MAJOR_NUM = 100
DEVICE_FILE = '/dev/pyb_gpio'
GPIO = 22
'''
Calculate IOCTL IDs
'''
IOCTL_GPIO_OUTPUT = nio._IOR(MAJOR_NUM, 0, 4)
IOCTL_GPIO_SET = nio._IOR(MAJOR_NUM, 1, 4)
IOCTL_GPIO_CLEAT = nio._IOR(MAJOR_NUM, 2, 4)
f = nio.open(DEVICE_FILE, nio.O_RDWR)
if f < 0:
print("Failed to open device file: %s" % DEVICE_FILE)
sys.exit(1)
if nio.ioctl(f, IOCTL_GPIO_OUTPUT, GPIO) != 0:
print("IOCTL_GPIO_OUTPUT failed")
sys.exit(1)
try:
while True:
nio.ioctl(f, IOCTL_GPIO_SET, GPIO)
time.sleep(0.25)
nio.ioctl(f, IOCTL_GPIO_SET, GPIO)
time.sleep(0.25)
except KeyboardInterrupt:
pass
nio.close(f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment