[新增] 华清 源码
This commit is contained in:
22
advio/ex1/Makefile
Executable file
22
advio/ex1/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
51
advio/ex1/test.c
Executable file
51
advio/ex1/test.c
Executable file
@ -0,0 +1,51 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
unsigned int baud;
|
||||
struct option opt = {8,1,1};
|
||||
|
||||
fd = open("/dev/vser0", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
baud = 9600;
|
||||
ret = ioctl(fd, VS_SET_BAUD, baud);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
ret = ioctl(fd, VS_GET_BAUD, baud);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
ret = ioctl(fd, VS_SET_FFMT, &opt);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
ret = ioctl(fd, VS_GET_FFMT, &opt);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
printf("baud rate: %d\n", baud);
|
||||
printf("frame format: %d%c%d\n", opt.datab, opt.parity == 0 ? 'N' : \
|
||||
opt.parity == 1 ? 'O' : 'E', \
|
||||
opt.stopb);
|
||||
|
||||
close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
fail:
|
||||
perror("ioctl test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
140
advio/ex1/vser.c
Executable file
140
advio/ex1/vser.c
Executable file
@ -0,0 +1,140 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex1/vser.h
Executable file
17
advio/ex1/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex10/Makefile
Executable file
22
advio/ex10/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vfb.o
|
||||
|
||||
endif
|
||||
|
||||
43
advio/ex10/test.c
Executable file
43
advio/ex10/test.c
Executable file
@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int fd;
|
||||
char *start;
|
||||
int i;
|
||||
char buf[32];
|
||||
|
||||
fd = open("/dev/vfb0", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
start = mmap(NULL, 32, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (start == MAP_FAILED)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < 26; i++)
|
||||
*(start + i) = 'a' + i;
|
||||
*(start + i) = '\0';
|
||||
|
||||
if(lseek(fd, 3, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
|
||||
if (read(fd, buf, 10) == -1)
|
||||
goto fail;
|
||||
|
||||
buf[10] = '\0';
|
||||
puts(buf);
|
||||
|
||||
munmap(start, 32);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
perror("mmap test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
139
advio/ex10/vfb.c
Executable file
139
advio/ex10/vfb.c
Executable file
@ -0,0 +1,139 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define VFB_MAJOR 256
|
||||
#define VFB_MINOR 1
|
||||
#define VFB_DEV_CNT 1
|
||||
#define VFB_DEV_NAME "vfbdev"
|
||||
|
||||
struct vfb_dev {
|
||||
unsigned char *buf;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static struct vfb_dev vfbdev;
|
||||
|
||||
static int vfb_open(struct inode * inode, struct file * filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfb_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfb_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(vfbdev.buf) >> PAGE_SHIFT, \
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t vfb_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
size_t len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
|
||||
|
||||
if (*pos + len > PAGE_SIZE)
|
||||
len = PAGE_SIZE - *pos;
|
||||
|
||||
ret = copy_to_user(buf, vfbdev.buf + *pos, len);
|
||||
*pos += len - ret;
|
||||
|
||||
return len - ret;
|
||||
}
|
||||
|
||||
static loff_t vfb_llseek(struct file * filp, loff_t off, int whence)
|
||||
{
|
||||
loff_t newpos;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
newpos = off;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
newpos = filp->f_pos + off;
|
||||
break;
|
||||
case SEEK_END:
|
||||
newpos = PAGE_SIZE + off;
|
||||
break;
|
||||
default: /* can't happen */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (newpos < 0 || newpos > PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
filp->f_pos = newpos;
|
||||
|
||||
return newpos;
|
||||
}
|
||||
|
||||
static struct file_operations vfb_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vfb_open,
|
||||
.release = vfb_release,
|
||||
.mmap = vfb_mmap,
|
||||
.read = vfb_read,
|
||||
.llseek = vfb_llseek,
|
||||
};
|
||||
|
||||
static int __init vfb_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
unsigned long addr;
|
||||
|
||||
dev = MKDEV(VFB_MAJOR, VFB_MINOR);
|
||||
ret = register_chrdev_region(dev, VFB_DEV_CNT, VFB_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vfbdev.cdev, &vfb_fops);
|
||||
vfbdev.cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&vfbdev.cdev, dev, VFB_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
addr = __get_free_page(GFP_KERNEL);
|
||||
if (!addr)
|
||||
goto get_err;
|
||||
|
||||
vfbdev.buf = (unsigned char *)addr;
|
||||
memset(vfbdev.buf, 0, PAGE_SIZE);
|
||||
|
||||
return 0;
|
||||
|
||||
get_err:
|
||||
cdev_del(&vfbdev.cdev);
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VFB_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vfb_exit(void)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VFB_MAJOR, VFB_MINOR);
|
||||
|
||||
free_page((unsigned long)vfbdev.buf);
|
||||
cdev_del(&vfbdev.cdev);
|
||||
unregister_chrdev_region(dev, VFB_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vfb_init);
|
||||
module_exit(vfb_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("This is an example for mmap");
|
||||
22
advio/ex2/Makefile
Executable file
22
advio/ex2/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
181
advio/ex2/vser.c
Executable file
181
advio/ex2/vser.c
Executable file
@ -0,0 +1,181 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
struct proc_dir_entry *pdir;
|
||||
struct proc_dir_entry *pdat;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
};
|
||||
|
||||
static int dat_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct vser_dev *dev = m->private;
|
||||
|
||||
seq_printf(m, "baudrate: %d\n", dev->baud);
|
||||
return seq_printf(m, "frame format: %d%c%d\n", dev->opt.datab, \
|
||||
dev->opt.parity == 0 ? 'N' : dev->opt.parity == 1 ? 'O': 'E', \
|
||||
dev->opt.stopb);
|
||||
}
|
||||
|
||||
static int proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dat_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static struct file_operations proc_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = proc_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
vsdev.pdir = proc_mkdir("vser", NULL);
|
||||
if (!vsdev.pdir)
|
||||
goto dir_err;
|
||||
vsdev.pdat = proc_create_data("info", 0, vsdev.pdir, &proc_ops, &vsdev);
|
||||
if (!vsdev.pdat)
|
||||
goto dat_err;
|
||||
|
||||
return 0;
|
||||
|
||||
dat_err:
|
||||
remove_proc_entry("vser", NULL);
|
||||
dir_err:
|
||||
cdev_del(&vsdev.cdev);
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
remove_proc_entry("info", vsdev.pdir);
|
||||
remove_proc_entry("vser", NULL);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex2/vser.h
Executable file
17
advio/ex2/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex3/Makefile
Executable file
22
advio/ex3/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
44
advio/ex3/test.c
Executable file
44
advio/ex3/test.c
Executable file
@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
unsigned int baud;
|
||||
struct option opt = {8,1,1};
|
||||
char rbuf[32] = {0};
|
||||
char wbuf[32] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
|
||||
fd = open("/dev/vser0", O_RDWR | O_NONBLOCK);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
ret = read(fd, rbuf, sizeof(rbuf));
|
||||
if (ret < 0)
|
||||
perror("read");
|
||||
|
||||
ret = write(fd, wbuf, sizeof(wbuf));
|
||||
if (ret < 0)
|
||||
perror("first write");
|
||||
|
||||
ret = write(fd, wbuf, sizeof(wbuf));
|
||||
if (ret < 0)
|
||||
perror("second write");
|
||||
|
||||
|
||||
close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
fail:
|
||||
perror("ioctl test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
148
advio/ex3/vser.c
Executable file
148
advio/ex3/vser.c
Executable file
@ -0,0 +1,148 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_empty(&vsfifo))
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_full(&vsfifo))
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex3/vser.h
Executable file
17
advio/ex3/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex4/Makefile
Executable file
22
advio/ex4/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
171
advio/ex4/vser.c
Executable file
171
advio/ex4/vser.c
Executable file
@ -0,0 +1,171 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
wait_queue_head_t rwqh;
|
||||
wait_queue_head_t wwqh;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_empty(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible(vsdev.rwqh, !kfifo_is_empty(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.wwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_full(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible(vsdev.wwqh, !kfifo_is_full(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.rwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
init_waitqueue_head(&vsdev.rwqh);
|
||||
init_waitqueue_head(&vsdev.wwqh);
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex4/vser.h
Executable file
17
advio/ex4/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex5/Makefile
Executable file
22
advio/ex5/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
34
advio/ex5/test.c
Executable file
34
advio/ex5/test.c
Executable file
@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
unsigned int baud;
|
||||
struct option opt = {8,1,1};
|
||||
char rbuf[32] = {0};
|
||||
|
||||
fd = open("/dev/vser0", O_RDWR | O_NONBLOCK);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
ret = read(fd, rbuf, sizeof(rbuf));
|
||||
if (ret < 0)
|
||||
perror("read");
|
||||
|
||||
close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
fail:
|
||||
perror("ioctl test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
171
advio/ex5/vser.c
Executable file
171
advio/ex5/vser.c
Executable file
@ -0,0 +1,171 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
wait_queue_head_t rwqh;
|
||||
wait_queue_head_t wwqh;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_empty(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.rwqh, !kfifo_is_empty(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.wwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_full(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.wwqh, !kfifo_is_full(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.rwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
init_waitqueue_head(&vsdev.rwqh);
|
||||
init_waitqueue_head(&vsdev.wwqh);
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex5/vser.h
Executable file
17
advio/ex5/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex6/Makefile
Executable file
22
advio/ex6/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
63
advio/ex6/test.c
Executable file
63
advio/ex6/test.c
Executable file
@ -0,0 +1,63 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
struct pollfd fds[2];
|
||||
char rbuf[32];
|
||||
char wbuf[32];
|
||||
struct input_event key;
|
||||
|
||||
fds[0].fd = open("/dev/vser0", O_RDWR | O_NONBLOCK);
|
||||
if (fds[0].fd == -1)
|
||||
goto fail;
|
||||
fds[0].events = POLLIN;
|
||||
fds[0].revents = 0;
|
||||
|
||||
fds[1].fd = open("/dev/input/event1", O_RDWR | O_NONBLOCK);
|
||||
if (fds[1].fd == -1)
|
||||
goto fail;
|
||||
fds[1].events = POLLIN;
|
||||
fds[1].revents = 0;
|
||||
|
||||
while (1) {
|
||||
ret = poll(fds, 2, -1);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
if (fds[0].revents & POLLIN) {
|
||||
ret = read(fds[0].fd, rbuf, sizeof(rbuf));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
puts(rbuf);
|
||||
}
|
||||
|
||||
if (fds[1].revents & POLLIN) {
|
||||
ret = read(fds[1].fd, &key, sizeof(key));
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
if (key.type == EV_KEY) {
|
||||
sprintf(wbuf, "%#x\n", key.code);
|
||||
ret = write(fds[0].fd, wbuf, strlen(wbuf) + 1);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
perror("poll test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
188
advio/ex6/vser.c
Executable file
188
advio/ex6/vser.c
Executable file
@ -0,0 +1,188 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
wait_queue_head_t rwqh;
|
||||
wait_queue_head_t wwqh;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_empty(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.rwqh, !kfifo_is_empty(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.wwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_full(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.wwqh, !kfifo_is_full(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.rwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int vser_poll(struct file *filp, struct poll_table_struct *p)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
poll_wait(filp, &vsdev.rwqh, p);
|
||||
poll_wait(filp, &vsdev.wwqh, p);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
.poll = vser_poll,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
init_waitqueue_head(&vsdev.rwqh);
|
||||
init_waitqueue_head(&vsdev.wwqh);
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex6/vser.h
Executable file
17
advio/ex6/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex7/Makefile
Executable file
22
advio/ex7/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
89
advio/ex7/test.c
Executable file
89
advio/ex7/test.c
Executable file
@ -0,0 +1,89 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <linux/input.h>
|
||||
#include <aio.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
void aiow_completion_handler(sigval_t sigval)
|
||||
{
|
||||
int ret;
|
||||
struct aiocb *req;
|
||||
|
||||
req = (struct aiocb *)sigval.sival_ptr;
|
||||
|
||||
if (aio_error(req) == 0) {
|
||||
ret = aio_return(req);
|
||||
printf("aio write %d bytes\n", ret);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void aior_completion_handler(sigval_t sigval)
|
||||
{
|
||||
int ret;
|
||||
struct aiocb *req;
|
||||
|
||||
req = (struct aiocb *)sigval.sival_ptr;
|
||||
|
||||
if (aio_error(req) == 0) {
|
||||
ret = aio_return(req);
|
||||
if (ret)
|
||||
printf("aio read: %s\n", (char *)req->aio_buf);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
struct aiocb aiow, aior;
|
||||
|
||||
fd = open("/dev/vser0", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
memset(&aiow, 0, sizeof(aiow));
|
||||
memset(&aior, 0, sizeof(aior));
|
||||
|
||||
aiow.aio_fildes = fd;
|
||||
aiow.aio_buf = malloc(32);
|
||||
strcpy((char *)aiow.aio_buf, "aio test");
|
||||
aiow.aio_nbytes = strlen((char *)aiow.aio_buf) + 1;
|
||||
aiow.aio_offset = 0;
|
||||
aiow.aio_sigevent.sigev_notify = SIGEV_THREAD;
|
||||
aiow.aio_sigevent.sigev_notify_function = aiow_completion_handler;
|
||||
aiow.aio_sigevent.sigev_notify_attributes = NULL;
|
||||
aiow.aio_sigevent.sigev_value.sival_ptr = &aiow;
|
||||
|
||||
aior.aio_fildes = fd;
|
||||
aior.aio_buf = malloc(32);
|
||||
aior.aio_nbytes = 32;
|
||||
aior.aio_offset = 0;
|
||||
aior.aio_sigevent.sigev_notify = SIGEV_THREAD;
|
||||
aior.aio_sigevent.sigev_notify_function = aior_completion_handler;
|
||||
aior.aio_sigevent.sigev_notify_attributes = NULL;
|
||||
aior.aio_sigevent.sigev_value.sival_ptr = &aior;
|
||||
|
||||
while (1) {
|
||||
if (aio_write(&aiow) == -1)
|
||||
goto fail;
|
||||
if (aio_read(&aior) == -1)
|
||||
goto fail;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
fail:
|
||||
perror("aio test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
223
advio/ex7/vser.c
Executable file
223
advio/ex7/vser.c
Executable file
@ -0,0 +1,223 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/aio.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
wait_queue_head_t rwqh;
|
||||
wait_queue_head_t wwqh;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_empty(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.rwqh, !kfifo_is_empty(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.wwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_full(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.wwqh, !kfifo_is_full(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
wake_up_interruptible(&vsdev.rwqh);
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int vser_poll(struct file *filp, struct poll_table_struct *p)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
poll_wait(filp, &vsdev.rwqh, p);
|
||||
poll_wait(filp, &vsdev.wwqh, p);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t vser_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
size_t read = 0;
|
||||
unsigned long i;
|
||||
ssize_t ret;
|
||||
|
||||
for (i = 0; i < nr_segs; i++) {
|
||||
ret = vser_read(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, &pos);
|
||||
if (ret < 0)
|
||||
break;
|
||||
read += ret;
|
||||
}
|
||||
|
||||
return read ? read : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t vser_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
size_t written = 0;
|
||||
unsigned long i;
|
||||
ssize_t ret;
|
||||
|
||||
for (i = 0; i < nr_segs; i++) {
|
||||
ret = vser_write(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, &pos);
|
||||
if (ret < 0)
|
||||
break;
|
||||
written += ret;
|
||||
}
|
||||
|
||||
return written ? written : -EFAULT;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
.poll = vser_poll,
|
||||
.aio_read = vser_aio_read,
|
||||
.aio_write = vser_aio_write,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
init_waitqueue_head(&vsdev.rwqh);
|
||||
init_waitqueue_head(&vsdev.wwqh);
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex7/vser.h
Executable file
17
advio/ex7/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex8/Makefile
Executable file
22
advio/ex8/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
67
advio/ex8/test.c
Executable file
67
advio/ex8/test.c
Executable file
@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
int fd;
|
||||
|
||||
void sigio_handler(int signum, siginfo_t *siginfo, void *act)
|
||||
{
|
||||
int ret;
|
||||
char buf[32];
|
||||
|
||||
if (signum == SIGIO) {
|
||||
if (siginfo->si_band & POLLIN) {
|
||||
printf("FIFO is not empty\n");
|
||||
if ((ret = read(fd, buf, sizeof(buf))) != -1) {
|
||||
buf[ret] = '\0';
|
||||
puts(buf);
|
||||
}
|
||||
}
|
||||
if (siginfo->si_band & POLLOUT)
|
||||
printf("FIFO is not full\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int flag;
|
||||
struct sigaction act, oldact;
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
sigaddset(&act.sa_mask, SIGIO);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = sigio_handler;
|
||||
if (sigaction(SIGIO, &act, &oldact) == -1)
|
||||
goto fail;
|
||||
|
||||
fd = open("/dev/vser0", O_RDWR | O_NONBLOCK);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
if (fcntl(fd, F_SETOWN, getpid()) == -1)
|
||||
goto fail;
|
||||
if (fcntl(fd, F_SETSIG, SIGIO) == -1)
|
||||
goto fail;
|
||||
if ((flag = fcntl(fd, F_GETFL)) == -1)
|
||||
goto fail;
|
||||
if (fcntl(fd, F_SETFL, flag | FASYNC) == -1)
|
||||
goto fail;
|
||||
|
||||
while (1)
|
||||
sleep(1);
|
||||
|
||||
fail:
|
||||
perror("fasync test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
237
advio/ex8/vser.c
Executable file
237
advio/ex8/vser.c
Executable file
@ -0,0 +1,237 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/aio.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
struct vser_dev {
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
wait_queue_head_t rwqh;
|
||||
wait_queue_head_t wwqh;
|
||||
struct fasync_struct *fapp;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static int vser_fasync(int fd, struct file *filp, int on);
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
vser_fasync(-1, filp, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_empty(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.rwqh, !kfifo_is_empty(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_full(&vsfifo)) {
|
||||
wake_up_interruptible(&vsdev.wwqh);
|
||||
kill_fasync(&vsdev.fapp, SIGIO, POLL_OUT);
|
||||
}
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
||||
int ret;
|
||||
unsigned int copied = 0;
|
||||
|
||||
if (kfifo_is_full(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(vsdev.wwqh, !kfifo_is_full(&vsfifo)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
ret = kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo)) {
|
||||
wake_up_interruptible(&vsdev.rwqh);
|
||||
kill_fasync(&vsdev.fapp, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
return ret == 0 ? copied : ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int vser_poll(struct file *filp, struct poll_table_struct *p)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
poll_wait(filp, &vsdev.rwqh, p);
|
||||
poll_wait(filp, &vsdev.wwqh, p);
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t vser_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
size_t read = 0;
|
||||
unsigned long i;
|
||||
ssize_t ret;
|
||||
|
||||
for (i = 0; i < nr_segs; i++) {
|
||||
ret = vser_read(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, &pos);
|
||||
if (ret < 0)
|
||||
break;
|
||||
read += ret;
|
||||
}
|
||||
|
||||
return read ? read : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t vser_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
size_t written = 0;
|
||||
unsigned long i;
|
||||
ssize_t ret;
|
||||
|
||||
for (i = 0; i < nr_segs; i++) {
|
||||
ret = vser_write(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, &pos);
|
||||
if (ret < 0)
|
||||
break;
|
||||
written += ret;
|
||||
}
|
||||
|
||||
return written ? written : -EFAULT;
|
||||
}
|
||||
|
||||
static int vser_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
return fasync_helper(fd, filp, on, &vsdev.fapp);
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
.poll = vser_poll,
|
||||
.aio_read = vser_aio_read,
|
||||
.aio_write = vser_aio_write,
|
||||
.fasync = vser_fasync,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
init_waitqueue_head(&vsdev.rwqh);
|
||||
init_waitqueue_head(&vsdev.wwqh);
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
advio/ex8/vser.h
Executable file
17
advio/ex8/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
advio/ex9/Makefile
Executable file
22
advio/ex9/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vfb.o
|
||||
|
||||
endif
|
||||
|
||||
39
advio/ex9/test.c
Executable file
39
advio/ex9/test.c
Executable file
@ -0,0 +1,39 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int fd;
|
||||
char *start;
|
||||
int i;
|
||||
char buf[32];
|
||||
|
||||
fd = open("/dev/vfb0", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
start = mmap(NULL, 32, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (start == MAP_FAILED)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < 26; i++)
|
||||
*(start + i) = 'a' + i;
|
||||
*(start + i) = '\0';
|
||||
|
||||
if (read(fd, buf, 27) == -1)
|
||||
goto fail;
|
||||
|
||||
puts(buf);
|
||||
|
||||
munmap(start, 32);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
perror("mmap test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
108
advio/ex9/vfb.c
Executable file
108
advio/ex9/vfb.c
Executable file
@ -0,0 +1,108 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define VFB_MAJOR 256
|
||||
#define VFB_MINOR 1
|
||||
#define VFB_DEV_CNT 1
|
||||
#define VFB_DEV_NAME "vfbdev"
|
||||
|
||||
struct vfb_dev {
|
||||
unsigned char *buf;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static struct vfb_dev vfbdev;
|
||||
|
||||
static int vfb_open(struct inode * inode, struct file * filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfb_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfb_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(vfbdev.buf) >> PAGE_SHIFT, \
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t vfb_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
size_t len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
|
||||
|
||||
ret = copy_to_user(buf, vfbdev.buf, len);
|
||||
|
||||
return len - ret;
|
||||
}
|
||||
|
||||
static struct file_operations vfb_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vfb_open,
|
||||
.release = vfb_release,
|
||||
.mmap = vfb_mmap,
|
||||
.read = vfb_read,
|
||||
};
|
||||
|
||||
static int __init vfb_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
unsigned long addr;
|
||||
|
||||
dev = MKDEV(VFB_MAJOR, VFB_MINOR);
|
||||
ret = register_chrdev_region(dev, VFB_DEV_CNT, VFB_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vfbdev.cdev, &vfb_fops);
|
||||
vfbdev.cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&vfbdev.cdev, dev, VFB_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
addr = __get_free_page(GFP_KERNEL);
|
||||
if (!addr)
|
||||
goto get_err;
|
||||
|
||||
vfbdev.buf = (unsigned char *)addr;
|
||||
memset(vfbdev.buf, 0, PAGE_SIZE);
|
||||
|
||||
return 0;
|
||||
|
||||
get_err:
|
||||
cdev_del(&vfbdev.cdev);
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VFB_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vfb_exit(void)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VFB_MAJOR, VFB_MINOR);
|
||||
|
||||
free_page((unsigned long)vfbdev.buf);
|
||||
cdev_del(&vfbdev.cdev);
|
||||
unregister_chrdev_region(dev, VFB_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vfb_init);
|
||||
module_exit(vfb_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("This is an example for mmap");
|
||||
22
block/ex1/Makefile
Executable file
22
block/ex1/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vdsk.o
|
||||
|
||||
endif
|
||||
|
||||
161
block/ex1/vdsk.c
Executable file
161
block/ex1/vdsk.c
Executable file
@ -0,0 +1,161 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#define VDSK_MINORS 4
|
||||
#define VDSK_HEADS 4
|
||||
#define VDSK_SECTORS 16
|
||||
#define VDSK_CYLINDERS 256
|
||||
#define VDSK_SECTOR_SIZE 512
|
||||
#define VDSK_SECTOR_TOTAL (VDSK_HEADS * VDSK_SECTORS * VDSK_CYLINDERS)
|
||||
#define VDSK_SIZE (VDSK_SECTOR_TOTAL * VDSK_SECTOR_SIZE)
|
||||
|
||||
static int vdsk_major = 0;
|
||||
static char vdsk_name[] = "vdsk";
|
||||
|
||||
struct vdsk_dev
|
||||
{
|
||||
u8 *data;
|
||||
int size;
|
||||
spinlock_t lock;
|
||||
struct gendisk *gd;
|
||||
struct request_queue *queue;
|
||||
};
|
||||
|
||||
struct vdsk_dev *vdsk = NULL;
|
||||
|
||||
static int vdsk_open(struct block_device *bdev, fmode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vdsk_release(struct gendisk *gd, fmode_t mode)
|
||||
{
|
||||
}
|
||||
|
||||
static int vdsk_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdsk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||
{
|
||||
geo->cylinders = VDSK_CYLINDERS;
|
||||
geo->heads = VDSK_HEADS;
|
||||
geo->sectors = VDSK_SECTORS;
|
||||
geo->start = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vdsk_make_request(struct request_queue *q, struct bio *bio)
|
||||
{
|
||||
struct vdsk_dev *vdsk;
|
||||
struct bio_vec bvec;
|
||||
struct bvec_iter iter;
|
||||
unsigned long offset;
|
||||
unsigned long nbytes;
|
||||
char *buffer;
|
||||
|
||||
vdsk = q->queuedata;
|
||||
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
buffer = __bio_kmap_atomic(bio, iter);
|
||||
offset = iter.bi_sector * VDSK_SECTOR_SIZE;
|
||||
nbytes = bvec.bv_len;
|
||||
|
||||
if ((offset + nbytes) > get_capacity(vdsk->gd) * VDSK_SECTOR_SIZE) {
|
||||
bio_endio(bio, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bio_data_dir(bio) == WRITE)
|
||||
memcpy(vdsk->data + offset, buffer, nbytes);
|
||||
else
|
||||
memcpy(buffer, vdsk->data + offset, nbytes);
|
||||
|
||||
__bio_kunmap_atomic(bio);
|
||||
}
|
||||
|
||||
bio_endio(bio, 0);
|
||||
}
|
||||
|
||||
static struct block_device_operations vdsk_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vdsk_open,
|
||||
.release = vdsk_release,
|
||||
.ioctl = vdsk_ioctl,
|
||||
.getgeo = vdsk_getgeo,
|
||||
};
|
||||
|
||||
static int __init vdsk_init(void)
|
||||
{
|
||||
vdsk_major = register_blkdev(vdsk_major, vdsk_name);
|
||||
if (vdsk_major <= 0)
|
||||
return -EBUSY;
|
||||
|
||||
vdsk = kzalloc(sizeof(struct vdsk_dev), GFP_KERNEL);
|
||||
if (!vdsk)
|
||||
goto unreg_dev;
|
||||
|
||||
vdsk->size = VDSK_SIZE;
|
||||
vdsk->data = vmalloc(vdsk->size);
|
||||
if (!vdsk->data)
|
||||
goto free_dev;
|
||||
|
||||
spin_lock_init(&vdsk->lock);
|
||||
vdsk->queue = blk_alloc_queue(GFP_KERNEL);
|
||||
if (vdsk->queue == NULL)
|
||||
goto free_data;
|
||||
blk_queue_make_request(vdsk->queue, vdsk_make_request);
|
||||
blk_queue_logical_block_size(vdsk->queue, VDSK_SECTOR_SIZE);
|
||||
vdsk->queue->queuedata = vdsk;
|
||||
|
||||
vdsk->gd = alloc_disk(VDSK_MINORS);
|
||||
if (!vdsk->gd)
|
||||
goto free_queue;
|
||||
|
||||
vdsk->gd->major = vdsk_major;
|
||||
vdsk->gd->first_minor = 0;
|
||||
vdsk->gd->fops = &vdsk_fops;
|
||||
vdsk->gd->queue = vdsk->queue;
|
||||
vdsk->gd->private_data = vdsk;
|
||||
snprintf(vdsk->gd->disk_name, 32, "vdsk%c", 'a');
|
||||
set_capacity(vdsk->gd, VDSK_SECTOR_TOTAL);
|
||||
add_disk(vdsk->gd);
|
||||
|
||||
return 0;
|
||||
|
||||
free_queue:
|
||||
blk_cleanup_queue(vdsk->queue);
|
||||
free_data:
|
||||
vfree(vdsk->data);
|
||||
free_dev:
|
||||
kfree(vdsk);
|
||||
unreg_dev:
|
||||
unregister_blkdev(vdsk_major, vdsk_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void __exit vdsk_exit(void)
|
||||
{
|
||||
del_gendisk(vdsk->gd);
|
||||
put_disk(vdsk->gd);
|
||||
blk_cleanup_queue(vdsk->queue);
|
||||
vfree(vdsk->data);
|
||||
kfree(vdsk);
|
||||
unregister_blkdev(vdsk_major, vdsk_name);
|
||||
}
|
||||
|
||||
module_init(vdsk_init);
|
||||
module_exit(vdsk_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("This is an example for Linux block device driver");
|
||||
22
block/ex2/Makefile
Executable file
22
block/ex2/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vdsk.o
|
||||
|
||||
endif
|
||||
|
||||
162
block/ex2/vdsk.c
Executable file
162
block/ex2/vdsk.c
Executable file
@ -0,0 +1,162 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
|
||||
#define VDSK_MINORS 4
|
||||
#define VDSK_HEADS 4
|
||||
#define VDSK_SECTORS 16
|
||||
#define VDSK_CYLINDERS 256
|
||||
#define VDSK_SECTOR_SIZE 512
|
||||
#define VDSK_SECTOR_TOTAL (VDSK_HEADS * VDSK_SECTORS * VDSK_CYLINDERS)
|
||||
#define VDSK_SIZE (VDSK_SECTOR_TOTAL * VDSK_SECTOR_SIZE)
|
||||
|
||||
static int vdsk_major = 0;
|
||||
static char vdsk_name[] = "vdsk";
|
||||
|
||||
struct vdsk_dev
|
||||
{
|
||||
int size;
|
||||
u8 *data;
|
||||
spinlock_t lock;
|
||||
struct gendisk *gd;
|
||||
struct request_queue *queue;
|
||||
};
|
||||
|
||||
static struct vdsk_dev *vdsk = NULL;
|
||||
|
||||
static int vdsk_open(struct block_device *bdev, fmode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vdsk_release(struct gendisk *gd, fmode_t mode)
|
||||
{
|
||||
}
|
||||
|
||||
static int vdsk_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdsk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||
{
|
||||
geo->cylinders = VDSK_CYLINDERS;
|
||||
geo->heads = VDSK_HEADS;
|
||||
geo->sectors = VDSK_SECTORS;
|
||||
geo->start = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vdsk_request(struct request_queue *q)
|
||||
{
|
||||
struct vdsk_dev *vdsk;
|
||||
struct request *req;
|
||||
struct bio *bio;
|
||||
struct bio_vec bvec;
|
||||
struct bvec_iter iter;
|
||||
unsigned long offset;
|
||||
unsigned long nbytes;
|
||||
char *buffer;
|
||||
|
||||
vdsk = q->queuedata;
|
||||
req = blk_fetch_request(q);
|
||||
while (req != NULL) {
|
||||
__rq_for_each_bio(bio, req) {
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
buffer = __bio_kmap_atomic(bio, iter);
|
||||
offset = iter.bi_sector * VDSK_SECTOR_SIZE;
|
||||
nbytes = bvec.bv_len;
|
||||
|
||||
if ((offset + nbytes) > get_capacity(vdsk->gd) * VDSK_SECTOR_SIZE)
|
||||
return;
|
||||
|
||||
if (bio_data_dir(bio) == WRITE)
|
||||
memcpy(vdsk->data + offset, buffer, nbytes);
|
||||
else
|
||||
memcpy(buffer, vdsk->data + offset, nbytes);
|
||||
|
||||
__bio_kunmap_atomic(bio);
|
||||
}
|
||||
}
|
||||
|
||||
if (!__blk_end_request_cur(req, 0))
|
||||
req = blk_fetch_request(q);
|
||||
}
|
||||
}
|
||||
|
||||
static struct block_device_operations vdsk_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vdsk_open,
|
||||
.release = vdsk_release,
|
||||
.ioctl = vdsk_ioctl,
|
||||
.getgeo = vdsk_getgeo,
|
||||
};
|
||||
|
||||
static int __init vdsk_init(void)
|
||||
{
|
||||
vdsk_major = register_blkdev(vdsk_major, vdsk_name);
|
||||
if (vdsk_major <= 0)
|
||||
return -EBUSY;
|
||||
|
||||
vdsk = kzalloc(sizeof(struct vdsk_dev), GFP_KERNEL);
|
||||
if (!vdsk)
|
||||
goto unreg_dev;
|
||||
|
||||
vdsk->size = VDSK_SIZE;
|
||||
vdsk->data = vmalloc(vdsk->size);
|
||||
if (!vdsk->data)
|
||||
goto free_dev;
|
||||
|
||||
spin_lock_init(&vdsk->lock);
|
||||
vdsk->queue = blk_init_queue(vdsk_request, &vdsk->lock);
|
||||
blk_queue_logical_block_size(vdsk->queue, VDSK_SECTOR_SIZE);
|
||||
vdsk->queue->queuedata = vdsk;
|
||||
|
||||
vdsk->gd = alloc_disk(VDSK_MINORS);
|
||||
if (!vdsk->gd)
|
||||
goto free_data;
|
||||
|
||||
vdsk->gd->major = vdsk_major;
|
||||
vdsk->gd->first_minor = 0;
|
||||
vdsk->gd->fops = &vdsk_fops;
|
||||
vdsk->gd->queue = vdsk->queue;
|
||||
vdsk->gd->private_data = vdsk;
|
||||
snprintf(vdsk->gd->disk_name, 32, "vdsk%c", 'a');
|
||||
set_capacity(vdsk->gd, VDSK_SECTOR_TOTAL);
|
||||
add_disk(vdsk->gd);
|
||||
return 0;
|
||||
|
||||
free_data:
|
||||
blk_cleanup_queue(vdsk->queue);
|
||||
vfree(vdsk->data);
|
||||
free_dev:
|
||||
kfree(vdsk);
|
||||
unreg_dev:
|
||||
unregister_blkdev(vdsk_major, vdsk_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void __exit vdsk_exit(void)
|
||||
{
|
||||
del_gendisk(vdsk->gd);
|
||||
put_disk(vdsk->gd);
|
||||
blk_cleanup_queue(vdsk->queue);
|
||||
vfree(vdsk->data);
|
||||
kfree(vdsk);
|
||||
unregister_blkdev(vdsk_major, vdsk_name);
|
||||
}
|
||||
|
||||
module_init(vdsk_init);
|
||||
module_exit(vdsk_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("This is an example for Linux block device driver");
|
||||
22
chrdev/ex1/Makefile
Executable file
22
chrdev/ex1/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
42
chrdev/ex1/vser.c
Executable file
42
chrdev/ex1/vser.c
Executable file
@ -0,0 +1,42 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
return 0;
|
||||
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
22
chrdev/ex2/Makefile
Executable file
22
chrdev/ex2/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
61
chrdev/ex2/vser.c
Executable file
61
chrdev/ex2/vser.c
Executable file
@ -0,0 +1,61 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
static struct cdev vsdev;
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev, &vser_ops);
|
||||
vsdev.owner = THIS_MODULE;
|
||||
|
||||
ret = cdev_add(&vsdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
22
chrdev/ex3/Makefile
Executable file
22
chrdev/ex3/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
95
chrdev/ex3/vser.c
Executable file
95
chrdev/ex3/vser.c
Executable file
@ -0,0 +1,95 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
static struct cdev vsdev;
|
||||
DEFINE_KFIFO(vsfifo, char, 32);
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
unsigned int copied = 0;
|
||||
|
||||
kfifo_to_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
unsigned int copied = 0;
|
||||
|
||||
kfifo_from_user(&vsfifo, buf, count, &copied);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev, &vser_ops);
|
||||
vsdev.owner = THIS_MODULE;
|
||||
|
||||
ret = cdev_add(&vsdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
22
chrdev/ex4/Makefile
Executable file
22
chrdev/ex4/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
107
chrdev/ex4/vser.c
Executable file
107
chrdev/ex4/vser.c
Executable file
@ -0,0 +1,107 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 2
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
static struct cdev vsdev;
|
||||
static DEFINE_KFIFO(vsfifo0, char, 32);
|
||||
static DEFINE_KFIFO(vsfifo1, char, 32);
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
switch (MINOR(inode->i_rdev)) {
|
||||
default:
|
||||
case 0:
|
||||
filp->private_data = &vsfifo0;
|
||||
break;
|
||||
case 1:
|
||||
filp->private_data = &vsfifo1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
unsigned int copied = 0;
|
||||
struct kfifo *vsfifo = filp->private_data;
|
||||
|
||||
kfifo_to_user(vsfifo, buf, count, &copied);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
unsigned int copied = 0;
|
||||
struct kfifo *vsfifo = filp->private_data;
|
||||
|
||||
kfifo_from_user(vsfifo, buf, count, &copied);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev, &vser_ops);
|
||||
vsdev.owner = THIS_MODULE;
|
||||
|
||||
ret = cdev_add(&vsdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
cdev_del(&vsdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
112
chrdev/ex5/vser.c
Executable file
112
chrdev/ex5/vser.c
Executable file
@ -0,0 +1,112 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 2
|
||||
#define VSER_DEV_NAME "vser"
|
||||
|
||||
static DEFINE_KFIFO(vsfifo0, char, 32);
|
||||
static DEFINE_KFIFO(vsfifo1, char, 32);
|
||||
|
||||
struct vser_dev {
|
||||
struct kfifo *fifo;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static struct vser_dev vsdev[2];
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
filp->private_data = container_of(inode->i_cdev, struct vser_dev, cdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
unsigned int copied = 0;
|
||||
struct vser_dev *dev = filp->private_data;
|
||||
|
||||
kfifo_to_user(dev->fifo, buf, count, &copied);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
unsigned int copied = 0;
|
||||
struct vser_dev *dev = filp->private_data;
|
||||
|
||||
kfifo_from_user(dev->fifo, buf, count, &copied);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
for (i = 0; i < VSER_DEV_CNT; i++) {
|
||||
cdev_init(&vsdev[i].cdev, &vser_ops);
|
||||
vsdev[i].cdev.owner = THIS_MODULE;
|
||||
vsdev[i].fifo = i == 0 ? (struct kfifo *) &vsfifo0 : (struct kfifo*)&vsfifo1;
|
||||
|
||||
ret = cdev_add(&vsdev[i].cdev, dev + i, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
add_err:
|
||||
for (--i; i > 0; --i)
|
||||
cdev_del(&vsdev[i].cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
int i;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
for (i = 0; i < VSER_DEV_CNT; i++)
|
||||
cdev_del(&vsdev[i].cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
22
concurrence/ex1/Makefile
Executable file
22
concurrence/ex1/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vser.o
|
||||
|
||||
endif
|
||||
|
||||
277
concurrence/ex1/vser.c
Executable file
277
concurrence/ex1/vser.c
Executable file
@ -0,0 +1,277 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/aio.h>
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "vser.h"
|
||||
|
||||
#define VSER_MAJOR 256
|
||||
#define VSER_MINOR 0
|
||||
#define VSER_DEV_CNT 1
|
||||
#define VSER_DEV_NAME "vser"
|
||||
#define VSER_FIFO_SIZE 32
|
||||
|
||||
struct vser_dev {
|
||||
wait_queue_head_t rwqh;
|
||||
struct fasync_struct *fapp;
|
||||
atomic_t available;
|
||||
unsigned int baud;
|
||||
struct option opt;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
DEFINE_KFIFO(vsfifo, char, VSER_FIFO_SIZE);
|
||||
static struct vser_dev vsdev;
|
||||
|
||||
static void vser_work(struct work_struct *work);
|
||||
DECLARE_WORK(vswork, vser_work);
|
||||
|
||||
static int vser_fasync(int fd, struct file *filp, int on);
|
||||
|
||||
static int vser_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (atomic_dec_and_test(&vsdev.available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&vsdev.available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int vser_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
vser_fasync(-1, filp, 0);
|
||||
atomic_inc(&vsdev.available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vser_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
char tbuf[VSER_FIFO_SIZE];
|
||||
|
||||
len = count > sizeof(tbuf) ? sizeof(tbuf) : count;
|
||||
spin_lock(&vsdev.rwqh.lock);
|
||||
if (kfifo_is_empty(&vsfifo)) {
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
spin_unlock(&vsdev.rwqh.lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (wait_event_interruptible_locked(vsdev.rwqh, !kfifo_is_empty(&vsfifo))) {
|
||||
spin_unlock(&vsdev.rwqh.lock);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
}
|
||||
|
||||
len = kfifo_out(&vsfifo, tbuf, len);
|
||||
spin_unlock(&vsdev.rwqh.lock);
|
||||
|
||||
ret = copy_to_user(buf, tbuf, len);
|
||||
return len - ret;
|
||||
}
|
||||
|
||||
static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
|
||||
int ret;
|
||||
int len;
|
||||
char *tbuf[VSER_FIFO_SIZE];
|
||||
|
||||
len = count > sizeof(tbuf) ? sizeof(tbuf) : count;
|
||||
ret = copy_from_user(tbuf, buf, len);
|
||||
|
||||
return len - ret;
|
||||
}
|
||||
|
||||
static long vser_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (_IOC_TYPE(cmd) != VS_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case VS_SET_BAUD:
|
||||
vsdev.baud = arg;
|
||||
break;
|
||||
case VS_GET_BAUD:
|
||||
arg = vsdev.baud;
|
||||
break;
|
||||
case VS_SET_FFMT:
|
||||
if (copy_from_user(&vsdev.opt, (struct option __user *)arg, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case VS_GET_FFMT:
|
||||
if (copy_to_user((struct option __user *)arg, &vsdev.opt, sizeof(struct option)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int vser_poll(struct file *filp, struct poll_table_struct *p)
|
||||
{
|
||||
int mask = POLLOUT | POLLWRNORM;
|
||||
|
||||
poll_wait(filp, &vsdev.rwqh, p);
|
||||
|
||||
spin_lock(&vsdev.rwqh.lock);
|
||||
if (!kfifo_is_empty(&vsfifo))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
spin_unlock(&vsdev.rwqh.lock);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t vser_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
size_t read = 0;
|
||||
unsigned long i;
|
||||
ssize_t ret;
|
||||
|
||||
for (i = 0; i < nr_segs; i++) {
|
||||
ret = vser_read(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, &pos);
|
||||
if (ret < 0)
|
||||
break;
|
||||
read += ret;
|
||||
}
|
||||
|
||||
return read ? read : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t vser_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
size_t written = 0;
|
||||
unsigned long i;
|
||||
ssize_t ret;
|
||||
|
||||
for (i = 0; i < nr_segs; i++) {
|
||||
ret = vser_write(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, &pos);
|
||||
if (ret < 0)
|
||||
break;
|
||||
written += ret;
|
||||
}
|
||||
|
||||
return written ? written : -EFAULT;
|
||||
}
|
||||
|
||||
static int vser_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
return fasync_helper(fd, filp, on, &vsdev.fapp);
|
||||
}
|
||||
|
||||
static irqreturn_t vser_handler(int irq, void *dev_id)
|
||||
{
|
||||
schedule_work(&vswork);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void vser_work(struct work_struct *work)
|
||||
{
|
||||
char data;
|
||||
|
||||
get_random_bytes(&data, sizeof(data));
|
||||
data %= 26;
|
||||
data += 'A';
|
||||
|
||||
spin_lock(&vsdev.rwqh.lock);
|
||||
if (!kfifo_is_full(&vsfifo))
|
||||
if(!kfifo_in(&vsfifo, &data, sizeof(data)))
|
||||
printk(KERN_ERR "vser: kfifo_in failure\n");
|
||||
|
||||
if (!kfifo_is_empty(&vsfifo)) {
|
||||
spin_unlock(&vsdev.rwqh.lock);
|
||||
wake_up_interruptible(&vsdev.rwqh);
|
||||
kill_fasync(&vsdev.fapp, SIGIO, POLL_IN);
|
||||
} else
|
||||
spin_unlock(&vsdev.rwqh.lock);
|
||||
}
|
||||
|
||||
static struct file_operations vser_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = vser_open,
|
||||
.release = vser_release,
|
||||
.read = vser_read,
|
||||
.write = vser_write,
|
||||
.unlocked_ioctl = vser_ioctl,
|
||||
.poll = vser_poll,
|
||||
.aio_read = vser_aio_read,
|
||||
.aio_write = vser_aio_write,
|
||||
.fasync = vser_fasync,
|
||||
};
|
||||
|
||||
static int __init vser_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
cdev_init(&vsdev.cdev, &vser_ops);
|
||||
vsdev.cdev.owner = THIS_MODULE;
|
||||
vsdev.baud = 115200;
|
||||
vsdev.opt.datab = 8;
|
||||
vsdev.opt.parity = 0;
|
||||
vsdev.opt.stopb = 1;
|
||||
|
||||
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
init_waitqueue_head(&vsdev.rwqh);
|
||||
|
||||
ret = request_irq(167, vser_handler, IRQF_TRIGGER_HIGH | IRQF_SHARED, "vser", &vsdev);
|
||||
if (ret)
|
||||
goto irq_err;
|
||||
|
||||
atomic_set(&vsdev.available, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
irq_err:
|
||||
cdev_del(&vsdev.cdev);
|
||||
add_err:
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vser_exit(void)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
|
||||
|
||||
free_irq(167, &vsdev);
|
||||
cdev_del(&vsdev.cdev);
|
||||
unregister_chrdev_region(dev, VSER_DEV_CNT);
|
||||
}
|
||||
|
||||
module_init(vser_init);
|
||||
module_exit(vser_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver");
|
||||
MODULE_ALIAS("virtual-serial");
|
||||
17
concurrence/ex1/vser.h
Executable file
17
concurrence/ex1/vser.h
Executable file
@ -0,0 +1,17 @@
|
||||
#ifndef _VSER_H
|
||||
#define _VSER_H
|
||||
|
||||
struct option {
|
||||
unsigned int datab;
|
||||
unsigned int parity;
|
||||
unsigned int stopb;
|
||||
};
|
||||
|
||||
#define VS_MAGIC 's'
|
||||
|
||||
#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int)
|
||||
#define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int)
|
||||
#define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option)
|
||||
#define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)
|
||||
|
||||
#endif
|
||||
22
devmodel/ex1/Makefile
Executable file
22
devmodel/ex1/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := model.o
|
||||
|
||||
endif
|
||||
|
||||
66
devmodel/ex1/model.c
Executable file
66
devmodel/ex1/model.c
Executable file
@ -0,0 +1,66 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
static struct kset *kset;
|
||||
static struct kobject *kobj1;
|
||||
static struct kobject *kobj2;
|
||||
static unsigned int val = 0;
|
||||
|
||||
static ssize_t val_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t val_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
char *endp;
|
||||
|
||||
printk("size = %d\n", count);
|
||||
val = simple_strtoul(buf, &endp, 10);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute kobj1_val_attr = __ATTR(val, 0666, val_show, val_store);
|
||||
static struct attribute *kobj1_attrs[] = {
|
||||
&kobj1_val_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group kobj1_attr_group = {
|
||||
.attrs = kobj1_attrs,
|
||||
};
|
||||
|
||||
static int __init model_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
kset = kset_create_and_add("kset", NULL, NULL);
|
||||
kobj1 = kobject_create_and_add("kobj1", &kset->kobj);
|
||||
kobj2 = kobject_create_and_add("kobj2", &kset->kobj);
|
||||
|
||||
ret = sysfs_create_group(kobj1, &kobj1_attr_group);
|
||||
ret = sysfs_create_link(kobj2, kobj1, "kobj1");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit model_exit(void)
|
||||
{
|
||||
sysfs_remove_link(kobj2, "kobj1");
|
||||
sysfs_remove_group(kobj1, &kobj1_attr_group);
|
||||
kobject_del(kobj2);
|
||||
kobject_del(kobj1);
|
||||
kset_unregister(kset);
|
||||
}
|
||||
|
||||
module_init(model_init);
|
||||
module_exit(model_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple module for device model");
|
||||
21
devmodel/ex2/Makefile
Executable file
21
devmodel/ex2/Makefile
Executable file
@ -0,0 +1,21 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := vbus.o vdrv.o vdev.o
|
||||
|
||||
endif
|
||||
34
devmodel/ex2/vbus.c
Executable file
34
devmodel/ex2/vbus.c
Executable file
@ -0,0 +1,34 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
static int vbus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct bus_type vbus = {
|
||||
.name = "vbus",
|
||||
.match = vbus_match,
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(vbus);
|
||||
|
||||
static int __init vbus_init(void)
|
||||
{
|
||||
return bus_register(&vbus);
|
||||
}
|
||||
|
||||
static void __exit vbus_exit(void)
|
||||
{
|
||||
bus_unregister(&vbus);
|
||||
}
|
||||
|
||||
module_init(vbus_init);
|
||||
module_exit(vbus_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A virtual bus");
|
||||
34
devmodel/ex2/vdev.c
Executable file
34
devmodel/ex2/vdev.c
Executable file
@ -0,0 +1,34 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
extern struct bus_type vbus;
|
||||
|
||||
static void vdev_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static struct device vdev = {
|
||||
.init_name = "vdev",
|
||||
.bus = &vbus,
|
||||
.release = vdev_release,
|
||||
};
|
||||
|
||||
static int __init vdev_init(void)
|
||||
{
|
||||
return device_register(&vdev);
|
||||
}
|
||||
|
||||
static void __exit vdev_exit(void)
|
||||
{
|
||||
device_unregister(&vdev);
|
||||
}
|
||||
|
||||
module_init(vdev_init);
|
||||
module_exit(vdev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A virtual device");
|
||||
29
devmodel/ex2/vdrv.c
Executable file
29
devmodel/ex2/vdrv.c
Executable file
@ -0,0 +1,29 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
extern struct bus_type vbus;
|
||||
|
||||
static struct device_driver vdrv = {
|
||||
.name = "vdrv",
|
||||
.bus = &vbus,
|
||||
};
|
||||
|
||||
static int __init vdrv_init(void)
|
||||
{
|
||||
return driver_register(&vdrv);
|
||||
}
|
||||
|
||||
static void __exit vdrv_exit(void)
|
||||
{
|
||||
driver_unregister(&vdrv);
|
||||
}
|
||||
|
||||
module_init(vdrv_init);
|
||||
module_exit(vdrv_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A virtual device driver");
|
||||
21
devmodel/ex3/Makefile
Executable file
21
devmodel/ex3/Makefile
Executable file
@ -0,0 +1,21 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := pltdev.o pltdrv.o
|
||||
|
||||
endif
|
||||
50
devmodel/ex3/pltdev.c
Executable file
50
devmodel/ex3/pltdev.c
Executable file
@ -0,0 +1,50 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static void pdev_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
struct platform_device pdev0 = {
|
||||
.name = "pdev",
|
||||
.id = 0,
|
||||
.num_resources = 0,
|
||||
.resource = NULL,
|
||||
.dev = {
|
||||
.release = pdev_release,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device pdev1 = {
|
||||
.name = "pdev",
|
||||
.id = 1,
|
||||
.num_resources = 0,
|
||||
.resource = NULL,
|
||||
.dev = {
|
||||
.release = pdev_release,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pltdev_init(void)
|
||||
{
|
||||
platform_device_register(&pdev0);
|
||||
platform_device_register(&pdev1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit pltdev_exit(void)
|
||||
{
|
||||
platform_device_unregister(&pdev1);
|
||||
platform_device_unregister(&pdev0);
|
||||
}
|
||||
|
||||
module_init(pltdev_init);
|
||||
module_exit(pltdev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("register a platfom device");
|
||||
49
devmodel/ex3/pltdrv.c
Executable file
49
devmodel/ex3/pltdrv.c
Executable file
@ -0,0 +1,49 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int pdrv_suspend(struct device *dev)
|
||||
{
|
||||
printk("pdev: suspend\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdrv_resume(struct device *dev)
|
||||
{
|
||||
printk("pdev: resume\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops pdrv_pm_ops = {
|
||||
.suspend = pdrv_suspend,
|
||||
.resume = pdrv_resume,
|
||||
};
|
||||
|
||||
static int pdrv_probe(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdrv_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver pdrv = {
|
||||
.driver = {
|
||||
.name = "pdev",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pdrv_pm_ops,
|
||||
},
|
||||
.probe = pdrv_probe,
|
||||
.remove = pdrv_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(pdrv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple platform driver");
|
||||
MODULE_ALIAS("platform:pdev");
|
||||
23
devmodel/ex4/Makefile
Executable file
23
devmodel/ex4/Makefile
Executable file
@ -0,0 +1,23 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fsled.o
|
||||
obj-m += fsdev.o
|
||||
|
||||
endif
|
||||
|
||||
101
devmodel/ex4/fsdev.c
Executable file
101
devmodel/ex4/fsdev.c
Executable file
@ -0,0 +1,101 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static void fsdev_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static struct resource led2_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x11000C40, 4),
|
||||
};
|
||||
|
||||
static struct resource led3_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x11000C20, 4),
|
||||
};
|
||||
|
||||
static struct resource led4_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x114001E0, 4),
|
||||
};
|
||||
|
||||
static struct resource led5_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x114001E0, 4),
|
||||
};
|
||||
|
||||
unsigned int led2pin = 7;
|
||||
unsigned int led3pin = 0;
|
||||
unsigned int led4pin = 4;
|
||||
unsigned int led5pin = 5;
|
||||
|
||||
struct platform_device fsled2 = {
|
||||
.name = "fsled",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(led2_resources),
|
||||
.resource = led2_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led2pin,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device fsled3 = {
|
||||
.name = "fsled",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(led3_resources),
|
||||
.resource = led3_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led3pin,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device fsled4 = {
|
||||
.name = "fsled",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(led4_resources),
|
||||
.resource = led4_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led4pin,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device fsled5 = {
|
||||
.name = "fsled",
|
||||
.id = 5,
|
||||
.num_resources = ARRAY_SIZE(led5_resources),
|
||||
.resource = led5_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led5pin,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *fsled_devices[] = {
|
||||
&fsled2,
|
||||
&fsled3,
|
||||
&fsled4,
|
||||
&fsled5,
|
||||
};
|
||||
|
||||
static int __init fsdev_init(void)
|
||||
{
|
||||
return platform_add_devices(fsled_devices, ARRAY_SIZE(fsled_devices));
|
||||
}
|
||||
|
||||
static void __exit fsdev_exit(void)
|
||||
{
|
||||
platform_device_unregister(&fsled5);
|
||||
platform_device_unregister(&fsled4);
|
||||
platform_device_unregister(&fsled3);
|
||||
platform_device_unregister(&fsled2);
|
||||
}
|
||||
|
||||
module_init(fsdev_init);
|
||||
module_exit(fsdev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("register LED devices");
|
||||
165
devmodel/ex4/fsled.c
Executable file
165
devmodel/ex4/fsled.c
Executable file
@ -0,0 +1,165 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "fsled.h"
|
||||
|
||||
#define FSLED_MAJOR 256
|
||||
#define FSLED_DEV_NAME "fsled"
|
||||
|
||||
struct fsled_dev {
|
||||
unsigned int __iomem *con;
|
||||
unsigned int __iomem *dat;
|
||||
unsigned int pin;
|
||||
atomic_t available;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static int fsled_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsled_dev *fsled = container_of(inode->i_cdev, struct fsled_dev, cdev);
|
||||
|
||||
filp->private_data = fsled;
|
||||
if (atomic_dec_and_test(&fsled->available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&fsled->available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int fsled_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsled_dev *fsled = filp->private_data;
|
||||
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
|
||||
atomic_inc(&fsled->available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fsled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct fsled_dev *fsled = filp->private_data;
|
||||
|
||||
if (_IOC_TYPE(cmd) != FSLED_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case FSLED_ON:
|
||||
writel(readl(fsled->dat) | (0x1 << fsled->pin), fsled->dat);
|
||||
break;
|
||||
case FSLED_OFF:
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations fsled_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fsled_open,
|
||||
.release = fsled_release,
|
||||
.unlocked_ioctl = fsled_ioctl,
|
||||
};
|
||||
|
||||
static int fsled_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
struct fsled_dev *fsled;
|
||||
struct resource *res;
|
||||
unsigned int pin = *(unsigned int*)pdev->dev.platform_data;
|
||||
|
||||
dev = MKDEV(FSLED_MAJOR, pdev->id);
|
||||
ret = register_chrdev_region(dev, 1, FSLED_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
fsled = kzalloc(sizeof(struct fsled_dev), GFP_KERNEL);
|
||||
if (!fsled) {
|
||||
ret = -ENOMEM;
|
||||
goto mem_err;
|
||||
}
|
||||
|
||||
cdev_init(&fsled->cdev, &fsled_ops);
|
||||
fsled->cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&fsled->cdev, dev, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
fsled->con = ioremap(res->start, resource_size(res));
|
||||
if (!fsled->con) {
|
||||
ret = -EBUSY;
|
||||
goto map_err;
|
||||
}
|
||||
fsled->dat = fsled->con + 1;
|
||||
|
||||
fsled->pin = pin;
|
||||
atomic_set(&fsled->available, 1);
|
||||
writel((readl(fsled->con) & ~(0xF << 4 * fsled->pin)) | (0x1 << 4 * fsled->pin), fsled->con);
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
platform_set_drvdata(pdev, fsled);
|
||||
|
||||
return 0;
|
||||
|
||||
map_err:
|
||||
res_err:
|
||||
cdev_del(&fsled->cdev);
|
||||
add_err:
|
||||
kfree(fsled);
|
||||
mem_err:
|
||||
unregister_chrdev_region(dev, 1);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsled_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_t dev;
|
||||
struct fsled_dev *fsled = platform_get_drvdata(pdev);
|
||||
|
||||
dev = MKDEV(FSLED_MAJOR, pdev->id);
|
||||
|
||||
iounmap(fsled->con);
|
||||
cdev_del(&fsled->cdev);
|
||||
kfree(fsled);
|
||||
unregister_chrdev_region(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver fsled_drv = {
|
||||
.driver = {
|
||||
.name = "fsled",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = fsled_probe,
|
||||
.remove = fsled_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fsled_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board");
|
||||
9
devmodel/ex4/fsled.h
Executable file
9
devmodel/ex4/fsled.h
Executable file
@ -0,0 +1,9 @@
|
||||
#ifndef _FSLED_H
|
||||
#define _FSLED_H
|
||||
|
||||
#define FSLED_MAGIC 'f'
|
||||
|
||||
#define FSLED_ON _IO(FSLED_MAGIC, 0)
|
||||
#define FSLED_OFF _IO(FSLED_MAGIC, 1)
|
||||
|
||||
#endif
|
||||
46
devmodel/ex4/test.c
Executable file
46
devmodel/ex4/test.c
Executable file
@ -0,0 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fsled.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd[4];
|
||||
int ret;
|
||||
int num = 0;
|
||||
|
||||
fd[0] = open("/dev/led2", O_RDWR);
|
||||
if (fd[0] == -1)
|
||||
goto fail;
|
||||
fd[1] = open("/dev/led3", O_RDWR);
|
||||
if (fd[1] == -1)
|
||||
goto fail;
|
||||
fd[2] = open("/dev/led4", O_RDWR);
|
||||
if (fd[2] == -1)
|
||||
goto fail;
|
||||
fd[3] = open("/dev/led5", O_RDWR);
|
||||
if (fd[3] == -1)
|
||||
goto fail;
|
||||
|
||||
while (1) {
|
||||
ret = ioctl(fd[num], FSLED_ON);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(500000);
|
||||
ret = ioctl(fd[num], FSLED_OFF);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(500000);
|
||||
|
||||
num = (num + 1) % 4;
|
||||
}
|
||||
fail:
|
||||
perror("led test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
23
devmodel/ex5/Makefile
Executable file
23
devmodel/ex5/Makefile
Executable file
@ -0,0 +1,23 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fsled.o
|
||||
obj-m += fsdev.o
|
||||
|
||||
endif
|
||||
|
||||
101
devmodel/ex5/fsdev.c
Executable file
101
devmodel/ex5/fsdev.c
Executable file
@ -0,0 +1,101 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static void fsdev_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static struct resource led2_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x11000C40, 4),
|
||||
};
|
||||
|
||||
static struct resource led3_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x11000C20, 4),
|
||||
};
|
||||
|
||||
static struct resource led4_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x114001E0, 4),
|
||||
};
|
||||
|
||||
static struct resource led5_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(0x114001E0, 4),
|
||||
};
|
||||
|
||||
unsigned int led2pin = 7;
|
||||
unsigned int led3pin = 0;
|
||||
unsigned int led4pin = 4;
|
||||
unsigned int led5pin = 5;
|
||||
|
||||
struct platform_device fsled2 = {
|
||||
.name = "fsled",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(led2_resources),
|
||||
.resource = led2_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led2pin,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device fsled3 = {
|
||||
.name = "fsled",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(led3_resources),
|
||||
.resource = led3_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led3pin,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device fsled4 = {
|
||||
.name = "fsled",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(led4_resources),
|
||||
.resource = led4_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led4pin,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device fsled5 = {
|
||||
.name = "fsled",
|
||||
.id = 5,
|
||||
.num_resources = ARRAY_SIZE(led5_resources),
|
||||
.resource = led5_resources,
|
||||
.dev = {
|
||||
.release = fsdev_release,
|
||||
.platform_data = &led5pin,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *fsled_devices[] = {
|
||||
&fsled2,
|
||||
&fsled3,
|
||||
&fsled4,
|
||||
&fsled5,
|
||||
};
|
||||
|
||||
static int __init fsdev_init(void)
|
||||
{
|
||||
return platform_add_devices(fsled_devices, ARRAY_SIZE(fsled_devices));
|
||||
}
|
||||
|
||||
static void __exit fsdev_exit(void)
|
||||
{
|
||||
platform_device_unregister(&fsled5);
|
||||
platform_device_unregister(&fsled4);
|
||||
platform_device_unregister(&fsled3);
|
||||
platform_device_unregister(&fsled2);
|
||||
}
|
||||
|
||||
module_init(fsdev_init);
|
||||
module_exit(fsdev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("register LED devices");
|
||||
199
devmodel/ex5/fsled.c
Executable file
199
devmodel/ex5/fsled.c
Executable file
@ -0,0 +1,199 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "fsled.h"
|
||||
|
||||
#define FSLED_MAJOR 256
|
||||
#define FSLED_DEV_NAME "fsled"
|
||||
|
||||
struct fsled_dev {
|
||||
unsigned int __iomem *con;
|
||||
unsigned int __iomem *dat;
|
||||
unsigned int pin;
|
||||
atomic_t available;
|
||||
struct cdev cdev;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct class *fsled_cls;
|
||||
|
||||
static int fsled_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsled_dev *fsled = container_of(inode->i_cdev, struct fsled_dev, cdev);
|
||||
|
||||
filp->private_data = fsled;
|
||||
if (atomic_dec_and_test(&fsled->available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&fsled->available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int fsled_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsled_dev *fsled = filp->private_data;
|
||||
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
|
||||
atomic_inc(&fsled->available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fsled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct fsled_dev *fsled = filp->private_data;
|
||||
|
||||
if (_IOC_TYPE(cmd) != FSLED_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case FSLED_ON:
|
||||
writel(readl(fsled->dat) | (0x1 << fsled->pin), fsled->dat);
|
||||
break;
|
||||
case FSLED_OFF:
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations fsled_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fsled_open,
|
||||
.release = fsled_release,
|
||||
.unlocked_ioctl = fsled_ioctl,
|
||||
};
|
||||
|
||||
static int fsled_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
struct fsled_dev *fsled;
|
||||
struct resource *res;
|
||||
unsigned int pin = *(unsigned int*)pdev->dev.platform_data;
|
||||
|
||||
dev = MKDEV(FSLED_MAJOR, pdev->id);
|
||||
ret = register_chrdev_region(dev, 1, FSLED_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
fsled = kzalloc(sizeof(struct fsled_dev), GFP_KERNEL);
|
||||
if (!fsled) {
|
||||
ret = -ENOMEM;
|
||||
goto mem_err;
|
||||
}
|
||||
|
||||
cdev_init(&fsled->cdev, &fsled_ops);
|
||||
fsled->cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&fsled->cdev, dev, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
fsled->con = ioremap(res->start, resource_size(res));
|
||||
if (!fsled->con) {
|
||||
ret = -EBUSY;
|
||||
goto map_err;
|
||||
}
|
||||
fsled->dat = fsled->con + 1;
|
||||
|
||||
fsled->pin = pin;
|
||||
atomic_set(&fsled->available, 1);
|
||||
writel((readl(fsled->con) & ~(0xF << 4 * fsled->pin)) | (0x1 << 4 * fsled->pin), fsled->con);
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
platform_set_drvdata(pdev, fsled);
|
||||
|
||||
fsled->dev = device_create(fsled_cls, NULL, dev, NULL, "led%d", pdev->id);
|
||||
if (IS_ERR(fsled->dev)) {
|
||||
ret = PTR_ERR(fsled->dev);
|
||||
goto dev_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dev_err:
|
||||
iounmap(fsled->con);
|
||||
map_err:
|
||||
res_err:
|
||||
cdev_del(&fsled->cdev);
|
||||
add_err:
|
||||
kfree(fsled);
|
||||
mem_err:
|
||||
unregister_chrdev_region(dev, 1);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsled_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_t dev;
|
||||
struct fsled_dev *fsled = platform_get_drvdata(pdev);
|
||||
|
||||
dev = MKDEV(FSLED_MAJOR, pdev->id);
|
||||
|
||||
device_destroy(fsled_cls, dev);
|
||||
iounmap(fsled->con);
|
||||
cdev_del(&fsled->cdev);
|
||||
kfree(fsled);
|
||||
unregister_chrdev_region(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver fsled_drv = {
|
||||
.driver = {
|
||||
.name = "fsled",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = fsled_probe,
|
||||
.remove = fsled_remove,
|
||||
};
|
||||
|
||||
static int __init fsled_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
fsled_cls = class_create(THIS_MODULE, "fsled");
|
||||
if (IS_ERR(fsled_cls))
|
||||
return PTR_ERR(fsled_cls);
|
||||
|
||||
ret = platform_driver_register(&fsled_drv);
|
||||
if (ret)
|
||||
class_destroy(fsled_cls);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fsled_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&fsled_drv);
|
||||
class_destroy(fsled_cls);
|
||||
}
|
||||
|
||||
module_init(fsled_init);
|
||||
module_exit(fsled_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board");
|
||||
9
devmodel/ex5/fsled.h
Executable file
9
devmodel/ex5/fsled.h
Executable file
@ -0,0 +1,9 @@
|
||||
#ifndef _FSLED_H
|
||||
#define _FSLED_H
|
||||
|
||||
#define FSLED_MAGIC 'f'
|
||||
|
||||
#define FSLED_ON _IO(FSLED_MAGIC, 0)
|
||||
#define FSLED_OFF _IO(FSLED_MAGIC, 1)
|
||||
|
||||
#endif
|
||||
46
devmodel/ex5/test.c
Executable file
46
devmodel/ex5/test.c
Executable file
@ -0,0 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fsled.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd[4];
|
||||
int ret;
|
||||
int num = 0;
|
||||
|
||||
fd[0] = open("/dev/led2", O_RDWR);
|
||||
if (fd[0] == -1)
|
||||
goto fail;
|
||||
fd[1] = open("/dev/led3", O_RDWR);
|
||||
if (fd[1] == -1)
|
||||
goto fail;
|
||||
fd[2] = open("/dev/led4", O_RDWR);
|
||||
if (fd[2] == -1)
|
||||
goto fail;
|
||||
fd[3] = open("/dev/led5", O_RDWR);
|
||||
if (fd[3] == -1)
|
||||
goto fail;
|
||||
|
||||
while (1) {
|
||||
ret = ioctl(fd[num], FSLED_ON);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(500000);
|
||||
ret = ioctl(fd[num], FSLED_OFF);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(500000);
|
||||
|
||||
num = (num + 1) % 4;
|
||||
}
|
||||
fail:
|
||||
perror("led test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
22
devmodel/ex6/Makefile
Executable file
22
devmodel/ex6/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fsled.o
|
||||
|
||||
endif
|
||||
|
||||
183
devmodel/ex6/fsled.c
Executable file
183
devmodel/ex6/fsled.c
Executable file
@ -0,0 +1,183 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "fsled.h"
|
||||
|
||||
#define FSLED_MAJOR 256
|
||||
#define FSLED_DEV_NAME "fsled"
|
||||
|
||||
struct fsled_dev {
|
||||
unsigned int __iomem *con;
|
||||
unsigned int __iomem *dat;
|
||||
unsigned int pin;
|
||||
atomic_t available;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static int fsled_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsled_dev *fsled = container_of(inode->i_cdev, struct fsled_dev, cdev);
|
||||
|
||||
filp->private_data = fsled;
|
||||
if (atomic_dec_and_test(&fsled->available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&fsled->available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int fsled_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsled_dev *fsled = filp->private_data;
|
||||
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
|
||||
atomic_inc(&fsled->available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fsled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct fsled_dev *fsled = filp->private_data;
|
||||
|
||||
if (_IOC_TYPE(cmd) != FSLED_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case FSLED_ON:
|
||||
writel(readl(fsled->dat) | (0x1 << fsled->pin), fsled->dat);
|
||||
break;
|
||||
case FSLED_OFF:
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations fsled_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fsled_open,
|
||||
.release = fsled_release,
|
||||
.unlocked_ioctl = fsled_ioctl,
|
||||
};
|
||||
|
||||
static int fsled_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
struct fsled_dev *fsled;
|
||||
struct resource *res;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "id", &pdev->id);
|
||||
if (ret)
|
||||
goto id_err;
|
||||
|
||||
dev = MKDEV(FSLED_MAJOR, pdev->id);
|
||||
ret = register_chrdev_region(dev, 1, FSLED_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
fsled = kzalloc(sizeof(struct fsled_dev), GFP_KERNEL);
|
||||
if (!fsled) {
|
||||
ret = -ENOMEM;
|
||||
goto mem_err;
|
||||
}
|
||||
|
||||
cdev_init(&fsled->cdev, &fsled_ops);
|
||||
fsled->cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&fsled->cdev, dev, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
fsled->con = ioremap(res->start, resource_size(res));
|
||||
if (!fsled->con) {
|
||||
ret = -EBUSY;
|
||||
goto map_err;
|
||||
}
|
||||
fsled->dat = fsled->con + 1;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "pin", &fsled->pin);
|
||||
if (ret)
|
||||
goto pin_err;
|
||||
|
||||
atomic_set(&fsled->available, 1);
|
||||
writel((readl(fsled->con) & ~(0xF << 4 * fsled->pin)) | (0x1 << 4 * fsled->pin), fsled->con);
|
||||
writel(readl(fsled->dat) & ~(0x1 << fsled->pin), fsled->dat);
|
||||
platform_set_drvdata(pdev, fsled);
|
||||
|
||||
return 0;
|
||||
|
||||
pin_err:
|
||||
iounmap(fsled->con);
|
||||
map_err:
|
||||
res_err:
|
||||
cdev_del(&fsled->cdev);
|
||||
add_err:
|
||||
kfree(fsled);
|
||||
mem_err:
|
||||
unregister_chrdev_region(dev, 1);
|
||||
reg_err:
|
||||
id_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsled_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_t dev;
|
||||
struct fsled_dev *fsled = platform_get_drvdata(pdev);
|
||||
|
||||
dev = MKDEV(FSLED_MAJOR, pdev->id);
|
||||
|
||||
iounmap(fsled->con);
|
||||
cdev_del(&fsled->cdev);
|
||||
kfree(fsled);
|
||||
unregister_chrdev_region(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fsled_of_matches[] = {
|
||||
{ .compatible = "fs4412,fsled", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsled_of_matches);
|
||||
|
||||
struct platform_driver pdrv = {
|
||||
.driver = {
|
||||
.name = "fsled",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(fsled_of_matches),
|
||||
},
|
||||
.probe = fsled_probe,
|
||||
.remove = fsled_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(pdrv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board");
|
||||
9
devmodel/ex6/fsled.h
Executable file
9
devmodel/ex6/fsled.h
Executable file
@ -0,0 +1,9 @@
|
||||
#ifndef _FSLED_H
|
||||
#define _FSLED_H
|
||||
|
||||
#define FSLED_MAGIC 'f'
|
||||
|
||||
#define FSLED_ON _IO(FSLED_MAGIC, 0)
|
||||
#define FSLED_OFF _IO(FSLED_MAGIC, 1)
|
||||
|
||||
#endif
|
||||
46
devmodel/ex6/test.c
Executable file
46
devmodel/ex6/test.c
Executable file
@ -0,0 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fsled.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd[4];
|
||||
int ret;
|
||||
int num = 0;
|
||||
|
||||
fd[0] = open("/dev/led2", O_RDWR);
|
||||
if (fd[0] == -1)
|
||||
goto fail;
|
||||
fd[1] = open("/dev/led3", O_RDWR);
|
||||
if (fd[1] == -1)
|
||||
goto fail;
|
||||
fd[2] = open("/dev/led4", O_RDWR);
|
||||
if (fd[2] == -1)
|
||||
goto fail;
|
||||
fd[3] = open("/dev/led5", O_RDWR);
|
||||
if (fd[3] == -1)
|
||||
goto fail;
|
||||
|
||||
while (1) {
|
||||
ret = ioctl(fd[num], FSLED_ON);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(500000);
|
||||
ret = ioctl(fd[num], FSLED_OFF);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(500000);
|
||||
|
||||
num = (num + 1) % 4;
|
||||
}
|
||||
fail:
|
||||
perror("led test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
22
dma/ex1/Makefile
Executable file
22
dma/ex1/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := memcpy.o
|
||||
|
||||
endif
|
||||
|
||||
96
dma/ex1/memcpy.c
Executable file
96
dma/ex1/memcpy.c
Executable file
@ -0,0 +1,96 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct dma_chan *chan;
|
||||
unsigned int *txbuf;
|
||||
unsigned int *rxbuf;
|
||||
dma_addr_t txaddr;
|
||||
dma_addr_t rxaddr;
|
||||
|
||||
static void dma_callback(void *data)
|
||||
{
|
||||
int i;
|
||||
unsigned int *p = rxbuf;
|
||||
printk("dma complete\n");
|
||||
|
||||
for (i = 0; i < PAGE_SIZE / sizeof(unsigned int); i++)
|
||||
printk("%d ", *p++);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static bool filter(struct dma_chan *chan, void *filter_param)
|
||||
{
|
||||
printk("%s\n", dma_chan_name(chan));
|
||||
return strcmp(dma_chan_name(chan), filter_param) == 0;
|
||||
}
|
||||
|
||||
static int __init memcpy_init(void)
|
||||
{
|
||||
int i;
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
char name[] = "dma2chan0";
|
||||
unsigned int *p;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_MEMCPY, mask);
|
||||
chan = dma_request_channel(mask, filter, name);
|
||||
if (!chan) {
|
||||
printk("dma_request_channel failure\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
txbuf = dma_alloc_coherent(chan->device->dev, PAGE_SIZE, &txaddr, GFP_KERNEL);
|
||||
if (!txbuf) {
|
||||
printk("dma_alloc_coherent failure\n");
|
||||
dma_release_channel(chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rxbuf = dma_alloc_coherent(chan->device->dev, PAGE_SIZE, &rxaddr, GFP_KERNEL);
|
||||
if (!rxbuf) {
|
||||
printk("dma_alloc_coherent failure\n");
|
||||
dma_free_coherent(chan->device->dev, PAGE_SIZE, txbuf, txaddr);
|
||||
dma_release_channel(chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0, p = txbuf; i < PAGE_SIZE / sizeof(unsigned int); i++)
|
||||
*p++ = i;
|
||||
for (i = 0, p = txbuf; i < PAGE_SIZE / sizeof(unsigned int); i++)
|
||||
printk("%d ", *p++);
|
||||
printk("\n");
|
||||
|
||||
memset(rxbuf, 0, PAGE_SIZE);
|
||||
for (i = 0, p = rxbuf; i < PAGE_SIZE / sizeof(unsigned int); i++)
|
||||
printk("%d ", *p++);
|
||||
printk("\n");
|
||||
|
||||
desc = chan->device->device_prep_dma_memcpy(chan, rxaddr, txaddr, PAGE_SIZE, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
|
||||
desc->callback = dma_callback;
|
||||
desc->callback_param = NULL;
|
||||
|
||||
dmaengine_submit(desc);
|
||||
dma_async_issue_pending(chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit memcpy_exit(void)
|
||||
{
|
||||
dma_free_coherent(chan->device->dev, PAGE_SIZE, txbuf, txaddr);
|
||||
dma_free_coherent(chan->device->dev, PAGE_SIZE, rxbuf, rxaddr);
|
||||
dma_release_channel(chan);
|
||||
}
|
||||
|
||||
module_init(memcpy_init);
|
||||
module_exit(memcpy_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("simple driver using dmaengine");
|
||||
61
examples/ex1/test.c
Executable file
61
examples/ex1/test.c
Executable file
@ -0,0 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define LED_DEV_PATH "/sys/class/leds/led%d/brightness"
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
|
||||
int fs4412_set_led(unsigned int lednum, unsigned int mode)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
char devpath[128];
|
||||
char *on = "1\n";
|
||||
char *off = "0\n";
|
||||
char *m = NULL;
|
||||
|
||||
snprintf(devpath, sizeof(devpath), LED_DEV_PATH, lednum);
|
||||
fd = open(devpath, O_WRONLY);
|
||||
if (fd == -1) {
|
||||
perror("fsled->open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mode == ON)
|
||||
m = on;
|
||||
else
|
||||
m = off;
|
||||
|
||||
ret = write(fd, m, strlen(m));
|
||||
if (ret == -1) {
|
||||
perror("fsled->write");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int lednum = 2;
|
||||
|
||||
while (1) {
|
||||
fs4412_set_led(lednum, ON);
|
||||
usleep(500000);
|
||||
fs4412_set_led(lednum, OFF);
|
||||
usleep(500000);
|
||||
|
||||
lednum++;
|
||||
if (lednum > 5)
|
||||
lednum = 2;
|
||||
}
|
||||
}
|
||||
22
examples/ex2/Makefile
Executable file
22
examples/ex2/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fskey.o
|
||||
|
||||
endif
|
||||
|
||||
85
examples/ex2/fskey.c
Executable file
85
examples/ex2/fskey.c
Executable file
@ -0,0 +1,85 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct resource *key2_res;
|
||||
struct resource *key3_res;
|
||||
|
||||
static irqreturn_t fskey_handler(int irq, void *dev_id)
|
||||
{
|
||||
if (irq == key2_res->start)
|
||||
printk("K2 pressed\n");
|
||||
else
|
||||
printk("K3 pressed\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int fskey_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
key2_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
key3_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
|
||||
|
||||
if (!key2_res || !key3_res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
ret = request_irq(key2_res->start, fskey_handler, key2_res->flags & IRQF_TRIGGER_MASK, "key2", NULL);
|
||||
if (ret)
|
||||
goto key2_err;
|
||||
ret = request_irq(key3_res->start, fskey_handler, key3_res->flags & IRQF_TRIGGER_MASK, "key3", NULL);
|
||||
if (ret)
|
||||
goto key3_err;
|
||||
|
||||
return 0;
|
||||
|
||||
key3_err:
|
||||
free_irq(key2_res->start, NULL);
|
||||
key2_err:
|
||||
res_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fskey_remove(struct platform_device *pdev)
|
||||
{
|
||||
free_irq(key3_res->start, NULL);
|
||||
free_irq(key2_res->start, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fskey_of_matches[] = {
|
||||
{ .compatible = "fs4412,fskey", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fskey_of_matches);
|
||||
|
||||
struct platform_driver fskey_drv = {
|
||||
.driver = {
|
||||
.name = "fskey",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(fskey_of_matches),
|
||||
},
|
||||
.probe = fskey_probe,
|
||||
.remove = fskey_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fskey_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple device driver for Keys on FS4412 board");
|
||||
22
examples/ex3/Makefile
Executable file
22
examples/ex3/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fskey.o
|
||||
|
||||
endif
|
||||
|
||||
168
examples/ex3/fskey.c
Executable file
168
examples/ex3/fskey.c
Executable file
@ -0,0 +1,168 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MAX_KEYS_NUM (8)
|
||||
#define SCAN_INTERVAL (50) /* ms */
|
||||
#define KB_ACTIVATE_DELAY (20) /* us */
|
||||
#define KBDSCAN_STABLE_COUNT (3)
|
||||
|
||||
struct fskey_dev {
|
||||
unsigned int count;
|
||||
unsigned int kstate[MAX_KEYS_NUM];
|
||||
unsigned int kcount[MAX_KEYS_NUM];
|
||||
unsigned char keycode[MAX_KEYS_NUM];
|
||||
int gpio[MAX_KEYS_NUM];
|
||||
struct input_polled_dev *polldev;
|
||||
};
|
||||
|
||||
static void fskey_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
unsigned int index;
|
||||
unsigned int kstate;
|
||||
struct fskey_dev *fskey = dev->private;
|
||||
|
||||
for (index = 0; index < fskey->count; index++)
|
||||
fskey->kcount[index] = 0;
|
||||
|
||||
index = 0;
|
||||
do {
|
||||
udelay(KB_ACTIVATE_DELAY);
|
||||
kstate = gpio_get_value(fskey->gpio[index]);
|
||||
if (kstate != fskey->kstate[index]) {
|
||||
fskey->kstate[index] = kstate;
|
||||
fskey->kcount[index] = 0;
|
||||
} else {
|
||||
if (++fskey->kcount[index] >= KBDSCAN_STABLE_COUNT) {
|
||||
input_report_key(dev->input, fskey->keycode[index], !kstate);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
} while (index < fskey->count);
|
||||
|
||||
input_sync(dev->input);
|
||||
}
|
||||
|
||||
static int fskey_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
int index;
|
||||
struct fskey_dev *fskey;
|
||||
|
||||
fskey = kzalloc(sizeof(struct fskey_dev), GFP_KERNEL);
|
||||
if (!fskey)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, fskey);
|
||||
|
||||
for (index = 0; index < MAX_KEYS_NUM; index++) {
|
||||
ret = of_get_gpio(pdev->dev.of_node, index);
|
||||
if (ret < 0)
|
||||
break;
|
||||
else
|
||||
fskey->gpio[index] = ret;
|
||||
}
|
||||
|
||||
if (!index)
|
||||
goto gpio_err;
|
||||
else
|
||||
fskey->count = index;
|
||||
|
||||
for (index = 0; index < fskey->count; index++) {
|
||||
ret = gpio_request(fskey->gpio[index], "KEY");
|
||||
if (ret)
|
||||
goto req_err;
|
||||
|
||||
gpio_direction_input(fskey->gpio[index]);
|
||||
fskey->keycode[index] = KEY_2 + index;
|
||||
fskey->kstate[index] = 1;
|
||||
}
|
||||
|
||||
fskey->polldev = input_allocate_polled_device();
|
||||
if (!fskey->polldev) {
|
||||
ret = -ENOMEM;
|
||||
goto req_err;
|
||||
}
|
||||
|
||||
fskey->polldev->private = fskey;
|
||||
fskey->polldev->poll = fskey_poll;
|
||||
fskey->polldev->poll_interval = SCAN_INTERVAL;
|
||||
|
||||
fskey->polldev->input->name = "FS4412 Keyboard";
|
||||
fskey->polldev->input->phys = "fskbd/input0";
|
||||
fskey->polldev->input->id.bustype = BUS_HOST;
|
||||
fskey->polldev->input->id.vendor = 0x0001;
|
||||
fskey->polldev->input->id.product = 0x0001;
|
||||
fskey->polldev->input->id.version = 0x0100;
|
||||
fskey->polldev->input->dev.parent = &pdev->dev;
|
||||
|
||||
fskey->polldev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
fskey->polldev->input->keycode = fskey->keycode;
|
||||
fskey->polldev->input->keycodesize = sizeof(unsigned char);
|
||||
fskey->polldev->input->keycodemax = index;
|
||||
|
||||
for (index = 0; index < fskey->count; index++)
|
||||
__set_bit(fskey->keycode[index], fskey->polldev->input->keybit);
|
||||
__clear_bit(KEY_RESERVED, fskey->polldev->input->keybit);
|
||||
|
||||
ret = input_register_polled_device(fskey->polldev);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
return 0;
|
||||
|
||||
reg_err:
|
||||
input_free_polled_device(fskey->polldev);
|
||||
req_err:
|
||||
for (index--; index >= 0; index--)
|
||||
gpio_free(fskey->gpio[index]);
|
||||
gpio_err:
|
||||
kfree(fskey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fskey_remove(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int index;
|
||||
struct fskey_dev *fskey = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_polled_device(fskey->polldev);
|
||||
input_free_polled_device(fskey->polldev);
|
||||
for (index = 0; index < fskey->count; index++)
|
||||
gpio_free(fskey->gpio[index]);
|
||||
kfree(fskey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fskey_of_matches[] = {
|
||||
{ .compatible = "fs4412,fskey", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fskey_of_matches);
|
||||
|
||||
struct platform_driver fskey_drv = {
|
||||
.driver = {
|
||||
.name = "fskey",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(fskey_of_matches),
|
||||
},
|
||||
.probe = fskey_probe,
|
||||
.remove = fskey_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fskey_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("A simple device driver for Keys on FS4412 board");
|
||||
46
examples/ex3/test.c
Executable file
46
examples/ex3/test.c
Executable file
@ -0,0 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
|
||||
#define KEY_DEV_PATH "/dev/input/event0"
|
||||
|
||||
int fs4412_get_key(void)
|
||||
{
|
||||
int fd;
|
||||
struct input_event event;
|
||||
|
||||
fd = open(KEY_DEV_PATH, O_RDONLY);
|
||||
if(fd == -1) {
|
||||
perror("fskey->open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if(read(fd, &event, sizeof(event)) == sizeof(event)) {
|
||||
if (event.type == EV_KEY && event.value == 1) {
|
||||
close(fd);
|
||||
return event.code;
|
||||
} else
|
||||
continue;
|
||||
} else {
|
||||
close(fd);
|
||||
fprintf(stderr, "fskey->read: read failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
while (1)
|
||||
printf("key value: %d\n", fs4412_get_key());
|
||||
}
|
||||
BIN
examples/ex4/.test.c.swp
Executable file
BIN
examples/ex4/.test.c.swp
Executable file
Binary file not shown.
22
examples/ex4/Makefile
Executable file
22
examples/ex4/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fsadc.o
|
||||
|
||||
endif
|
||||
|
||||
211
examples/ex4/fsadc.c
Executable file
211
examples/ex4/fsadc.c
Executable file
@ -0,0 +1,211 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "fsadc.h"
|
||||
|
||||
#define FSADC_MAJOR 256
|
||||
#define FSADC_MINOR 6
|
||||
#define FSADC_DEV_NAME "fsadc"
|
||||
|
||||
struct fsadc_dev {
|
||||
unsigned int __iomem *adccon;
|
||||
unsigned int __iomem *adcdat;
|
||||
unsigned int __iomem *clrint;
|
||||
unsigned int __iomem *adcmux;
|
||||
|
||||
unsigned int adcval;
|
||||
struct completion completion;
|
||||
atomic_t available;
|
||||
unsigned int irq;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static int fsadc_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsadc_dev *fsadc = container_of(inode->i_cdev, struct fsadc_dev, cdev);
|
||||
|
||||
filp->private_data = fsadc;
|
||||
if (atomic_dec_and_test(&fsadc->available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&fsadc->available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int fsadc_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsadc_dev *fsadc = filp->private_data;
|
||||
|
||||
atomic_inc(&fsadc->available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fsadc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct fsadc_dev *fsadc = filp->private_data;
|
||||
union chan_val cv;
|
||||
|
||||
if (_IOC_TYPE(cmd) != FSADC_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case FSADC_GET_VAL:
|
||||
if (copy_from_user(&cv, (union chan_val __user *)arg, sizeof(union chan_val)))
|
||||
return -EFAULT;
|
||||
if (cv.chan > AIN3)
|
||||
return -ENOTTY;
|
||||
writel(cv.chan, fsadc->adcmux);
|
||||
writel(readl(fsadc->adccon) | 1, fsadc->adccon);
|
||||
if (wait_for_completion_interruptible(&fsadc->completion))
|
||||
return -ERESTARTSYS;
|
||||
cv.val = fsadc->adcval & 0xFFF;
|
||||
if (copy_to_user( (union chan_val __user *)arg, &cv, sizeof(union chan_val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t fsadc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct fsadc_dev *fsadc = dev_id;
|
||||
|
||||
fsadc->adcval = readl(fsadc->adcdat);
|
||||
writel(1, fsadc->clrint);
|
||||
complete(&fsadc->completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct file_operations fsadc_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fsadc_open,
|
||||
.release = fsadc_release,
|
||||
.unlocked_ioctl = fsadc_ioctl,
|
||||
};
|
||||
|
||||
static int fsadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
struct fsadc_dev *fsadc;
|
||||
struct resource *res;
|
||||
|
||||
dev = MKDEV(FSADC_MAJOR, FSADC_MINOR);
|
||||
ret = register_chrdev_region(dev, 1, FSADC_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
fsadc = kzalloc(sizeof(struct fsadc_dev), GFP_KERNEL);
|
||||
if (!fsadc) {
|
||||
ret = -ENOMEM;
|
||||
goto mem_err;
|
||||
}
|
||||
platform_set_drvdata(pdev, fsadc);
|
||||
|
||||
cdev_init(&fsadc->cdev, &fsadc_ops);
|
||||
fsadc->cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&fsadc->cdev, dev, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
fsadc->adccon = ioremap(res->start, resource_size(res));
|
||||
if (!fsadc->adccon) {
|
||||
ret = -EBUSY;
|
||||
goto map_err;
|
||||
}
|
||||
fsadc->adcdat = fsadc->adccon + 3;
|
||||
fsadc->clrint = fsadc->adccon + 6;
|
||||
fsadc->adcmux = fsadc->adccon + 7;
|
||||
|
||||
fsadc->irq = platform_get_irq(pdev, 0);
|
||||
if (fsadc->irq < 0) {
|
||||
ret = fsadc->irq;
|
||||
goto irq_err;
|
||||
}
|
||||
|
||||
ret = request_irq(fsadc->irq, fsadc_isr, 0, "adc", fsadc);
|
||||
if (ret)
|
||||
goto irq_err;
|
||||
|
||||
writel((1 << 16) | (1 << 14) | (19 << 6), fsadc->adccon);
|
||||
|
||||
init_completion(&fsadc->completion);
|
||||
atomic_set(&fsadc->available, 1);
|
||||
|
||||
return 0;
|
||||
irq_err:
|
||||
iounmap(fsadc->adccon);
|
||||
map_err:
|
||||
res_err:
|
||||
cdev_del(&fsadc->cdev);
|
||||
add_err:
|
||||
kfree(fsadc);
|
||||
mem_err:
|
||||
unregister_chrdev_region(dev, 1);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsadc_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_t dev;
|
||||
struct fsadc_dev *fsadc = platform_get_drvdata(pdev);
|
||||
|
||||
dev = MKDEV(FSADC_MAJOR, FSADC_MINOR);
|
||||
|
||||
writel((readl(fsadc->adccon) & ~(1 << 16)) | (1 << 2), fsadc->adccon);
|
||||
free_irq(fsadc->irq, fsadc);
|
||||
iounmap(fsadc->adccon);
|
||||
cdev_del(&fsadc->cdev);
|
||||
kfree(fsadc);
|
||||
unregister_chrdev_region(dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fsadc_of_matches[] = {
|
||||
{ .compatible = "fs4412,fsadc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsadc_of_matches);
|
||||
|
||||
struct platform_driver fsadc_drv = {
|
||||
.driver = {
|
||||
.name = "fsadc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(fsadc_of_matches),
|
||||
},
|
||||
.probe = fsadc_probe,
|
||||
.remove = fsadc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fsadc_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("ADC driver");
|
||||
18
examples/ex4/fsadc.h
Executable file
18
examples/ex4/fsadc.h
Executable file
@ -0,0 +1,18 @@
|
||||
#ifndef _FSADC_H
|
||||
#define _FSADC_H
|
||||
|
||||
#define FSADC_MAGIC 'f'
|
||||
|
||||
union chan_val {
|
||||
unsigned int chan;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
#define FSADC_GET_VAL _IOWR(FSADC_MAGIC, 0, union chan_val)
|
||||
|
||||
#define AIN0 0
|
||||
#define AIN1 1
|
||||
#define AIN2 2
|
||||
#define AIN3 3
|
||||
|
||||
#endif
|
||||
33
examples/ex4/test.c
Executable file
33
examples/ex4/test.c
Executable file
@ -0,0 +1,33 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fsadc.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
union chan_val cv;
|
||||
|
||||
fd = open("/dev/adc", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
while (1) {
|
||||
cv.chan = 3;
|
||||
ret = ioctl(fd, FSADC_GET_VAL, &cv);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
printf("current volatage is: %.2fV\n", 1.8 * cv.val / 4095.0);
|
||||
sleep(1);
|
||||
}
|
||||
fail:
|
||||
perror("adc test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
22
examples/ex5/Makefile
Executable file
22
examples/ex5/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fspwm.o
|
||||
|
||||
endif
|
||||
|
||||
215
examples/ex5/fspwm.c
Executable file
215
examples/ex5/fspwm.c
Executable file
@ -0,0 +1,215 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include "fspwm.h"
|
||||
|
||||
#define FSPWM_MAJOR 256
|
||||
#define FSPWM_MINOR 7
|
||||
#define FSPWM_DEV_NAME "fspwm"
|
||||
|
||||
struct fspwm_dev {
|
||||
unsigned int __iomem *tcfg0;
|
||||
unsigned int __iomem *tcfg1;
|
||||
unsigned int __iomem *tcon;
|
||||
unsigned int __iomem *tcntb0;
|
||||
unsigned int __iomem *tcmpb0;
|
||||
unsigned int __iomem *tcnto0;
|
||||
struct clk *clk;
|
||||
unsigned long freq;
|
||||
struct pinctrl *pctrl;
|
||||
atomic_t available;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static int fspwm_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fspwm_dev *fspwm = container_of(inode->i_cdev, struct fspwm_dev, cdev);
|
||||
|
||||
filp->private_data = fspwm;
|
||||
if (atomic_dec_and_test(&fspwm->available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&fspwm->available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int fspwm_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fspwm_dev *fspwm = filp->private_data;
|
||||
|
||||
atomic_inc(&fspwm->available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fspwm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct fspwm_dev *fspwm = filp->private_data;
|
||||
unsigned int div;
|
||||
|
||||
if (_IOC_TYPE(cmd) != FSPWM_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case FSPWM_START:
|
||||
writel(readl(fspwm->tcon) | 0x1, fspwm->tcon);
|
||||
break;
|
||||
case FSPWM_STOP:
|
||||
writel(readl(fspwm->tcon) & ~0x1, fspwm->tcon);
|
||||
break;
|
||||
case FSPWM_SET_FREQ:
|
||||
if (arg > fspwm->freq || arg == 0)
|
||||
return -ENOTTY;
|
||||
div = fspwm->freq / arg - 1;
|
||||
writel(div, fspwm->tcntb0);
|
||||
writel(div / 2, fspwm->tcmpb0);
|
||||
writel(readl(fspwm->tcon) | 0x2, fspwm->tcon);
|
||||
writel(readl(fspwm->tcon) & ~0x2, fspwm->tcon);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations fspwm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fspwm_open,
|
||||
.release = fspwm_release,
|
||||
.unlocked_ioctl = fspwm_ioctl,
|
||||
};
|
||||
|
||||
static int fspwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
struct fspwm_dev *fspwm;
|
||||
struct resource *res;
|
||||
unsigned int prescaler0;
|
||||
|
||||
dev = MKDEV(FSPWM_MAJOR, FSPWM_MINOR);
|
||||
ret = register_chrdev_region(dev, 1, FSPWM_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
fspwm = kzalloc(sizeof(struct fspwm_dev), GFP_KERNEL);
|
||||
if (!fspwm) {
|
||||
ret = -ENOMEM;
|
||||
goto mem_err;
|
||||
}
|
||||
platform_set_drvdata(pdev, fspwm);
|
||||
|
||||
cdev_init(&fspwm->cdev, &fspwm_ops);
|
||||
fspwm->cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&fspwm->cdev, dev, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
fspwm->tcfg0 = ioremap(res->start, resource_size(res));
|
||||
if (!fspwm->tcfg0) {
|
||||
ret = -EBUSY;
|
||||
goto map_err;
|
||||
}
|
||||
fspwm->tcfg1 = fspwm->tcfg0 + 1;
|
||||
fspwm->tcon = fspwm->tcfg0 + 2;
|
||||
fspwm->tcntb0 = fspwm->tcfg0 + 3;
|
||||
fspwm->tcmpb0 = fspwm->tcfg0 + 4;
|
||||
fspwm->tcnto0 = fspwm->tcfg0 + 5;
|
||||
|
||||
fspwm->clk = clk_get(&pdev->dev, "timers");
|
||||
if (IS_ERR(fspwm->clk)) {
|
||||
ret = PTR_ERR(fspwm->clk);
|
||||
goto get_clk_err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(fspwm->clk);
|
||||
if (ret < 0)
|
||||
goto enable_clk_err;
|
||||
fspwm->freq = clk_get_rate(fspwm->clk);
|
||||
|
||||
prescaler0 = readl(fspwm->tcfg0) & 0xFF;
|
||||
writel((readl(fspwm->tcfg1) & ~0xF) | 0x4, fspwm->tcfg1); /* 1/16 */
|
||||
fspwm->freq /= (prescaler0 + 1) * 16; /* 3125000 */
|
||||
writel((readl(fspwm->tcon) & ~0xF) | 0x8, fspwm->tcon); /* auto-reload */
|
||||
|
||||
fspwm->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
|
||||
atomic_set(&fspwm->available, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
enable_clk_err:
|
||||
clk_put(fspwm->clk);
|
||||
get_clk_err:
|
||||
iounmap(fspwm->tcfg0);
|
||||
map_err:
|
||||
res_err:
|
||||
cdev_del(&fspwm->cdev);
|
||||
add_err:
|
||||
kfree(fspwm);
|
||||
mem_err:
|
||||
unregister_chrdev_region(dev, 1);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fspwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_t dev;
|
||||
struct fspwm_dev *fspwm = platform_get_drvdata(pdev);
|
||||
|
||||
dev = MKDEV(FSPWM_MAJOR, FSPWM_MINOR);
|
||||
|
||||
clk_disable_unprepare(fspwm->clk);
|
||||
clk_put(fspwm->clk);
|
||||
iounmap(fspwm->tcfg0);
|
||||
cdev_del(&fspwm->cdev);
|
||||
kfree(fspwm);
|
||||
unregister_chrdev_region(dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fspwm_of_matches[] = {
|
||||
{ .compatible = "fs4412,fspwm", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fspwm_of_matches);
|
||||
|
||||
struct platform_driver fspwm_drv = {
|
||||
.driver = {
|
||||
.name = "fspwm",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(fspwm_of_matches),
|
||||
},
|
||||
.probe = fspwm_probe,
|
||||
.remove = fspwm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fspwm_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("PWM driver");
|
||||
10
examples/ex5/fspwm.h
Executable file
10
examples/ex5/fspwm.h
Executable file
@ -0,0 +1,10 @@
|
||||
#ifndef _FSPWM_H
|
||||
#define _FSPWM_H
|
||||
|
||||
#define FSPWM_MAGIC 'f'
|
||||
|
||||
#define FSPWM_START _IO(FSPWM_MAGIC, 0)
|
||||
#define FSPWM_STOP _IO(FSPWM_MAGIC, 1)
|
||||
#define FSPWM_SET_FREQ _IOW(FSPWM_MAGIC, 2, unsigned int)
|
||||
|
||||
#endif
|
||||
36
examples/ex5/music.h
Executable file
36
examples/ex5/music.h
Executable file
@ -0,0 +1,36 @@
|
||||
#ifndef _MUSIC_H
|
||||
#define _MUSIC_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int pitch;
|
||||
int dimation;
|
||||
} note;
|
||||
|
||||
// 1 2 3 4 5 6 7
|
||||
// C D E F G A B
|
||||
// 261.6256 293.6648 329.6276 349.2282 391.9954 440 493.8833
|
||||
|
||||
// C调
|
||||
#define DO 262
|
||||
#define RE 294
|
||||
#define MI 330
|
||||
#define FA 349
|
||||
#define SOL 392
|
||||
#define LA 440
|
||||
#define SI 494
|
||||
|
||||
#define BEAT (60000000 / 120)
|
||||
|
||||
const note HappyNewYear[] = {
|
||||
{DO, BEAT/2}, {DO, BEAT/2}, {DO, BEAT}, {SOL/2, BEAT},
|
||||
{MI, BEAT/2}, {MI, BEAT/2}, {MI, BEAT}, {DO, BEAT},
|
||||
{DO, BEAT/2}, {MI, BEAT/2}, {SOL, BEAT}, {SOL, BEAT},
|
||||
{FA, BEAT/2}, {MI, BEAT/2}, {RE, BEAT}, {RE, BEAT},
|
||||
{RE, BEAT/2}, {MI, BEAT/2}, {FA, BEAT}, {FA, BEAT},
|
||||
{MI, BEAT/2}, {RE, BEAT/2}, {MI, BEAT}, {DO, BEAT},
|
||||
{DO, BEAT/2}, {MI, BEAT/2}, {RE, BEAT}, {SOL/2, BEAT},
|
||||
{SI/2, BEAT/2}, {RE, BEAT/2}, {DO, BEAT}, {DO, BEAT},
|
||||
};
|
||||
|
||||
#endif
|
||||
45
examples/ex5/test.c
Executable file
45
examples/ex5/test.c
Executable file
@ -0,0 +1,45 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fspwm.h"
|
||||
#include "music.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int fd;
|
||||
int ret;
|
||||
unsigned int freq;
|
||||
|
||||
fd = open("/dev/pwm", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
ret = ioctl(fd, FSPWM_START);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(HappyNewYear); i++) {
|
||||
ret = ioctl(fd, FSPWM_SET_FREQ, HappyNewYear[i].pitch);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
usleep(HappyNewYear[i].dimation);
|
||||
}
|
||||
|
||||
ret = ioctl(fd, FSPWM_STOP);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
fail:
|
||||
perror("pwm test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
22
examples/ex6/Makefile
Executable file
22
examples/ex6/Makefile
Executable file
@ -0,0 +1,22 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
KERNELDIR ?= /home/farsight/fs4412/linux-3.14.25-fs4412
|
||||
ROOTFS ?= /nfs/rootfs
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
|
||||
clean:
|
||||
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
|
||||
else
|
||||
|
||||
obj-m := fsrtc.o
|
||||
|
||||
endif
|
||||
|
||||
221
examples/ex6/fsrtc.c
Executable file
221
examples/ex6/fsrtc.c
Executable file
@ -0,0 +1,221 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#include "fsrtc.h"
|
||||
|
||||
#define FSRTC_MAJOR 256
|
||||
#define FSRTC_MINOR 8
|
||||
#define FSRTC_DEV_NAME "fsrtc"
|
||||
|
||||
struct fsrtc_dev {
|
||||
unsigned int __iomem *rtccon;
|
||||
unsigned int __iomem *bcdsec;
|
||||
unsigned int __iomem *bcdmin;
|
||||
unsigned int __iomem *bcdhour;
|
||||
unsigned int __iomem *bcdday;
|
||||
unsigned int __iomem *bcdmon;
|
||||
unsigned int __iomem *bcdyear;
|
||||
struct clk *clk;
|
||||
atomic_t available;
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static int fsrtc_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsrtc_dev *fsrtc = container_of(inode->i_cdev, struct fsrtc_dev, cdev);
|
||||
|
||||
filp->private_data = fsrtc;
|
||||
if (atomic_dec_and_test(&fsrtc->available))
|
||||
return 0;
|
||||
else {
|
||||
atomic_inc(&fsrtc->available);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
static int fsrtc_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct fsrtc_dev *fsrtc = filp->private_data;
|
||||
|
||||
atomic_inc(&fsrtc->available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fsrtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct fsrtc_dev *fsrtc = filp->private_data;
|
||||
struct rtc_time time;
|
||||
|
||||
if (_IOC_TYPE(cmd) != FSRTC_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case FSRTC_SET:
|
||||
if (copy_from_user(&time, (struct rtc_time __user *)arg, sizeof(struct rtc_time)))
|
||||
return -ENOTTY;
|
||||
writel(readl(fsrtc->rtccon) | 0x1, fsrtc->rtccon);
|
||||
|
||||
writel(bin2bcd(time.tm_sec ), fsrtc->bcdsec);
|
||||
writel(bin2bcd(time.tm_min ), fsrtc->bcdmin);
|
||||
writel(bin2bcd(time.tm_hour), fsrtc->bcdhour);
|
||||
writel(bin2bcd(time.tm_mday), fsrtc->bcdday);
|
||||
writel(bin2bcd(time.tm_mon ), fsrtc->bcdmon);
|
||||
writel(bin2bcd(time.tm_year - 2000), fsrtc->bcdyear);
|
||||
|
||||
writel(readl(fsrtc->rtccon) & ~0x1, fsrtc->rtccon);
|
||||
break;
|
||||
case FSRTC_GET:
|
||||
time.tm_sec = bcd2bin(readl(fsrtc->bcdsec));
|
||||
time.tm_min = bcd2bin(readl(fsrtc->bcdmin));
|
||||
time.tm_hour = bcd2bin(readl(fsrtc->bcdhour));
|
||||
time.tm_mday = bcd2bin(readl(fsrtc->bcdday));
|
||||
time.tm_mon = bcd2bin(readl(fsrtc->bcdmon));
|
||||
time.tm_year = bcd2bin(readl(fsrtc->bcdyear)) + 2000;
|
||||
|
||||
if (copy_to_user((struct rtc_time __user *)arg, &time, sizeof(struct rtc_time)))
|
||||
return -ENOTTY;
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations fsrtc_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fsrtc_open,
|
||||
.release = fsrtc_release,
|
||||
.unlocked_ioctl = fsrtc_ioctl,
|
||||
};
|
||||
|
||||
static int fsrtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev;
|
||||
struct fsrtc_dev *fsrtc;
|
||||
struct resource *res;
|
||||
unsigned int __iomem *regbase;
|
||||
|
||||
dev = MKDEV(FSRTC_MAJOR, FSRTC_MINOR);
|
||||
ret = register_chrdev_region(dev, 1, FSRTC_DEV_NAME);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
fsrtc = kzalloc(sizeof(struct fsrtc_dev), GFP_KERNEL);
|
||||
if (!fsrtc) {
|
||||
ret = -ENOMEM;
|
||||
goto mem_err;
|
||||
}
|
||||
platform_set_drvdata(pdev, fsrtc);
|
||||
|
||||
cdev_init(&fsrtc->cdev, &fsrtc_ops);
|
||||
fsrtc->cdev.owner = THIS_MODULE;
|
||||
ret = cdev_add(&fsrtc->cdev, dev, 1);
|
||||
if (ret)
|
||||
goto add_err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto res_err;
|
||||
}
|
||||
|
||||
regbase = ioremap(res->start, resource_size(res));
|
||||
if (!regbase) {
|
||||
ret = -EBUSY;
|
||||
goto map_err;
|
||||
}
|
||||
fsrtc->rtccon = regbase + 16;
|
||||
fsrtc->bcdsec = regbase + 28;
|
||||
fsrtc->bcdmin = regbase + 29;
|
||||
fsrtc->bcdhour = regbase + 30;
|
||||
fsrtc->bcdday = regbase + 31;
|
||||
fsrtc->bcdmon = regbase + 33;
|
||||
fsrtc->bcdyear = regbase + 34;
|
||||
|
||||
fsrtc->clk = clk_get(&pdev->dev, "rtc");
|
||||
if (IS_ERR(fsrtc->clk)) {
|
||||
ret = PTR_ERR(fsrtc->clk);
|
||||
goto get_clk_err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(fsrtc->clk);
|
||||
if (ret < 0)
|
||||
goto enable_clk_err;
|
||||
|
||||
writel(0, fsrtc->rtccon);
|
||||
|
||||
atomic_set(&fsrtc->available, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
enable_clk_err:
|
||||
clk_put(fsrtc->clk);
|
||||
get_clk_err:
|
||||
iounmap(fsrtc->rtccon - 16);
|
||||
map_err:
|
||||
res_err:
|
||||
cdev_del(&fsrtc->cdev);
|
||||
add_err:
|
||||
kfree(fsrtc);
|
||||
mem_err:
|
||||
unregister_chrdev_region(dev, 1);
|
||||
reg_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fsrtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_t dev;
|
||||
struct fsrtc_dev *fsrtc = platform_get_drvdata(pdev);
|
||||
|
||||
dev = MKDEV(FSRTC_MAJOR, FSRTC_MINOR);
|
||||
|
||||
clk_disable_unprepare(fsrtc->clk);
|
||||
clk_put(fsrtc->clk);
|
||||
iounmap(fsrtc->rtccon - 16);
|
||||
cdev_del(&fsrtc->cdev);
|
||||
kfree(fsrtc);
|
||||
unregister_chrdev_region(dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id fsrtc_of_matches[] = {
|
||||
{ .compatible = "fs4412,fsrtc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsrtc_of_matches);
|
||||
|
||||
struct platform_driver fsrtc_drv = {
|
||||
.driver = {
|
||||
.name = "fsrtc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(fsrtc_of_matches),
|
||||
},
|
||||
.probe = fsrtc_probe,
|
||||
.remove = fsrtc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(fsrtc_drv);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
||||
MODULE_DESCRIPTION("RTC driver");
|
||||
20
examples/ex6/fsrtc.h
Executable file
20
examples/ex6/fsrtc.h
Executable file
@ -0,0 +1,20 @@
|
||||
#ifndef _FSRTC_H
|
||||
#define _FSRTC_H
|
||||
|
||||
struct rtc_time {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
};
|
||||
|
||||
#define FSRTC_MAGIC 'f'
|
||||
|
||||
#define FSRTC_SET _IOW(FSRTC_MAGIC, 0, struct rtc_time)
|
||||
#define FSRTC_GET _IOR(FSRTC_MAGIC, 1, struct rtc_time)
|
||||
|
||||
#endif
|
||||
36
examples/ex6/music.h
Executable file
36
examples/ex6/music.h
Executable file
@ -0,0 +1,36 @@
|
||||
#ifndef _MUSIC_H
|
||||
#define _MUSIC_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int pitch;
|
||||
int dimation;
|
||||
} note;
|
||||
|
||||
// 1 2 3 4 5 6 7
|
||||
// C D E F G A B
|
||||
// 261.6256 293.6648 329.6276 349.2282 391.9954 440 493.8833
|
||||
|
||||
// C调
|
||||
#define DO 262
|
||||
#define RE 294
|
||||
#define MI 330
|
||||
#define FA 349
|
||||
#define SOL 392
|
||||
#define LA 440
|
||||
#define SI 494
|
||||
|
||||
#define BEAT (60000000 / 120)
|
||||
|
||||
const note HappyNewYear[] = {
|
||||
{DO, BEAT/2}, {DO, BEAT/2}, {DO, BEAT}, {SOL/2, BEAT},
|
||||
{MI, BEAT/2}, {MI, BEAT/2}, {MI, BEAT}, {DO, BEAT},
|
||||
{DO, BEAT/2}, {MI, BEAT/2}, {SOL, BEAT}, {SOL, BEAT},
|
||||
{FA, BEAT/2}, {MI, BEAT/2}, {RE, BEAT}, {RE, BEAT},
|
||||
{RE, BEAT/2}, {MI, BEAT/2}, {FA, BEAT}, {FA, BEAT},
|
||||
{MI, BEAT/2}, {RE, BEAT/2}, {MI, BEAT}, {DO, BEAT},
|
||||
{DO, BEAT/2}, {MI, BEAT/2}, {RE, BEAT}, {SOL/2, BEAT},
|
||||
{SI/2, BEAT/2}, {RE, BEAT/2}, {DO, BEAT}, {DO, BEAT},
|
||||
};
|
||||
|
||||
#endif
|
||||
47
examples/ex6/test.c
Executable file
47
examples/ex6/test.c
Executable file
@ -0,0 +1,47 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fsrtc.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
struct rtc_time time;
|
||||
|
||||
fd = open("/dev/rtc", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
time.tm_sec = 59;
|
||||
time.tm_min = 59;
|
||||
time.tm_hour = 23;
|
||||
time.tm_mday = 8;
|
||||
time.tm_mon = 8;
|
||||
time.tm_year = 2016;
|
||||
|
||||
ret = ioctl(fd, FSRTC_SET, &time);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
while (1) {
|
||||
ret = ioctl(fd, FSRTC_GET, &time);
|
||||
if (ret == -1)
|
||||
goto fail;
|
||||
|
||||
printf("%d-%d-%d %d:%d:%d\n", time.tm_year, time.tm_mon, time.tm_mday,\
|
||||
time.tm_hour, time.tm_min, time.tm_sec);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
fail:
|
||||
perror("adc test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
334
i2c/ex1/i2c-dev.h
Executable file
334
i2c/ex1/i2c-dev.h
Executable file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
i2c-dev.h - i2c-bus driver, char device interface
|
||||
|
||||
Copyright (C) 1995-97 Simon G. Vogl
|
||||
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* $Id: i2c-dev.h 5361 2008-10-19 09:47:02Z khali $ */
|
||||
|
||||
#ifndef LIB_I2CDEV_H
|
||||
#define LIB_I2CDEV_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
|
||||
/* -- i2c.h -- */
|
||||
|
||||
|
||||
/*
|
||||
* I2C Message - used for pure i2c transaction, also from /dev interface
|
||||
*/
|
||||
struct i2c_msg {
|
||||
__u16 addr; /* slave address */
|
||||
unsigned short flags;
|
||||
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
|
||||
#define I2C_M_RD 0x01
|
||||
#define I2C_M_NOSTART 0x4000
|
||||
#define I2C_M_REV_DIR_ADDR 0x2000
|
||||
#define I2C_M_IGNORE_NAK 0x1000
|
||||
#define I2C_M_NO_RD_ACK 0x0800
|
||||
short len; /* msg length */
|
||||
char *buf; /* pointer to msg data */
|
||||
};
|
||||
|
||||
/* To determine what functionality is present */
|
||||
|
||||
#define I2C_FUNC_I2C 0x00000001
|
||||
#define I2C_FUNC_10BIT_ADDR 0x00000002
|
||||
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
|
||||
#define I2C_FUNC_SMBUS_PEC 0x00000008
|
||||
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
|
||||
#define I2C_FUNC_SMBUS_QUICK 0x00010000
|
||||
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
|
||||
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
|
||||
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
|
||||
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
|
||||
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
|
||||
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
|
||||
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
|
||||
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
|
||||
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
|
||||
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
|
||||
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
|
||||
|
||||
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE)
|
||||
#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
|
||||
#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
|
||||
I2C_FUNC_SMBUS_WRITE_WORD_DATA)
|
||||
#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
|
||||
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
|
||||
#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
|
||||
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
|
||||
|
||||
/* Old name, for compatibility */
|
||||
#define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC
|
||||
|
||||
/*
|
||||
* Data for SMBus Messages
|
||||
*/
|
||||
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
|
||||
#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */
|
||||
union i2c_smbus_data {
|
||||
__u8 byte;
|
||||
__u16 word;
|
||||
__u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
|
||||
/* and one more for PEC */
|
||||
};
|
||||
|
||||
/* smbus_access read or write markers */
|
||||
#define I2C_SMBUS_READ 1
|
||||
#define I2C_SMBUS_WRITE 0
|
||||
|
||||
/* SMBus transaction types (size parameter in the above functions)
|
||||
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
|
||||
#define I2C_SMBUS_QUICK 0
|
||||
#define I2C_SMBUS_BYTE 1
|
||||
#define I2C_SMBUS_BYTE_DATA 2
|
||||
#define I2C_SMBUS_WORD_DATA 3
|
||||
#define I2C_SMBUS_PROC_CALL 4
|
||||
#define I2C_SMBUS_BLOCK_DATA 5
|
||||
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
|
||||
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
|
||||
#define I2C_SMBUS_I2C_BLOCK_DATA 8
|
||||
|
||||
|
||||
/* ----- commands for the ioctl like i2c_command call:
|
||||
* note that additional calls are defined in the algorithm and hw
|
||||
* dependent layers - these can be listed here, or see the
|
||||
* corresponding header files.
|
||||
*/
|
||||
/* -> bit-adapter specific ioctls */
|
||||
#define I2C_RETRIES 0x0701 /* number of times a device address */
|
||||
/* should be polled when not */
|
||||
/* acknowledging */
|
||||
#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
|
||||
|
||||
|
||||
/* this is for i2c-dev.c */
|
||||
#define I2C_SLAVE 0x0703 /* Change slave address */
|
||||
/* Attn.: Slave address is 7 or 10 bits */
|
||||
#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */
|
||||
/* Attn.: Slave address is 7 or 10 bits */
|
||||
/* This changes the address, even if it */
|
||||
/* is already taken! */
|
||||
#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
|
||||
|
||||
#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
|
||||
#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
|
||||
#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
|
||||
|
||||
#define I2C_SMBUS 0x0720 /* SMBus-level access */
|
||||
|
||||
/* -- i2c.h -- */
|
||||
|
||||
|
||||
/* Note: 10-bit addresses are NOT supported! */
|
||||
|
||||
/* This is the structure as used in the I2C_SMBUS ioctl call */
|
||||
struct i2c_smbus_ioctl_data {
|
||||
char read_write;
|
||||
__u8 command;
|
||||
int size;
|
||||
union i2c_smbus_data *data;
|
||||
};
|
||||
|
||||
/* This is the structure as used in the I2C_RDWR ioctl call */
|
||||
struct i2c_rdwr_ioctl_data {
|
||||
struct i2c_msg *msgs; /* pointers to i2c_msgs */
|
||||
int nmsgs; /* number of i2c_msgs */
|
||||
};
|
||||
|
||||
|
||||
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_smbus_ioctl_data args;
|
||||
|
||||
args.read_write = read_write;
|
||||
args.command = command;
|
||||
args.size = size;
|
||||
args.data = data;
|
||||
return ioctl(file,I2C_SMBUS,&args);
|
||||
}
|
||||
|
||||
|
||||
static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
|
||||
{
|
||||
return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_read_byte(int file)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FF & data.byte;
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
|
||||
{
|
||||
return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
|
||||
I2C_SMBUS_BYTE,NULL);
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
|
||||
I2C_SMBUS_BYTE_DATA,&data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FF & data.byte;
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
|
||||
__u8 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.byte = value;
|
||||
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
|
||||
I2C_SMBUS_BYTE_DATA, &data);
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
|
||||
I2C_SMBUS_WORD_DATA,&data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FFFF & data.word;
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
|
||||
__u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.word = value;
|
||||
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
|
||||
I2C_SMBUS_WORD_DATA, &data);
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
data.word = value;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
|
||||
I2C_SMBUS_PROC_CALL,&data))
|
||||
return -1;
|
||||
else
|
||||
return 0x0FFFF & data.word;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
static inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
|
||||
__u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
|
||||
I2C_SMBUS_BLOCK_DATA,&data))
|
||||
return -1;
|
||||
else {
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
|
||||
__u8 length, __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > 32)
|
||||
length = 32;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
|
||||
I2C_SMBUS_BLOCK_DATA, &data);
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
|
||||
ask for less than 32 bytes, your code will only work with kernels
|
||||
2.6.23 and later. */
|
||||
static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
|
||||
__u8 length, __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
|
||||
if (length > 32)
|
||||
length = 32;
|
||||
data.block[0] = length;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
|
||||
length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
|
||||
I2C_SMBUS_I2C_BLOCK_DATA,&data))
|
||||
return -1;
|
||||
else {
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
|
||||
__u8 length, __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > 32)
|
||||
length = 32;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
|
||||
I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
|
||||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
|
||||
__u8 length, __u8 *values)
|
||||
{
|
||||
union i2c_smbus_data data;
|
||||
int i;
|
||||
if (length > 32)
|
||||
length = 32;
|
||||
for (i = 1; i <= length; i++)
|
||||
data.block[i] = values[i-1];
|
||||
data.block[0] = length;
|
||||
if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
|
||||
I2C_SMBUS_BLOCK_PROC_CALL,&data))
|
||||
return -1;
|
||||
else {
|
||||
for (i = 1; i <= data.block[0]; i++)
|
||||
values[i-1] = data.block[i];
|
||||
return data.block[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* LIB_I2CDEV_H */
|
||||
95
i2c/ex1/test.c
Executable file
95
i2c/ex1/test.c
Executable file
@ -0,0 +1,95 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "i2c-dev.h"
|
||||
|
||||
#define SMPLRT_DIV 0x19
|
||||
#define CONFIG 0x1A
|
||||
#define GYRO_CONFIG 0x1B
|
||||
#define ACCEL_CONFIG 0x1C
|
||||
#define ACCEL_XOUT_H 0x3B
|
||||
#define ACCEL_XOUT_L 0x3C
|
||||
#define ACCEL_YOUT_H 0x3D
|
||||
#define ACCEL_YOUT_L 0x3E
|
||||
#define ACCEL_ZOUT_H 0x3F
|
||||
#define ACCEL_ZOUT_L 0x40
|
||||
#define TEMP_OUT_H 0x41
|
||||
#define TEMP_OUT_L 0x42
|
||||
#define GYRO_XOUT_H 0x43
|
||||
#define GYRO_XOUT_L 0x44
|
||||
#define GYRO_YOUT_H 0x45
|
||||
#define GYRO_YOUT_L 0x46
|
||||
#define GYRO_ZOUT_H 0x47
|
||||
#define GYRO_ZOUT_L 0x48
|
||||
#define PWR_MGMT_1 0x6B
|
||||
|
||||
void swap_int16(short *val)
|
||||
{
|
||||
*val = (*val << 8) | (*val >> 8);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
short accelx, accely, accelz;
|
||||
short temp;
|
||||
short gyrox, gyroy, gyroz;
|
||||
unsigned char *p;
|
||||
|
||||
fd = open("/dev/i2c-5", O_RDWR);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
if (ioctl(fd, I2C_SLAVE, 0x68) < 0)
|
||||
goto fail;
|
||||
|
||||
i2c_smbus_write_byte_data(fd, PWR_MGMT_1, 0x80);
|
||||
usleep(200000);
|
||||
i2c_smbus_write_byte_data(fd, PWR_MGMT_1, 0x40);
|
||||
i2c_smbus_write_byte_data(fd, PWR_MGMT_1, 0x00);
|
||||
|
||||
i2c_smbus_write_byte_data(fd, SMPLRT_DIV, 0x7);
|
||||
i2c_smbus_write_byte_data(fd, CONFIG, 0x6);
|
||||
i2c_smbus_write_byte_data(fd, GYRO_CONFIG, 0x3 << 3);
|
||||
i2c_smbus_write_byte_data(fd, ACCEL_CONFIG, 0x3 << 3);
|
||||
|
||||
while (1) {
|
||||
accelx = i2c_smbus_read_word_data(fd, ACCEL_XOUT_H);
|
||||
swap_int16(&accelx);
|
||||
accely = i2c_smbus_read_byte_data(fd, ACCEL_YOUT_H);
|
||||
swap_int16(&accely);
|
||||
accelz = i2c_smbus_read_byte_data(fd, ACCEL_ZOUT_H);
|
||||
swap_int16(&accelz);
|
||||
|
||||
printf("accelx: %.2f\n", accelx / 2048.0);
|
||||
printf("accely: %.2f\n", accely / 2048.0);
|
||||
printf("accelz: %.2f\n", accelz / 2048.0);
|
||||
|
||||
temp = i2c_smbus_read_word_data(fd, TEMP_OUT_H);
|
||||
swap_int16(&temp);
|
||||
printf("temp: %.2f\n", temp / 340.0 + 36.53);
|
||||
|
||||
gyrox = i2c_smbus_read_word_data(fd, GYRO_XOUT_H);
|
||||
swap_int16(&gyrox);
|
||||
gyroy = i2c_smbus_read_byte_data(fd, GYRO_YOUT_H);
|
||||
swap_int16(&gyroy);
|
||||
gyroz = i2c_smbus_read_byte_data(fd, GYRO_ZOUT_H);
|
||||
swap_int16(&gyroz);
|
||||
|
||||
printf("gyrox: %.2f\n", gyrox / 16.4);
|
||||
printf("gyroy: %.2f\n", gyroy / 16.4);
|
||||
printf("gyroz: %.2f\n", gyroz / 16.4);
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
fail:
|
||||
perror("i2c test");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user