From 3f3b436a9f97527226f2f903d6329861d3361a29 Mon Sep 17 00:00:00 2001 From: gaoyang3513 Date: Sun, 24 Dec 2023 10:29:22 +0000 Subject: [PATCH] =?UTF-8?q?[=E6=96=B0=E5=A2=9E]=20=E5=8D=8E=E6=B8=85=20?= =?UTF-8?q?=E6=BA=90=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- advio/ex1/Makefile | 22 +++ advio/ex1/test.c | 51 ++++++ advio/ex1/vser.c | 140 ++++++++++++++++ advio/ex1/vser.h | 17 ++ advio/ex10/Makefile | 22 +++ advio/ex10/test.c | 43 +++++ advio/ex10/vfb.c | 139 ++++++++++++++++ advio/ex2/Makefile | 22 +++ advio/ex2/vser.c | 181 +++++++++++++++++++++ advio/ex2/vser.h | 17 ++ advio/ex3/Makefile | 22 +++ advio/ex3/test.c | 44 ++++++ advio/ex3/vser.c | 148 +++++++++++++++++ advio/ex3/vser.h | 17 ++ advio/ex4/Makefile | 22 +++ advio/ex4/vser.c | 171 ++++++++++++++++++++ advio/ex4/vser.h | 17 ++ advio/ex5/Makefile | 22 +++ advio/ex5/test.c | 34 ++++ advio/ex5/vser.c | 171 ++++++++++++++++++++ advio/ex5/vser.h | 17 ++ advio/ex6/Makefile | 22 +++ advio/ex6/test.c | 63 ++++++++ advio/ex6/vser.c | 188 ++++++++++++++++++++++ advio/ex6/vser.h | 17 ++ advio/ex7/Makefile | 22 +++ advio/ex7/test.c | 89 +++++++++++ advio/ex7/vser.c | 223 ++++++++++++++++++++++++++ advio/ex7/vser.h | 17 ++ advio/ex8/Makefile | 22 +++ advio/ex8/test.c | 67 ++++++++ advio/ex8/vser.c | 237 +++++++++++++++++++++++++++ advio/ex8/vser.h | 17 ++ advio/ex9/Makefile | 22 +++ advio/ex9/test.c | 39 +++++ advio/ex9/vfb.c | 108 +++++++++++++ block/ex1/Makefile | 22 +++ block/ex1/vdsk.c | 161 +++++++++++++++++++ block/ex2/Makefile | 22 +++ block/ex2/vdsk.c | 162 +++++++++++++++++++ chrdev/ex1/Makefile | 22 +++ chrdev/ex1/vser.c | 42 +++++ chrdev/ex2/Makefile | 22 +++ chrdev/ex2/vser.c | 61 +++++++ chrdev/ex3/Makefile | 22 +++ chrdev/ex3/vser.c | 95 +++++++++++ chrdev/ex4/Makefile | 22 +++ chrdev/ex4/vser.c | 107 +++++++++++++ chrdev/ex5/vser.c | 112 +++++++++++++ concurrence/ex1/Makefile | 22 +++ concurrence/ex1/vser.c | 277 ++++++++++++++++++++++++++++++++ concurrence/ex1/vser.h | 17 ++ devmodel/ex1/Makefile | 22 +++ devmodel/ex1/model.c | 66 ++++++++ devmodel/ex2/Makefile | 21 +++ devmodel/ex2/vbus.c | 34 ++++ devmodel/ex2/vdev.c | 34 ++++ devmodel/ex2/vdrv.c | 29 ++++ devmodel/ex3/Makefile | 21 +++ devmodel/ex3/pltdev.c | 50 ++++++ devmodel/ex3/pltdrv.c | 49 ++++++ devmodel/ex4/Makefile | 23 +++ devmodel/ex4/fsdev.c | 101 ++++++++++++ devmodel/ex4/fsled.c | 165 +++++++++++++++++++ devmodel/ex4/fsled.h | 9 ++ devmodel/ex4/test.c | 46 ++++++ devmodel/ex5/Makefile | 23 +++ devmodel/ex5/fsdev.c | 101 ++++++++++++ devmodel/ex5/fsled.c | 199 +++++++++++++++++++++++ devmodel/ex5/fsled.h | 9 ++ devmodel/ex5/test.c | 46 ++++++ devmodel/ex6/Makefile | 22 +++ devmodel/ex6/fsled.c | 183 +++++++++++++++++++++ devmodel/ex6/fsled.h | 9 ++ devmodel/ex6/test.c | 46 ++++++ dma/ex1/Makefile | 22 +++ dma/ex1/memcpy.c | 96 +++++++++++ examples/ex1/test.c | 61 +++++++ examples/ex2/Makefile | 22 +++ examples/ex2/fskey.c | 85 ++++++++++ examples/ex3/Makefile | 22 +++ examples/ex3/fskey.c | 168 ++++++++++++++++++++ examples/ex3/test.c | 46 ++++++ examples/ex4/.test.c.swp | Bin 0 -> 12288 bytes examples/ex4/Makefile | 22 +++ examples/ex4/fsadc.c | 211 +++++++++++++++++++++++++ examples/ex4/fsadc.h | 18 +++ examples/ex4/test.c | 33 ++++ examples/ex5/Makefile | 22 +++ examples/ex5/fspwm.c | 215 +++++++++++++++++++++++++ examples/ex5/fspwm.h | 10 ++ examples/ex5/music.h | 36 +++++ examples/ex5/test.c | 45 ++++++ examples/ex6/Makefile | 22 +++ examples/ex6/fsrtc.c | 221 ++++++++++++++++++++++++++ examples/ex6/fsrtc.h | 20 +++ examples/ex6/music.h | 36 +++++ examples/ex6/test.c | 47 ++++++ i2c/ex1/i2c-dev.h | 334 +++++++++++++++++++++++++++++++++++++++ i2c/ex1/test.c | 95 +++++++++++ i2c/ex2/Makefile | 22 +++ i2c/ex2/mpu6050.c | 199 +++++++++++++++++++++++ i2c/ex2/mpu6050.h | 18 +++ i2c/ex2/test.c | 32 ++++ intdev/ex1/Makefile | 22 +++ intdev/ex1/vser.c | 265 +++++++++++++++++++++++++++++++ intdev/ex1/vser.h | 17 ++ intdev/ex2/Makefile | 22 +++ intdev/ex2/vser.c | 273 ++++++++++++++++++++++++++++++++ intdev/ex2/vser.h | 17 ++ intdev/ex3/Makefile | 22 +++ intdev/ex3/vser.c | 273 ++++++++++++++++++++++++++++++++ intdev/ex3/vser.h | 17 ++ memory/ex1/Makefile | 22 +++ memory/ex1/vser.c | 294 ++++++++++++++++++++++++++++++++++ memory/ex1/vser.h | 17 ++ memory/ex2/Makefile | 22 +++ memory/ex2/fsled.c | 187 ++++++++++++++++++++++ memory/ex2/fsled.h | 14 ++ memory/ex2/test.c | 37 +++++ module/ex1/Makefile | 22 +++ module/ex1/vser.c | 14 ++ module/ex2/Makefile | 22 +++ module/ex2/vser.c | 22 +++ module/ex3/Makefile | 23 +++ module/ex3/bar.c | 6 + module/ex3/foo.c | 25 +++ module/ex4/Makefile | 22 +++ module/ex4/vser.c | 39 +++++ module/ex5/Makefile | 23 +++ module/ex5/dep.c | 15 ++ module/ex5/vser.c | 28 ++++ net/ex1/Makefile | 22 +++ net/ex1/vnet.c | 178 +++++++++++++++++++++ net/ex1/vnet.h | 12 ++ pci/ex1/Makefile | 22 +++ pci/ex1/ch368.c | 242 ++++++++++++++++++++++++++++ pci/ex1/ch368.h | 16 ++ pci/ex1/test.c | 45 ++++++ timer/ex1/Makefile | 22 +++ timer/ex1/vser.c | 267 +++++++++++++++++++++++++++++++ timer/ex1/vser.h | 17 ++ timer/ex2/Makefile | 22 +++ timer/ex2/vser.c | 267 +++++++++++++++++++++++++++++++ timer/ex2/vser.h | 17 ++ usb/ex1/Makefile | 22 +++ usb/ex1/pdiusbd12.c | 297 ++++++++++++++++++++++++++++++++++ usb/ex1/pdiusbd12.h | 17 ++ usb/ex1/test.c | 72 +++++++++ 149 files changed, 10507 insertions(+) create mode 100755 advio/ex1/Makefile create mode 100755 advio/ex1/test.c create mode 100755 advio/ex1/vser.c create mode 100755 advio/ex1/vser.h create mode 100755 advio/ex10/Makefile create mode 100755 advio/ex10/test.c create mode 100755 advio/ex10/vfb.c create mode 100755 advio/ex2/Makefile create mode 100755 advio/ex2/vser.c create mode 100755 advio/ex2/vser.h create mode 100755 advio/ex3/Makefile create mode 100755 advio/ex3/test.c create mode 100755 advio/ex3/vser.c create mode 100755 advio/ex3/vser.h create mode 100755 advio/ex4/Makefile create mode 100755 advio/ex4/vser.c create mode 100755 advio/ex4/vser.h create mode 100755 advio/ex5/Makefile create mode 100755 advio/ex5/test.c create mode 100755 advio/ex5/vser.c create mode 100755 advio/ex5/vser.h create mode 100755 advio/ex6/Makefile create mode 100755 advio/ex6/test.c create mode 100755 advio/ex6/vser.c create mode 100755 advio/ex6/vser.h create mode 100755 advio/ex7/Makefile create mode 100755 advio/ex7/test.c create mode 100755 advio/ex7/vser.c create mode 100755 advio/ex7/vser.h create mode 100755 advio/ex8/Makefile create mode 100755 advio/ex8/test.c create mode 100755 advio/ex8/vser.c create mode 100755 advio/ex8/vser.h create mode 100755 advio/ex9/Makefile create mode 100755 advio/ex9/test.c create mode 100755 advio/ex9/vfb.c create mode 100755 block/ex1/Makefile create mode 100755 block/ex1/vdsk.c create mode 100755 block/ex2/Makefile create mode 100755 block/ex2/vdsk.c create mode 100755 chrdev/ex1/Makefile create mode 100755 chrdev/ex1/vser.c create mode 100755 chrdev/ex2/Makefile create mode 100755 chrdev/ex2/vser.c create mode 100755 chrdev/ex3/Makefile create mode 100755 chrdev/ex3/vser.c create mode 100755 chrdev/ex4/Makefile create mode 100755 chrdev/ex4/vser.c create mode 100755 chrdev/ex5/vser.c create mode 100755 concurrence/ex1/Makefile create mode 100755 concurrence/ex1/vser.c create mode 100755 concurrence/ex1/vser.h create mode 100755 devmodel/ex1/Makefile create mode 100755 devmodel/ex1/model.c create mode 100755 devmodel/ex2/Makefile create mode 100755 devmodel/ex2/vbus.c create mode 100755 devmodel/ex2/vdev.c create mode 100755 devmodel/ex2/vdrv.c create mode 100755 devmodel/ex3/Makefile create mode 100755 devmodel/ex3/pltdev.c create mode 100755 devmodel/ex3/pltdrv.c create mode 100755 devmodel/ex4/Makefile create mode 100755 devmodel/ex4/fsdev.c create mode 100755 devmodel/ex4/fsled.c create mode 100755 devmodel/ex4/fsled.h create mode 100755 devmodel/ex4/test.c create mode 100755 devmodel/ex5/Makefile create mode 100755 devmodel/ex5/fsdev.c create mode 100755 devmodel/ex5/fsled.c create mode 100755 devmodel/ex5/fsled.h create mode 100755 devmodel/ex5/test.c create mode 100755 devmodel/ex6/Makefile create mode 100755 devmodel/ex6/fsled.c create mode 100755 devmodel/ex6/fsled.h create mode 100755 devmodel/ex6/test.c create mode 100755 dma/ex1/Makefile create mode 100755 dma/ex1/memcpy.c create mode 100755 examples/ex1/test.c create mode 100755 examples/ex2/Makefile create mode 100755 examples/ex2/fskey.c create mode 100755 examples/ex3/Makefile create mode 100755 examples/ex3/fskey.c create mode 100755 examples/ex3/test.c create mode 100755 examples/ex4/.test.c.swp create mode 100755 examples/ex4/Makefile create mode 100755 examples/ex4/fsadc.c create mode 100755 examples/ex4/fsadc.h create mode 100755 examples/ex4/test.c create mode 100755 examples/ex5/Makefile create mode 100755 examples/ex5/fspwm.c create mode 100755 examples/ex5/fspwm.h create mode 100755 examples/ex5/music.h create mode 100755 examples/ex5/test.c create mode 100755 examples/ex6/Makefile create mode 100755 examples/ex6/fsrtc.c create mode 100755 examples/ex6/fsrtc.h create mode 100755 examples/ex6/music.h create mode 100755 examples/ex6/test.c create mode 100755 i2c/ex1/i2c-dev.h create mode 100755 i2c/ex1/test.c create mode 100755 i2c/ex2/Makefile create mode 100755 i2c/ex2/mpu6050.c create mode 100755 i2c/ex2/mpu6050.h create mode 100755 i2c/ex2/test.c create mode 100755 intdev/ex1/Makefile create mode 100755 intdev/ex1/vser.c create mode 100755 intdev/ex1/vser.h create mode 100755 intdev/ex2/Makefile create mode 100755 intdev/ex2/vser.c create mode 100755 intdev/ex2/vser.h create mode 100755 intdev/ex3/Makefile create mode 100755 intdev/ex3/vser.c create mode 100755 intdev/ex3/vser.h create mode 100755 memory/ex1/Makefile create mode 100755 memory/ex1/vser.c create mode 100755 memory/ex1/vser.h create mode 100755 memory/ex2/Makefile create mode 100755 memory/ex2/fsled.c create mode 100755 memory/ex2/fsled.h create mode 100755 memory/ex2/test.c create mode 100755 module/ex1/Makefile create mode 100755 module/ex1/vser.c create mode 100755 module/ex2/Makefile create mode 100755 module/ex2/vser.c create mode 100755 module/ex3/Makefile create mode 100755 module/ex3/bar.c create mode 100755 module/ex3/foo.c create mode 100755 module/ex4/Makefile create mode 100755 module/ex4/vser.c create mode 100755 module/ex5/Makefile create mode 100755 module/ex5/dep.c create mode 100755 module/ex5/vser.c create mode 100755 net/ex1/Makefile create mode 100755 net/ex1/vnet.c create mode 100755 net/ex1/vnet.h create mode 100755 pci/ex1/Makefile create mode 100755 pci/ex1/ch368.c create mode 100755 pci/ex1/ch368.h create mode 100755 pci/ex1/test.c create mode 100755 timer/ex1/Makefile create mode 100755 timer/ex1/vser.c create mode 100755 timer/ex1/vser.h create mode 100755 timer/ex2/Makefile create mode 100755 timer/ex2/vser.c create mode 100755 timer/ex2/vser.h create mode 100755 usb/ex1/Makefile create mode 100755 usb/ex1/pdiusbd12.c create mode 100755 usb/ex1/pdiusbd12.h create mode 100755 usb/ex1/test.c diff --git a/advio/ex1/Makefile b/advio/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex1/Makefile @@ -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 + diff --git a/advio/ex1/test.c b/advio/ex1/test.c new file mode 100755 index 000000000..73e83a60c --- /dev/null +++ b/advio/ex1/test.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/advio/ex1/vser.c b/advio/ex1/vser.c new file mode 100755 index 000000000..04031a150 --- /dev/null +++ b/advio/ex1/vser.c @@ -0,0 +1,140 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex1/vser.h b/advio/ex1/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex1/vser.h @@ -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 diff --git a/advio/ex10/Makefile b/advio/ex10/Makefile new file mode 100755 index 000000000..c44440fa7 --- /dev/null +++ b/advio/ex10/Makefile @@ -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 + diff --git a/advio/ex10/test.c b/advio/ex10/test.c new file mode 100755 index 000000000..76e3568d5 --- /dev/null +++ b/advio/ex10/test.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +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); +} + diff --git a/advio/ex10/vfb.c b/advio/ex10/vfb.c new file mode 100755 index 000000000..0885ae18a --- /dev/null +++ b/advio/ex10/vfb.c @@ -0,0 +1,139 @@ +#include +#include +#include + +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("This is an example for mmap"); diff --git a/advio/ex2/Makefile b/advio/ex2/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex2/Makefile @@ -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 + diff --git a/advio/ex2/vser.c b/advio/ex2/vser.c new file mode 100755 index 000000000..2b7dc30dc --- /dev/null +++ b/advio/ex2/vser.c @@ -0,0 +1,181 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex2/vser.h b/advio/ex2/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex2/vser.h @@ -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 diff --git a/advio/ex3/Makefile b/advio/ex3/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex3/Makefile @@ -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 + diff --git a/advio/ex3/test.c b/advio/ex3/test.c new file mode 100755 index 000000000..6c7705e9f --- /dev/null +++ b/advio/ex3/test.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/advio/ex3/vser.c b/advio/ex3/vser.c new file mode 100755 index 000000000..be4c7d09b --- /dev/null +++ b/advio/ex3/vser.c @@ -0,0 +1,148 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex3/vser.h b/advio/ex3/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex3/vser.h @@ -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 diff --git a/advio/ex4/Makefile b/advio/ex4/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex4/Makefile @@ -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 + diff --git a/advio/ex4/vser.c b/advio/ex4/vser.c new file mode 100755 index 000000000..e5a61e973 --- /dev/null +++ b/advio/ex4/vser.c @@ -0,0 +1,171 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex4/vser.h b/advio/ex4/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex4/vser.h @@ -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 diff --git a/advio/ex5/Makefile b/advio/ex5/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex5/Makefile @@ -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 + diff --git a/advio/ex5/test.c b/advio/ex5/test.c new file mode 100755 index 000000000..6aa40f6e8 --- /dev/null +++ b/advio/ex5/test.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/advio/ex5/vser.c b/advio/ex5/vser.c new file mode 100755 index 000000000..56a69ec8c --- /dev/null +++ b/advio/ex5/vser.c @@ -0,0 +1,171 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex5/vser.h b/advio/ex5/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex5/vser.h @@ -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 diff --git a/advio/ex6/Makefile b/advio/ex6/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex6/Makefile @@ -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 + diff --git a/advio/ex6/test.c b/advio/ex6/test.c new file mode 100755 index 000000000..be3956c55 --- /dev/null +++ b/advio/ex6/test.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/advio/ex6/vser.c b/advio/ex6/vser.c new file mode 100755 index 000000000..89e04df86 --- /dev/null +++ b/advio/ex6/vser.c @@ -0,0 +1,188 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex6/vser.h b/advio/ex6/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex6/vser.h @@ -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 diff --git a/advio/ex7/Makefile b/advio/ex7/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex7/Makefile @@ -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 + diff --git a/advio/ex7/test.c b/advio/ex7/test.c new file mode 100755 index 000000000..cab01cf51 --- /dev/null +++ b/advio/ex7/test.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/advio/ex7/vser.c b/advio/ex7/vser.c new file mode 100755 index 000000000..48ca95903 --- /dev/null +++ b/advio/ex7/vser.c @@ -0,0 +1,223 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex7/vser.h b/advio/ex7/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex7/vser.h @@ -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 diff --git a/advio/ex8/Makefile b/advio/ex8/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/advio/ex8/Makefile @@ -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 + diff --git a/advio/ex8/test.c b/advio/ex8/test.c new file mode 100755 index 000000000..6bc011437 --- /dev/null +++ b/advio/ex8/test.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/advio/ex8/vser.c b/advio/ex8/vser.c new file mode 100755 index 000000000..b0d45aa3d --- /dev/null +++ b/advio/ex8/vser.c @@ -0,0 +1,237 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/advio/ex8/vser.h b/advio/ex8/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/advio/ex8/vser.h @@ -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 diff --git a/advio/ex9/Makefile b/advio/ex9/Makefile new file mode 100755 index 000000000..c44440fa7 --- /dev/null +++ b/advio/ex9/Makefile @@ -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 + diff --git a/advio/ex9/test.c b/advio/ex9/test.c new file mode 100755 index 000000000..6504e7f4a --- /dev/null +++ b/advio/ex9/test.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +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); +} + diff --git a/advio/ex9/vfb.c b/advio/ex9/vfb.c new file mode 100755 index 000000000..01df8d215 --- /dev/null +++ b/advio/ex9/vfb.c @@ -0,0 +1,108 @@ +#include +#include +#include + +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("This is an example for mmap"); diff --git a/block/ex1/Makefile b/block/ex1/Makefile new file mode 100755 index 000000000..44cd5bc23 --- /dev/null +++ b/block/ex1/Makefile @@ -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 + diff --git a/block/ex1/vdsk.c b/block/ex1/vdsk.c new file mode 100755 index 000000000..c77f6c548 --- /dev/null +++ b/block/ex1/vdsk.c @@ -0,0 +1,161 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("This is an example for Linux block device driver"); diff --git a/block/ex2/Makefile b/block/ex2/Makefile new file mode 100755 index 000000000..44cd5bc23 --- /dev/null +++ b/block/ex2/Makefile @@ -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 + diff --git a/block/ex2/vdsk.c b/block/ex2/vdsk.c new file mode 100755 index 000000000..23bd0be03 --- /dev/null +++ b/block/ex2/vdsk.c @@ -0,0 +1,162 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#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 "); +MODULE_DESCRIPTION("This is an example for Linux block device driver"); diff --git a/chrdev/ex1/Makefile b/chrdev/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/chrdev/ex1/Makefile @@ -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 + diff --git a/chrdev/ex1/vser.c b/chrdev/ex1/vser.c new file mode 100755 index 000000000..476b070c4 --- /dev/null +++ b/chrdev/ex1/vser.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/chrdev/ex2/Makefile b/chrdev/ex2/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/chrdev/ex2/Makefile @@ -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 + diff --git a/chrdev/ex2/vser.c b/chrdev/ex2/vser.c new file mode 100755 index 000000000..080ac749b --- /dev/null +++ b/chrdev/ex2/vser.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/chrdev/ex3/Makefile b/chrdev/ex3/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/chrdev/ex3/Makefile @@ -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 + diff --git a/chrdev/ex3/vser.c b/chrdev/ex3/vser.c new file mode 100755 index 000000000..631a76535 --- /dev/null +++ b/chrdev/ex3/vser.c @@ -0,0 +1,95 @@ +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/chrdev/ex4/Makefile b/chrdev/ex4/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/chrdev/ex4/Makefile @@ -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 + diff --git a/chrdev/ex4/vser.c b/chrdev/ex4/vser.c new file mode 100755 index 000000000..a4a96d95c --- /dev/null +++ b/chrdev/ex4/vser.c @@ -0,0 +1,107 @@ +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/chrdev/ex5/vser.c b/chrdev/ex5/vser.c new file mode 100755 index 000000000..459bb5672 --- /dev/null +++ b/chrdev/ex5/vser.c @@ -0,0 +1,112 @@ +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/concurrence/ex1/Makefile b/concurrence/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/concurrence/ex1/Makefile @@ -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 + diff --git a/concurrence/ex1/vser.c b/concurrence/ex1/vser.c new file mode 100755 index 000000000..48910d3c5 --- /dev/null +++ b/concurrence/ex1/vser.c @@ -0,0 +1,277 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/concurrence/ex1/vser.h b/concurrence/ex1/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/concurrence/ex1/vser.h @@ -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 diff --git a/devmodel/ex1/Makefile b/devmodel/ex1/Makefile new file mode 100755 index 000000000..d1d233303 --- /dev/null +++ b/devmodel/ex1/Makefile @@ -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 + diff --git a/devmodel/ex1/model.c b/devmodel/ex1/model.c new file mode 100755 index 000000000..7354adae5 --- /dev/null +++ b/devmodel/ex1/model.c @@ -0,0 +1,66 @@ +#include +#include +#include + +#include +#include + +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 "); +MODULE_DESCRIPTION("A simple module for device model"); diff --git a/devmodel/ex2/Makefile b/devmodel/ex2/Makefile new file mode 100755 index 000000000..302123aab --- /dev/null +++ b/devmodel/ex2/Makefile @@ -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 diff --git a/devmodel/ex2/vbus.c b/devmodel/ex2/vbus.c new file mode 100755 index 000000000..6d09dee2b --- /dev/null +++ b/devmodel/ex2/vbus.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("A virtual bus"); diff --git a/devmodel/ex2/vdev.c b/devmodel/ex2/vdev.c new file mode 100755 index 000000000..ee6935232 --- /dev/null +++ b/devmodel/ex2/vdev.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("A virtual device"); diff --git a/devmodel/ex2/vdrv.c b/devmodel/ex2/vdrv.c new file mode 100755 index 000000000..f7383fd58 --- /dev/null +++ b/devmodel/ex2/vdrv.c @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("A virtual device driver"); diff --git a/devmodel/ex3/Makefile b/devmodel/ex3/Makefile new file mode 100755 index 000000000..58e615090 --- /dev/null +++ b/devmodel/ex3/Makefile @@ -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 diff --git a/devmodel/ex3/pltdev.c b/devmodel/ex3/pltdev.c new file mode 100755 index 000000000..198de7c9f --- /dev/null +++ b/devmodel/ex3/pltdev.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("register a platfom device"); diff --git a/devmodel/ex3/pltdrv.c b/devmodel/ex3/pltdrv.c new file mode 100755 index 000000000..672f3c16f --- /dev/null +++ b/devmodel/ex3/pltdrv.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("A simple platform driver"); +MODULE_ALIAS("platform:pdev"); diff --git a/devmodel/ex4/Makefile b/devmodel/ex4/Makefile new file mode 100755 index 000000000..36f5fb244 --- /dev/null +++ b/devmodel/ex4/Makefile @@ -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 + diff --git a/devmodel/ex4/fsdev.c b/devmodel/ex4/fsdev.c new file mode 100755 index 000000000..d76d56001 --- /dev/null +++ b/devmodel/ex4/fsdev.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("register LED devices"); diff --git a/devmodel/ex4/fsled.c b/devmodel/ex4/fsled.c new file mode 100755 index 000000000..025819642 --- /dev/null +++ b/devmodel/ex4/fsled.c @@ -0,0 +1,165 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board"); diff --git a/devmodel/ex4/fsled.h b/devmodel/ex4/fsled.h new file mode 100755 index 000000000..cdf58abf2 --- /dev/null +++ b/devmodel/ex4/fsled.h @@ -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 diff --git a/devmodel/ex4/test.c b/devmodel/ex4/test.c new file mode 100755 index 000000000..81be1fa85 --- /dev/null +++ b/devmodel/ex4/test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/devmodel/ex5/Makefile b/devmodel/ex5/Makefile new file mode 100755 index 000000000..36f5fb244 --- /dev/null +++ b/devmodel/ex5/Makefile @@ -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 + diff --git a/devmodel/ex5/fsdev.c b/devmodel/ex5/fsdev.c new file mode 100755 index 000000000..d76d56001 --- /dev/null +++ b/devmodel/ex5/fsdev.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include + +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 "); +MODULE_DESCRIPTION("register LED devices"); diff --git a/devmodel/ex5/fsled.c b/devmodel/ex5/fsled.c new file mode 100755 index 000000000..8257198c0 --- /dev/null +++ b/devmodel/ex5/fsled.c @@ -0,0 +1,199 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board"); diff --git a/devmodel/ex5/fsled.h b/devmodel/ex5/fsled.h new file mode 100755 index 000000000..cdf58abf2 --- /dev/null +++ b/devmodel/ex5/fsled.h @@ -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 diff --git a/devmodel/ex5/test.c b/devmodel/ex5/test.c new file mode 100755 index 000000000..81be1fa85 --- /dev/null +++ b/devmodel/ex5/test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/devmodel/ex6/Makefile b/devmodel/ex6/Makefile new file mode 100755 index 000000000..67d5f2531 --- /dev/null +++ b/devmodel/ex6/Makefile @@ -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 + diff --git a/devmodel/ex6/fsled.c b/devmodel/ex6/fsled.c new file mode 100755 index 000000000..a6439b4e7 --- /dev/null +++ b/devmodel/ex6/fsled.c @@ -0,0 +1,183 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#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 "); +MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board"); diff --git a/devmodel/ex6/fsled.h b/devmodel/ex6/fsled.h new file mode 100755 index 000000000..cdf58abf2 --- /dev/null +++ b/devmodel/ex6/fsled.h @@ -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 diff --git a/devmodel/ex6/test.c b/devmodel/ex6/test.c new file mode 100755 index 000000000..81be1fa85 --- /dev/null +++ b/devmodel/ex6/test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/dma/ex1/Makefile b/dma/ex1/Makefile new file mode 100755 index 000000000..7d5c8b6ae --- /dev/null +++ b/dma/ex1/Makefile @@ -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 + diff --git a/dma/ex1/memcpy.c b/dma/ex1/memcpy.c new file mode 100755 index 000000000..d98e779c2 --- /dev/null +++ b/dma/ex1/memcpy.c @@ -0,0 +1,96 @@ +#include +#include +#include + +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("simple driver using dmaengine"); diff --git a/examples/ex1/test.c b/examples/ex1/test.c new file mode 100755 index 000000000..5ea890951 --- /dev/null +++ b/examples/ex1/test.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#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; + } +} diff --git a/examples/ex2/Makefile b/examples/ex2/Makefile new file mode 100755 index 000000000..8e94e6d1c --- /dev/null +++ b/examples/ex2/Makefile @@ -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 + diff --git a/examples/ex2/fskey.c b/examples/ex2/fskey.c new file mode 100755 index 000000000..726e1a25b --- /dev/null +++ b/examples/ex2/fskey.c @@ -0,0 +1,85 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("A simple device driver for Keys on FS4412 board"); diff --git a/examples/ex3/Makefile b/examples/ex3/Makefile new file mode 100755 index 000000000..8e94e6d1c --- /dev/null +++ b/examples/ex3/Makefile @@ -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 + diff --git a/examples/ex3/fskey.c b/examples/ex3/fskey.c new file mode 100755 index 000000000..0a72bc5bf --- /dev/null +++ b/examples/ex3/fskey.c @@ -0,0 +1,168 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("A simple device driver for Keys on FS4412 board"); diff --git a/examples/ex3/test.c b/examples/ex3/test.c new file mode 100755 index 000000000..aea209480 --- /dev/null +++ b/examples/ex3/test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +#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()); +} diff --git a/examples/ex4/.test.c.swp b/examples/ex4/.test.c.swp new file mode 100755 index 0000000000000000000000000000000000000000..9625a90b566ba53050437630de0044e9f959b32b GIT binary patch literal 12288 zcmeI2O;6N77{><_4?Q466Azvqikd>!b{EzlFKe<9P!fy@@?u1?DeZK3lF~NqY=sax z_ys)qEj)YiX5tsnlQ%zrsGmUn&x(qYVDP4SCi!J&pU(W}ncr<+Hmj=(w`sy17Z`&= z?0$Z+wsFf5bY6(a&kNP=X!Gc}(cSDOx_jJ;Z_oC=2YOLauh+)BFju9_3r}wQTUjj4 zr0!{1XgBzC8n0jjY~W-D`o;KItvYNE(YdoLC)>)a*#H}018jf|umLu}2G{@__~#Ai ztWSKwElz<7Q6({z*F!Tq#yz7;69iH6Tk%*!5|m_AI}K!4!i-c!7K0_JOO(k10EO#1TKKn z;1hcIaL~(p(+>|ezy{a=8(;%$fDNz#Hoykh02}yA1CN9yx0QD0?kz00=9>$PD@$`D z)56MRo~OBE`(Z%l|JOE(k+0$@VPT6^#8PHX&8)PtTqQbk?4XE%H zGI4A#l%JrP;M51PiO1s5Bvy-7>8QCE{^oLSF~7D4Z6%!qm2Wl{jYN=k1_k zHsv&mdAYtZf{(W<3F2-j$&Lyf<96&rwHX*sQnz#c=dzh7NOb&bsn{vJo{OX9Li_q? URqtf7_^qtNSZyAusov>d0g7_b`2YX_ literal 0 HcmV?d00001 diff --git a/examples/ex4/Makefile b/examples/ex4/Makefile new file mode 100755 index 000000000..a657c1f64 --- /dev/null +++ b/examples/ex4/Makefile @@ -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 + diff --git a/examples/ex4/fsadc.c b/examples/ex4/fsadc.c new file mode 100755 index 000000000..c26a4755e --- /dev/null +++ b/examples/ex4/fsadc.c @@ -0,0 +1,211 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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 "); +MODULE_DESCRIPTION("ADC driver"); diff --git a/examples/ex4/fsadc.h b/examples/ex4/fsadc.h new file mode 100755 index 000000000..868df33b7 --- /dev/null +++ b/examples/ex4/fsadc.h @@ -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 diff --git a/examples/ex4/test.c b/examples/ex4/test.c new file mode 100755 index 000000000..390b52a9a --- /dev/null +++ b/examples/ex4/test.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/examples/ex5/Makefile b/examples/ex5/Makefile new file mode 100755 index 000000000..c79cb5ba7 --- /dev/null +++ b/examples/ex5/Makefile @@ -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 + diff --git a/examples/ex5/fspwm.c b/examples/ex5/fspwm.c new file mode 100755 index 000000000..3510fe09f --- /dev/null +++ b/examples/ex5/fspwm.c @@ -0,0 +1,215 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("PWM driver"); diff --git a/examples/ex5/fspwm.h b/examples/ex5/fspwm.h new file mode 100755 index 000000000..db8a49ee7 --- /dev/null +++ b/examples/ex5/fspwm.h @@ -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 diff --git a/examples/ex5/music.h b/examples/ex5/music.h new file mode 100755 index 000000000..0008c1576 --- /dev/null +++ b/examples/ex5/music.h @@ -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 diff --git a/examples/ex5/test.c b/examples/ex5/test.c new file mode 100755 index 000000000..f3c0f00fd --- /dev/null +++ b/examples/ex5/test.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/examples/ex6/Makefile b/examples/ex6/Makefile new file mode 100755 index 000000000..ab567ef8b --- /dev/null +++ b/examples/ex6/Makefile @@ -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 + diff --git a/examples/ex6/fsrtc.c b/examples/ex6/fsrtc.c new file mode 100755 index 000000000..2f641edd0 --- /dev/null +++ b/examples/ex6/fsrtc.c @@ -0,0 +1,221 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("RTC driver"); diff --git a/examples/ex6/fsrtc.h b/examples/ex6/fsrtc.h new file mode 100755 index 000000000..7e37f3205 --- /dev/null +++ b/examples/ex6/fsrtc.h @@ -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 diff --git a/examples/ex6/music.h b/examples/ex6/music.h new file mode 100755 index 000000000..0008c1576 --- /dev/null +++ b/examples/ex6/music.h @@ -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 diff --git a/examples/ex6/test.c b/examples/ex6/test.c new file mode 100755 index 000000000..b3af1709e --- /dev/null +++ b/examples/ex6/test.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} + diff --git a/i2c/ex1/i2c-dev.h b/i2c/ex1/i2c-dev.h new file mode 100755 index 000000000..2caeaac9b --- /dev/null +++ b/i2c/ex1/i2c-dev.h @@ -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 + + 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 +#include + + +/* -- 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 */ diff --git a/i2c/ex1/test.c b/i2c/ex1/test.c new file mode 100755 index 000000000..94aabb212 --- /dev/null +++ b/i2c/ex1/test.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/i2c/ex2/Makefile b/i2c/ex2/Makefile new file mode 100755 index 000000000..1035c9bdb --- /dev/null +++ b/i2c/ex2/Makefile @@ -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 := mpu6050.o + +endif + diff --git a/i2c/ex2/mpu6050.c b/i2c/ex2/mpu6050.c new file mode 100755 index 000000000..396896122 --- /dev/null +++ b/i2c/ex2/mpu6050.c @@ -0,0 +1,199 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "mpu6050.h" + +#define FSRTC_MAJOR 256 +#define FSRTC_MINOR 9 +#define FSRTC_DEV_NAME "mpu6050" + +#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 + +struct mpu6050_dev { + struct i2c_client *client; + atomic_t available; + struct cdev cdev; +}; + +static int mpu6050_open(struct inode *inode, struct file *filp) +{ + struct mpu6050_dev *mpu6050 = container_of(inode->i_cdev, struct mpu6050_dev, cdev); + + filp->private_data = mpu6050; + if (atomic_dec_and_test(&mpu6050->available)) + return 0; + else { + atomic_inc(&mpu6050->available); + return -EBUSY; + } +} + +static int mpu6050_release(struct inode *inode, struct file *filp) +{ + struct mpu6050_dev *mpu6050 = filp->private_data; + + atomic_inc(&mpu6050->available); + return 0; +} + +static long mpu6050_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct mpu6050_dev *mpu6050 = filp->private_data; + struct atg_val val; + + if (_IOC_TYPE(cmd) != MPU6050_MAGIC) + return -ENOTTY; + + switch (cmd) { + case MPU6050_GET_VAL: + val.accelx = i2c_smbus_read_word_data(mpu6050->client, ACCEL_XOUT_H); + val.accely = i2c_smbus_read_word_data(mpu6050->client, ACCEL_YOUT_H); + val.accelz = i2c_smbus_read_word_data(mpu6050->client, ACCEL_ZOUT_H); + val.temp = i2c_smbus_read_word_data(mpu6050->client, TEMP_OUT_H); + val.gyrox = i2c_smbus_read_word_data(mpu6050->client, GYRO_XOUT_H); + val.gyroy = i2c_smbus_read_word_data(mpu6050->client, GYRO_YOUT_H); + val.gyroz = i2c_smbus_read_word_data(mpu6050->client, GYRO_ZOUT_H); + val.accelx = be16_to_cpu(val.accelx); + val.accely = be16_to_cpu(val.accely); + val.accelz = be16_to_cpu(val.accelz); + val.temp = be16_to_cpu(val.temp); + val.gyrox = be16_to_cpu(val.gyrox); + val.gyroy = be16_to_cpu(val.gyroy); + val.gyroz = be16_to_cpu(val.gyroz); + if (copy_to_user((struct atg_val __user *)arg, &val, sizeof(struct atg_val))) + return -EFAULT; + break; + default: + return -ENOTTY; + } + + return 0; +} + +static struct file_operations mpu6050_ops = { + .owner = THIS_MODULE, + .open = mpu6050_open, + .release = mpu6050_release, + .unlocked_ioctl = mpu6050_ioctl, +}; + +static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret; + dev_t dev; + struct mpu6050_dev *mpu6050; + + dev = MKDEV(FSRTC_MAJOR, FSRTC_MINOR); + ret = register_chrdev_region(dev, 1, FSRTC_DEV_NAME); + if (ret) + goto reg_err; + + mpu6050 = kzalloc(sizeof(struct mpu6050_dev), GFP_KERNEL); + if (!mpu6050) { + ret = -ENOMEM; + goto mem_err; + } + i2c_set_clientdata(client, mpu6050); + mpu6050->client = client; + + cdev_init(&mpu6050->cdev, &mpu6050_ops); + mpu6050->cdev.owner = THIS_MODULE; + ret = cdev_add(&mpu6050->cdev, dev, 1); + if (ret) + goto add_err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + ret = -ENOSYS; + goto fun_err; + } + + i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x80); + msleep(200); + i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x40); + i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x00); + + i2c_smbus_write_byte_data(client, SMPLRT_DIV, 0x7); + i2c_smbus_write_byte_data(client, CONFIG, 0x6); + i2c_smbus_write_byte_data(client, GYRO_CONFIG, 0x3 << 3); + i2c_smbus_write_byte_data(client, ACCEL_CONFIG, 0x3 << 3); + + atomic_set(&mpu6050->available, 1); + + return 0; + +fun_err: + cdev_del(&mpu6050->cdev); +add_err: + kfree(mpu6050); +mem_err: + unregister_chrdev_region(dev, 1); +reg_err: + return ret; +} + +static int mpu6050_remove(struct i2c_client *client) +{ + dev_t dev; + struct mpu6050_dev *mpu6050 = i2c_get_clientdata(client); + + dev = MKDEV(FSRTC_MAJOR, FSRTC_MINOR); + + cdev_del(&mpu6050->cdev); + kfree(mpu6050); + unregister_chrdev_region(dev, 1); + return 0; +} + +static const struct i2c_device_id mpu6050_id[] = { + {"mpu6050", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mpu6050_id); + +static struct i2c_driver mpu6050_driver = { + .probe = mpu6050_probe, + .remove = mpu6050_remove, + .id_table = mpu6050_id, + .driver = { + .owner = THIS_MODULE, + .name = "mpu6050", + }, +}; + +module_i2c_driver(mpu6050_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("MPU6050 driver"); diff --git a/i2c/ex2/mpu6050.h b/i2c/ex2/mpu6050.h new file mode 100755 index 000000000..f6663cb68 --- /dev/null +++ b/i2c/ex2/mpu6050.h @@ -0,0 +1,18 @@ +#ifndef _MPU6050_H +#define _MPU6050_H + +struct atg_val { + short accelx; + short accely; + short accelz; + short temp; + short gyrox; + short gyroy; + short gyroz; +}; + +#define MPU6050_MAGIC 'm' + +#define MPU6050_GET_VAL _IOR(MPU6050_MAGIC, 0, struct atg_val) + +#endif diff --git a/i2c/ex2/test.c b/i2c/ex2/test.c new file mode 100755 index 000000000..097da5a25 --- /dev/null +++ b/i2c/ex2/test.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include + +#include "mpu6050.h" + + +int main(int argc, char *argv[]) +{ + int fd; + struct atg_val val; + + + fd = open("/dev/mpu6050", O_RDWR); + + while (2) { + ioctl(fd, MPU6050_GET_VAL, &val); + + printf("accelx: %.2f\n", val.accelx / 2048.0); + printf("accely: %.2f\n", val.accely / 2048.0); + printf("accelz: %.2f\n", val.accelz / 2048.0); + printf("temp: %.2f\n", val.temp / 340.0 + 36.53); + printf("gyrox: %.2f\n", val.gyrox / 16.4); + printf("gyroy: %.2f\n", val.gyroy / 16.4); + printf("gyroz: %.2f\n", val.gyroz / 16.4); + + + sleep(1); + } +} diff --git a/intdev/ex1/Makefile b/intdev/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/intdev/ex1/Makefile @@ -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 + diff --git a/intdev/ex1/vser.c b/intdev/ex1/vser.c new file mode 100755 index 000000000..ffbef456a --- /dev/null +++ b/intdev/ex1/vser.c @@ -0,0 +1,265 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 irqreturn_t vser_handler(int irq, void *dev_id) +{ + char data; + + get_random_bytes(&data, sizeof(data)); + data %= 26; + data += 'A'; + 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)) { + wake_up_interruptible(&vsdev.rwqh); + kill_fasync(&vsdev.fapp, SIGIO, POLL_IN); + } + + return IRQ_HANDLED; +} + +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); + + ret = request_irq(167, vser_handler, IRQF_TRIGGER_HIGH | IRQF_SHARED, "vser", &vsdev); + if (ret) + goto irq_err; + + 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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/intdev/ex1/vser.h b/intdev/ex1/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/intdev/ex1/vser.h @@ -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 diff --git a/intdev/ex2/Makefile b/intdev/ex2/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/intdev/ex2/Makefile @@ -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 + diff --git a/intdev/ex2/vser.c b/intdev/ex2/vser.c new file mode 100755 index 000000000..e661dfb83 --- /dev/null +++ b/intdev/ex2/vser.c @@ -0,0 +1,273 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 void vser_tsklet(unsigned long arg); +DECLARE_TASKLET(vstsklet, vser_tsklet, (unsigned long)&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 irqreturn_t vser_handler(int irq, void *dev_id) +{ + tasklet_schedule(&vstsklet); + + return IRQ_HANDLED; +} + +static void vser_tsklet(unsigned long arg) +{ + char data; + + get_random_bytes(&data, sizeof(data)); + data %= 26; + data += 'A'; + 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)) { + wake_up_interruptible(&vsdev.rwqh); + kill_fasync(&vsdev.fapp, SIGIO, POLL_IN); + } +} + +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); + + ret = request_irq(167, vser_handler, IRQF_TRIGGER_HIGH | IRQF_SHARED, "vser", &vsdev); + if (ret) + goto irq_err; + + 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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/intdev/ex2/vser.h b/intdev/ex2/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/intdev/ex2/vser.h @@ -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 diff --git a/intdev/ex3/Makefile b/intdev/ex3/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/intdev/ex3/Makefile @@ -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 + diff --git a/intdev/ex3/vser.c b/intdev/ex3/vser.c new file mode 100755 index 000000000..aa62e08b0 --- /dev/null +++ b/intdev/ex3/vser.c @@ -0,0 +1,273 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 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) +{ + 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 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'; + 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)) { + wake_up_interruptible(&vsdev.rwqh); + kill_fasync(&vsdev.fapp, SIGIO, POLL_IN); + } +} + +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); + + ret = request_irq(167, vser_handler, IRQF_TRIGGER_HIGH | IRQF_SHARED, "vser", &vsdev); + if (ret) + goto irq_err; + + 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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/intdev/ex3/vser.h b/intdev/ex3/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/intdev/ex3/vser.h @@ -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 diff --git a/memory/ex1/Makefile b/memory/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/memory/ex1/Makefile @@ -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 + diff --git a/memory/ex1/vser.c b/memory/ex1/vser.c new file mode 100755 index 000000000..31414f7a0 --- /dev/null +++ b/memory/ex1/vser.c @@ -0,0 +1,294 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 { + struct kfifo fifo; + wait_queue_head_t rwqh; + struct fasync_struct *fapp; + atomic_t available; + unsigned int baud; + struct option opt; + struct cdev cdev; +}; + +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(&vsdev->fifo)) { + if (filp->f_flags & O_NONBLOCK) { + spin_unlock(&vsdev->rwqh.lock); + return -EAGAIN; + } + + if (wait_event_interruptible_locked(vsdev->rwqh, !kfifo_is_empty(&vsdev->fifo))) { + spin_unlock(&vsdev->rwqh.lock); + return -ERESTARTSYS; + } + } + + len = kfifo_out(&vsdev->fifo, 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(&vsdev->fifo)) + 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(&vsdev->fifo)) + if(!kfifo_in(&vsdev->fifo, &data, sizeof(data))) + printk(KERN_ERR "vser: kfifo_in failure\n"); + + if (!kfifo_is_empty(&vsdev->fifo)) { + 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; + + vsdev = kzalloc(sizeof(struct vser_dev), GFP_KERNEL); + if (!vsdev) { + ret = -ENOMEM; + goto mem_err; + } + + ret = kfifo_alloc(&vsdev->fifo, VSER_FIFO_SIZE, GFP_KERNEL); + if (ret) + goto fifo_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: + kfifo_free(&vsdev->fifo); +fifo_err: + kfree(vsdev); +mem_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); + kfifo_free(&vsdev->fifo); + kfree(vsdev); +} + +module_init(vser_init); +module_exit(vser_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/memory/ex1/vser.h b/memory/ex1/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/memory/ex1/vser.h @@ -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 diff --git a/memory/ex2/Makefile b/memory/ex2/Makefile new file mode 100755 index 000000000..67d5f2531 --- /dev/null +++ b/memory/ex2/Makefile @@ -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 + diff --git a/memory/ex2/fsled.c b/memory/ex2/fsled.c new file mode 100755 index 000000000..19a5f52f8 --- /dev/null +++ b/memory/ex2/fsled.c @@ -0,0 +1,187 @@ +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "fsled.h" + +#define FSLED_MAJOR 256 +#define FSLED_MINOR 0 +#define FSLED_DEV_CNT 1 +#define FSLED_DEV_NAME "fsled" + +#define GPX2_BASE 0x11000C40 +#define GPX1_BASE 0x11000C20 +#define GPF3_BASE 0x114001E0 + +struct fsled_dev { + unsigned int __iomem *gpx2con; + unsigned int __iomem *gpx2dat; + unsigned int __iomem *gpx1con; + unsigned int __iomem *gpx1dat; + unsigned int __iomem *gpf3con; + unsigned int __iomem *gpf3dat; + atomic_t available; + struct cdev cdev; +}; + +static struct fsled_dev fsled; + +static int fsled_open(struct inode *inode, struct file *filp) +{ + 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) +{ + writel(readl(fsled.gpx2dat) & ~(0x1 << 7), fsled.gpx2dat); + writel(readl(fsled.gpx1dat) & ~(0x1 << 0), fsled.gpx1dat); + writel(readl(fsled.gpf3dat) & ~(0x3 << 4), fsled.gpf3dat); + + atomic_inc(&fsled.available); + return 0; +} + +static long fsled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + if (_IOC_TYPE(cmd) != FSLED_MAGIC) + return -ENOTTY; + + switch (cmd) { + case FSLED_ON: + switch(arg) { + case LED2: + writel(readl(fsled.gpx2dat) | (0x1 << 7), fsled.gpx2dat); + break; + case LED3: + writel(readl(fsled.gpx1dat) | (0x1 << 0), fsled.gpx1dat); + break; + case LED4: + writel(readl(fsled.gpf3dat) | (0x1 << 4), fsled.gpf3dat); + break; + case LED5: + writel(readl(fsled.gpf3dat) | (0x1 << 5), fsled.gpf3dat); + break; + default: + return -ENOTTY; + } + break; + case FSLED_OFF: + switch(arg) { + case LED2: + writel(readl(fsled.gpx2dat) & ~(0x1 << 7), fsled.gpx2dat); + break; + case LED3: + writel(readl(fsled.gpx1dat) & ~(0x1 << 0), fsled.gpx1dat); + break; + case LED4: + writel(readl(fsled.gpf3dat) & ~(0x1 << 4), fsled.gpf3dat); + break; + case LED5: + writel(readl(fsled.gpf3dat) & ~(0x1 << 5), fsled.gpf3dat); + break; + default: + return -ENOTTY; + } + 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 __init fsled_init(void) +{ + int ret; + dev_t dev; + + dev = MKDEV(FSLED_MAJOR, FSLED_MINOR); + ret = register_chrdev_region(dev, FSLED_DEV_CNT, FSLED_DEV_NAME); + if (ret) + goto reg_err; + + memset(&fsled, 0, sizeof(fsled)); + atomic_set(&fsled.available, 1); + cdev_init(&fsled.cdev, &fsled_ops); + fsled.cdev.owner = THIS_MODULE; + + ret = cdev_add(&fsled.cdev, dev, FSLED_DEV_CNT); + if (ret) + goto add_err; + + fsled.gpx2con = ioremap(GPX2_BASE, 8); + fsled.gpx1con = ioremap(GPX1_BASE, 8); + fsled.gpf3con = ioremap(GPF3_BASE, 8); + + if (!fsled.gpx2con || !fsled.gpx1con || !fsled.gpf3con) { + ret = -EBUSY; + goto map_err; + } + + fsled.gpx2dat = fsled.gpx2con + 1; + fsled.gpx1dat = fsled.gpx1con + 1; + fsled.gpf3dat = fsled.gpf3con + 1; + + writel((readl(fsled.gpx2con) & ~(0xF << 28)) | (0x1 << 28), fsled.gpx2con); + writel((readl(fsled.gpx1con) & ~(0xF << 0)) | (0x1 << 0), fsled.gpx1con); + writel((readl(fsled.gpf3con) & ~(0xFF << 16)) | (0x11 << 16), fsled.gpf3con); + + writel(readl(fsled.gpx2dat) & ~(0x1 << 7), fsled.gpx2dat); + writel(readl(fsled.gpx1dat) & ~(0x1 << 0), fsled.gpx1dat); + writel(readl(fsled.gpf3dat) & ~(0x3 << 4), fsled.gpf3dat); + + return 0; + +map_err: + if (fsled.gpf3con) + iounmap(fsled.gpf3con); + if (fsled.gpx1con) + iounmap(fsled.gpx1con); + if (fsled.gpx2con) + iounmap(fsled.gpx2con); +add_err: + unregister_chrdev_region(dev, FSLED_DEV_CNT); +reg_err: + return ret; +} + +static void __exit fsled_exit(void) +{ + dev_t dev; + + dev = MKDEV(FSLED_MAJOR, FSLED_MINOR); + + iounmap(fsled.gpf3con); + iounmap(fsled.gpx1con); + iounmap(fsled.gpx2con); + cdev_del(&fsled.cdev); + unregister_chrdev_region(dev, FSLED_DEV_CNT); +} + +module_init(fsled_init); +module_exit(fsled_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("A simple character device driver for LEDs on FS4412 board"); diff --git a/memory/ex2/fsled.h b/memory/ex2/fsled.h new file mode 100755 index 000000000..9487fb88a --- /dev/null +++ b/memory/ex2/fsled.h @@ -0,0 +1,14 @@ +#ifndef _FSLED_H +#define _FSLED_H + +#define FSLED_MAGIC 'f' + +#define FSLED_ON _IOW(FSLED_MAGIC, 0, unsigned int) +#define FSLED_OFF _IOW(FSLED_MAGIC, 1, unsigned int) + +#define LED2 0 +#define LED3 1 +#define LED4 2 +#define LED5 3 + +#endif diff --git a/memory/ex2/test.c b/memory/ex2/test.c new file mode 100755 index 000000000..652750c40 --- /dev/null +++ b/memory/ex2/test.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "fsled.h" + +int main(int argc, char *argv[]) +{ + int fd; + int ret; + int num = LED2; + + fd = open("/dev/led", O_RDWR); + if (fd == -1) + goto fail; + + while (1) { + ret = ioctl(fd, FSLED_ON, num); + if (ret == -1) + goto fail; + usleep(500000); + ret = ioctl(fd, FSLED_OFF, num); + if (ret == -1) + goto fail; + usleep(500000); + + num = (num + 1) % 4; + } +fail: + perror("led test"); + exit(EXIT_FAILURE); +} + diff --git a/module/ex1/Makefile b/module/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/module/ex1/Makefile @@ -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 + diff --git a/module/ex1/vser.c b/module/ex1/vser.c new file mode 100755 index 000000000..6df099d8e --- /dev/null +++ b/module/ex1/vser.c @@ -0,0 +1,14 @@ +#include +#include +#include + +int init_module(void) +{ + printk("module init\n"); + return 0; +} + +void cleanup_module(void) +{ + printk("cleanup module\n"); +} diff --git a/module/ex2/Makefile b/module/ex2/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/module/ex2/Makefile @@ -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 + diff --git a/module/ex2/vser.c b/module/ex2/vser.c new file mode 100755 index 000000000..462cd9585 --- /dev/null +++ b/module/ex2/vser.c @@ -0,0 +1,22 @@ +#include +#include +#include + +static int __init vser_init(void) +{ + printk("vser_init\n"); + return 0; +} + +static void __exit vser_exit(void) +{ + printk("vser_exit\n"); +} + +module_init(vser_init); +module_exit(vser_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("A simple module"); +MODULE_ALIAS("virtual-serial"); diff --git a/module/ex3/Makefile b/module/ex3/Makefile new file mode 100755 index 000000000..3ab7ec1e3 --- /dev/null +++ b/module/ex3/Makefile @@ -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 := vser.o +vser-objs = foo.o bar.o + +endif + diff --git a/module/ex3/bar.c b/module/ex3/bar.c new file mode 100755 index 000000000..fb7bf3d74 --- /dev/null +++ b/module/ex3/bar.c @@ -0,0 +1,6 @@ +#include + +void bar(void) +{ + printk("bar\n"); +} diff --git a/module/ex3/foo.c b/module/ex3/foo.c new file mode 100755 index 000000000..aea76cded --- /dev/null +++ b/module/ex3/foo.c @@ -0,0 +1,25 @@ +#include +#include +#include + +extern void bar(void); + +static int __init vser_init(void) +{ + printk("vser_init\n"); + bar(); + return 0; +} + +static void __exit vser_exit(void) +{ + printk("vser_exit\n"); +} + +module_init(vser_init); +module_exit(vser_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("A simple module"); +MODULE_ALIAS("virtual-serial"); diff --git a/module/ex4/Makefile b/module/ex4/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/module/ex4/Makefile @@ -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 + diff --git a/module/ex4/vser.c b/module/ex4/vser.c new file mode 100755 index 000000000..003d95ba7 --- /dev/null +++ b/module/ex4/vser.c @@ -0,0 +1,39 @@ +#include +#include +#include + +static int baudrate = 9600; +static int port[4] = {0, 1, 2, 3}; +static char *name = "vser"; + +module_param(baudrate, int, S_IRUGO); +module_param_array(port, int, NULL, S_IRUGO); +module_param(name, charp, S_IRUGO); + +static int __init vser_init(void) +{ + int i; + + printk("vser_init\n"); + printk("baudrate: %d\n", baudrate); + printk("port: "); + for (i = 0; i < ARRAY_SIZE(port); i++) + printk("%d ", port[i]); + printk("\n"); + printk("name: %s\n", name); + + return 0; +} + +static void __exit vser_exit(void) +{ + printk("vser_exit\n"); +} + +module_init(vser_init); +module_exit(vser_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("A simple module"); +MODULE_ALIAS("virtual-serial"); diff --git a/module/ex5/Makefile b/module/ex5/Makefile new file mode 100755 index 000000000..34e5bfd6e --- /dev/null +++ b/module/ex5/Makefile @@ -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 := vser.o +obj-m += dep.o + +endif + diff --git a/module/ex5/dep.c b/module/ex5/dep.c new file mode 100755 index 000000000..17b59ced8 --- /dev/null +++ b/module/ex5/dep.c @@ -0,0 +1,15 @@ +#include +#include + +static int expval = 5; +EXPORT_SYMBOL(expval); + +static void expfun(void) +{ + printk("expfun\n"); +} + +EXPORT_SYMBOL_GPL(expfun); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); diff --git a/module/ex5/vser.c b/module/ex5/vser.c new file mode 100755 index 000000000..563cd8bc4 --- /dev/null +++ b/module/ex5/vser.c @@ -0,0 +1,28 @@ +#include +#include +#include + +extern int expval; +extern void expfun(void); + +static int __init vser_init(void) +{ + printk("vser_init\n"); + printk("expval: %d\n", expval); + expfun(); + + return 0; +} + +static void __exit vser_exit(void) +{ + printk("vser_exit\n"); +} + +module_init(vser_init); +module_exit(vser_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("A simple module"); +MODULE_ALIAS("virtual-serial"); diff --git a/net/ex1/Makefile b/net/ex1/Makefile new file mode 100755 index 000000000..975c00763 --- /dev/null +++ b/net/ex1/Makefile @@ -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 := vnet.o + +endif + diff --git a/net/ex1/vnet.c b/net/ex1/vnet.c new file mode 100755 index 000000000..c66c5c6c7 --- /dev/null +++ b/net/ex1/vnet.c @@ -0,0 +1,178 @@ +#include +#include +#include + +#include +#include +#include + +#include + +#include "vnet.h" + +struct net_device *vnet_dev; + +static int vnet_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +static int vnet_stop(struct net_device *dev) +{ + netif_stop_queue(dev); + return 0; +} + +void vnet_rx(struct net_device *dev) +{ + struct sk_buff *skb; + struct vnet_priv *priv = netdev_priv(dev); + + skb = dev_alloc_skb(priv->rxlen + 2); + if (IS_ERR(skb)) { + printk(KERN_NOTICE "vnet: low on mem - packet dropped\n"); + dev->stats.rx_dropped++; + return; + } + skb_reserve(skb, 2); + memcpy(skb_put(skb, priv->rxlen), priv->rxdata, priv->rxlen); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + dev->stats.rx_packets++; + dev->stats.rx_bytes += priv->rxlen; + netif_rx(skb); + + return; +} + +static void vnet_rx_int(char *buf, int len, struct net_device *dev) +{ + struct vnet_priv *priv; + + priv = netdev_priv(dev); + priv->rxlen = len; + memcpy(priv->rxdata, buf, len); + vnet_rx(dev); + + return; +} + +static void vnet_hw_tx(char *buf, int len, struct net_device *dev) +{ +#if DEBUG + int i; +#endif + + struct iphdr *ih; + struct net_device *dest; + struct vnet_priv *priv; + u32 *saddr, *daddr; + + if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { + printk("vnet: Packet too short (%i octets)\n", len); + return; + } + +#if DEBUG + printk("len is %i\n", len); + printk("data: "); + for (i = 0; i < len; i++) + printk(" %02x",buf[i] & 0xff); + printk("\n"); +#endif + + ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); + saddr = &ih->saddr; + daddr = &ih->daddr; + ((u8 *)saddr)[3] = ((u8 *)saddr)[3] ^ ((u8 *)daddr)[3]; + ((u8 *)daddr)[3] = ((u8 *)saddr)[3] ^ ((u8 *)daddr)[3]; + ((u8 *)saddr)[3] = ((u8 *)saddr)[3] ^ ((u8 *)daddr)[3]; + + ih->check = 0; + ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl); + +#if DEBUG + printk("len is %i\n", len); + printk("data: "); + for (i = 0; i < len; i++) + printk(" %02x",buf[i] & 0xff); + printk("\n\n"); +#endif + + dest = vnet_dev; + vnet_rx_int(buf, len, dest); + + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; + priv = netdev_priv(dev); + dev_kfree_skb(priv->txskb); +} + +static netdev_tx_t vnet_tx(struct sk_buff *skb, struct net_device *dev) +{ + int len; + char *data, shortpkt[ETH_ZLEN]; + struct vnet_priv *priv = netdev_priv(dev); + + data = skb->data; + len = skb->len; + if (len < ETH_ZLEN) { + memset(shortpkt, 0, ETH_ZLEN); + memcpy(shortpkt, skb->data, skb->len); + len = ETH_ZLEN; + data = shortpkt; + } + dev->trans_start = jiffies; + priv->txskb = skb; + vnet_hw_tx(data, len, dev); + + return 0; +} + +static const struct net_device_ops vnet_ops = { + .ndo_open = vnet_open, + .ndo_stop = vnet_stop, + .ndo_start_xmit = vnet_tx, +}; + + +static int __init vnet_init(void) +{ + int status; + struct vnet_priv *priv; + + vnet_dev = alloc_etherdev(sizeof(struct vnet_priv)); + if (IS_ERR(vnet_dev)) + return -ENOMEM; + + ether_setup(vnet_dev); + vnet_dev->netdev_ops = &vnet_ops; + vnet_dev->flags |= IFF_NOARP; + priv = netdev_priv(vnet_dev); + memset(priv, 0, sizeof(struct vnet_priv)); + + status = register_netdev(vnet_dev); + if (status) { + free_netdev(vnet_dev); + return status; + } + + return 0; +} + +static void __exit vnet_exit(void) +{ + + unregister_netdev(vnet_dev); + free_netdev(vnet_dev); +} + +module_init(vnet_init); +module_exit(vnet_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("Virtual ethernet driver"); diff --git a/net/ex1/vnet.h b/net/ex1/vnet.h new file mode 100755 index 000000000..66d9b8496 --- /dev/null +++ b/net/ex1/vnet.h @@ -0,0 +1,12 @@ +#ifndef __VNET_H__ +#define __VNET_H__ + +#define DEBUG 1 + +struct vnet_priv { + struct sk_buff *txskb; + int rxlen; + unsigned char rxdata[ETH_DATA_LEN]; +}; + +#endif diff --git a/pci/ex1/Makefile b/pci/ex1/Makefile new file mode 100755 index 000000000..dee942d54 --- /dev/null +++ b/pci/ex1/Makefile @@ -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 := ch368.o + +endif + diff --git a/pci/ex1/ch368.c b/pci/ex1/ch368.c new file mode 100755 index 000000000..e96f0f9d4 --- /dev/null +++ b/pci/ex1/ch368.c @@ -0,0 +1,242 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ch368.h" + +#define CH368_MAJOR 256 +#define CH368_MINOR 11 +#define CH368_DEV_NAME "ch368" + +struct ch368_dev { + void __iomem *io_addr; + void __iomem *mem_addr; + unsigned long io_len; + unsigned long mem_len; + struct pci_dev *pdev; + struct cdev cdev; + dev_t dev; +}; + +static unsigned int minor = CH368_MINOR; + +static int ch368_open(struct inode *inode, struct file *filp) +{ + struct ch368_dev *ch368; + + ch368 = container_of(inode->i_cdev, struct ch368_dev, cdev); + filp->private_data = ch368; + + return 0; +} + +static int ch368_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t ch368_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops) +{ + int ret; + struct ch368_dev *ch368 = filp->private_data; + + count = count > ch368->mem_len ? ch368->mem_len : count; + ret = copy_to_user(buf, ch368->mem_addr, count); + + return count - ret; +} + +static ssize_t ch368_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops) +{ + int ret; + struct ch368_dev *ch368 = filp->private_data; + + count = count > ch368->mem_len ? ch368->mem_len : count; + ret = copy_from_user(ch368->mem_addr, buf, count); + + return count - ret; +} + +static long ch368_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + union addr_data ad; + struct ch368_dev *ch368 = filp->private_data; + + if (_IOC_TYPE(cmd) != CH368_MAGIC) + return -ENOTTY; + + if (copy_from_user(&ad, (union addr_data __user *)arg, sizeof(union addr_data))) + return -EFAULT; + + switch (cmd) { + case CH368_RD_CFG: + if (ad.addr > 0x3F) + return -ENOTTY; + pci_read_config_byte(ch368->pdev, ad.addr, &ad.data); + if (copy_to_user((union addr_data __user *)arg, &ad, sizeof(union addr_data))) + return -EFAULT; + break; + case CH368_WR_CFG: + if (ad.addr > 0x3F) + return -ENOTTY; + pci_write_config_byte(ch368->pdev, ad.addr, ad.data); + break; + case CH368_RD_IO: + ad.data = ioread8(ch368->io_addr + ad.addr); + if (copy_to_user((union addr_data __user *)arg, &ad, sizeof(union addr_data))) + return -EFAULT; + break; + case CH368_WR_IO: + iowrite8(ad.data, ch368->io_addr + ad.addr); + break; + default: + return -ENOTTY; + } + + return 0; +} + +static struct file_operations ch368_ops = { + .owner = THIS_MODULE, + .open = ch368_open, + .release = ch368_release, + .read = ch368_read, + .write = ch368_write, + .unlocked_ioctl = ch368_ioctl, +}; + +static int ch368_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int ret; + + unsigned long io_start; + unsigned long io_end; + unsigned long io_flags; + unsigned long io_len; + void __iomem *io_addr = NULL; + + unsigned long mem_start; + unsigned long mem_end; + unsigned long mem_flags; + unsigned long mem_len; + void __iomem *mem_addr = NULL; + + struct ch368_dev *ch368; + + ret = pci_enable_device(pdev); + if(ret) + goto enable_err; + + io_start = pci_resource_start(pdev, 0); + io_end = pci_resource_end(pdev, 0); + io_flags = pci_resource_flags(pdev, 0); + io_len = pci_resource_len(pdev, 0); + + mem_start = pci_resource_start(pdev, 1); + mem_end = pci_resource_end(pdev, 1); + mem_flags = pci_resource_flags(pdev, 1); + mem_len = pci_resource_len(pdev, 1); + + if (!(io_flags & IORESOURCE_IO) || !(mem_flags & IORESOURCE_MEM)) { + ret = -ENODEV; + goto res_err; + } + + ret = pci_request_regions(pdev, "ch368"); + if (ret) + goto res_err; + + io_addr = ioport_map(io_start, io_len); + if (io_addr == NULL) { + ret = -EIO; + goto ioport_map_err; + } + + mem_addr = ioremap(mem_start, mem_len); + if (mem_addr == NULL) { + ret = -EIO; + goto ioremap_err; + } + + ch368 = kzalloc(sizeof(struct ch368_dev), GFP_KERNEL); + if (!ch368) { + ret = -ENOMEM; + goto mem_err; + } + pci_set_drvdata(pdev, ch368); + + ch368->io_addr = io_addr; + ch368->mem_addr = mem_addr; + ch368->io_len = io_len; + ch368->mem_len = mem_len; + ch368->pdev = pdev; + + ch368->dev = MKDEV(CH368_MAJOR, minor++); + ret = register_chrdev_region (ch368->dev, 1, CH368_DEV_NAME); + if (ret < 0) + goto region_err; + + cdev_init(&ch368->cdev, &ch368_ops); + ch368->cdev.owner = THIS_MODULE; + ret = cdev_add(&ch368->cdev, ch368->dev, 1); + if (ret) + goto add_err; + + return 0; + +add_err: + unregister_chrdev_region(ch368->dev, 1); +region_err: + kfree(ch368); +mem_err: + iounmap(mem_addr); +ioremap_err: + ioport_unmap(io_addr); +ioport_map_err: + pci_release_regions(pdev); +res_err: + pci_disable_device(pdev); +enable_err: + return ret; +} + +static void ch368_remove(struct pci_dev *pdev) +{ + struct ch368_dev *ch368 = pci_get_drvdata(pdev); + + cdev_del(&ch368->cdev); + unregister_chrdev_region(ch368->dev, 1); + iounmap(ch368->mem_addr); + ioport_unmap(ch368->io_addr); + kfree(ch368); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id ch368_id_table[] = +{ + {0x1C00, 0x5834, 0x1C00, 0x5834, 0, 0, 0}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, ch368_id_table); + +static struct pci_driver ch368_driver = { + .name = "ch368", + .id_table = ch368_id_table, + .probe = ch368_probe, + .remove = ch368_remove, +}; + +module_pci_driver(ch368_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("CH368 driver"); diff --git a/pci/ex1/ch368.h b/pci/ex1/ch368.h new file mode 100755 index 000000000..50d62d2a9 --- /dev/null +++ b/pci/ex1/ch368.h @@ -0,0 +1,16 @@ +#ifndef _CH368_H +#define _CH368_H + +union addr_data { + unsigned char addr; + unsigned char data; +}; + +#define CH368_MAGIC 'c' + +#define CH368_RD_CFG _IOWR(CH368_MAGIC, 0, union addr_data) +#define CH368_WR_CFG _IOWR(CH368_MAGIC, 1, union addr_data) +#define CH368_RD_IO _IOWR(CH368_MAGIC, 2, union addr_data) +#define CH368_WR_IO _IOWR(CH368_MAGIC, 3, union addr_data) + +#endif diff --git a/pci/ex1/test.c b/pci/ex1/test.c new file mode 100755 index 000000000..e7f35587b --- /dev/null +++ b/pci/ex1/test.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "ch368.h" + +int main(int argc, char *argv[]) +{ + int i; + int fd; + int ret; + union addr_data ad; + unsigned char id[4]; + + fd = open("/dev/ch368", O_RDWR); + if (fd == -1) + goto fail; + + for (i = 0; i < sizeof(id); i++) { + ad.addr = i; + if (ioctl(fd, CH368_RD_CFG, &ad)) + goto fail; + id[i] = ad.data; + } + + printf("VID: 0x%02x%02x, DID: 0x%02x%02x\n", id[1], id[0], id[3], id[2]); + + i = 0; + ad.addr = 0; + while (1) { + ad.data = i++; + if (ioctl(fd, CH368_WR_IO, &ad)) + goto fail; + i %= 15; + sleep(1); + } +fail: + perror("pci test"); + exit(EXIT_FAILURE); +} + diff --git a/timer/ex1/Makefile b/timer/ex1/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/timer/ex1/Makefile @@ -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 + diff --git a/timer/ex1/vser.c b/timer/ex1/vser.c new file mode 100755 index 000000000..56b0a957f --- /dev/null +++ b/timer/ex1/vser.c @@ -0,0 +1,267 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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; + struct timer_list timer; +}; + +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 void vser_timer(unsigned long arg) +{ + char data; + struct vser_dev *dev = (struct vser_dev *)arg; + + get_random_bytes(&data, sizeof(data)); + data %= 26; + data += 'A'; + 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)) { + wake_up_interruptible(&vsdev.rwqh); + kill_fasync(&vsdev.fapp, SIGIO, POLL_IN); + } + + mod_timer(&dev->timer, get_jiffies_64() + msecs_to_jiffies(1000)); +} + +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); + + init_timer(&vsdev.timer); + vsdev.timer.expires = get_jiffies_64() + msecs_to_jiffies(1000); + vsdev.timer.function = vser_timer; + vsdev.timer.data = (unsigned long)&vsdev; + add_timer(&vsdev.timer); + + 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); + + del_timer(&vsdev.timer); + 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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/timer/ex1/vser.h b/timer/ex1/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/timer/ex1/vser.h @@ -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 diff --git a/timer/ex2/Makefile b/timer/ex2/Makefile new file mode 100755 index 000000000..490d4664c --- /dev/null +++ b/timer/ex2/Makefile @@ -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 + diff --git a/timer/ex2/vser.c b/timer/ex2/vser.c new file mode 100755 index 000000000..9fbf4834d --- /dev/null +++ b/timer/ex2/vser.c @@ -0,0 +1,267 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#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; + struct hrtimer timer; +}; + +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 enum hrtimer_restart vser_timer(struct hrtimer *timer) +{ + char data; + + get_random_bytes(&data, sizeof(data)); + data %= 26; + data += 'A'; + 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)) { + wake_up_interruptible(&vsdev.rwqh); + kill_fasync(&vsdev.fapp, SIGIO, POLL_IN); + } + + hrtimer_forward_now(timer, ktime_set(1, 1000)); + + return HRTIMER_RESTART; +} + +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); + + hrtimer_init(&vsdev.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + vsdev.timer.function = vser_timer; + hrtimer_start(&vsdev.timer, ktime_set(1, 1000), HRTIMER_MODE_REL); + + 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); + + hrtimer_cancel(&vsdev.timer); + 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 "); +MODULE_DESCRIPTION("A simple character device driver"); +MODULE_ALIAS("virtual-serial"); diff --git a/timer/ex2/vser.h b/timer/ex2/vser.h new file mode 100755 index 000000000..7e966272c --- /dev/null +++ b/timer/ex2/vser.h @@ -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 diff --git a/usb/ex1/Makefile b/usb/ex1/Makefile new file mode 100755 index 000000000..78f34e5bb --- /dev/null +++ b/usb/ex1/Makefile @@ -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 := pdiusbd12.o + +endif + diff --git a/usb/ex1/pdiusbd12.c b/usb/ex1/pdiusbd12.c new file mode 100755 index 000000000..9b3b28477 --- /dev/null +++ b/usb/ex1/pdiusbd12.c @@ -0,0 +1,297 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pdiusbd12.h" + +#define PDIUSBD12_MAJOR 256 +#define PDIUSBD12_MINOR 10 +#define PDIUSBD12_DEV_NAME "pdiusbd12" + +struct pdiusbd12_dev { + int pipe_ep1_out; + int pipe_ep1_in; + int pipe_ep2_out; + int pipe_ep2_in; + int maxp_ep1_out; + int maxp_ep1_in; + int maxp_ep2_out; + int maxp_ep2_in; + struct urb *ep2inurb; + int errors; + unsigned int ep2inlen; + unsigned char ep1inbuf[16]; + unsigned char ep1outbuf[16]; + unsigned char ep2inbuf[64]; + unsigned char ep2outbuf[64]; + struct usb_device *usbdev; + wait_queue_head_t wq; + struct cdev cdev; + dev_t dev; +}; + +static unsigned int minor = PDIUSBD12_MINOR; + +static int pdiusbd12_open(struct inode *inode, struct file *filp) +{ + struct pdiusbd12_dev *pdiusbd12; + + pdiusbd12 = container_of(inode->i_cdev, struct pdiusbd12_dev, cdev); + filp->private_data = pdiusbd12; + + return 0; +} + +static int pdiusbd12_release(struct inode *inode, struct file *filp) +{ + struct pdiusbd12_dev *pdiusbd12; + + pdiusbd12 = container_of(inode->i_cdev, struct pdiusbd12_dev, cdev); + usb_kill_urb(pdiusbd12->ep2inurb); + + return 0; +} + +void usb_read_complete(struct urb * urb) +{ + struct pdiusbd12_dev *pdiusbd12 = urb->context; + + switch (urb->status) { + case 0: + pdiusbd12->ep2inlen = urb->actual_length; + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + default: + pdiusbd12->ep2inlen = 0; + break; + } + pdiusbd12->errors = urb->status; + wake_up_interruptible(&pdiusbd12->wq); +} + +static ssize_t pdiusbd12_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops) +{ + int ret; + struct usb_device *usbdev; + struct pdiusbd12_dev *pdiusbd12 = filp->private_data; + + count = count > sizeof(pdiusbd12->ep2inbuf) ? sizeof(pdiusbd12->ep1inbuf) : count; + + ret = count; + usbdev = pdiusbd12->usbdev; + usb_fill_bulk_urb(pdiusbd12->ep2inurb, usbdev, pdiusbd12->pipe_ep2_in, pdiusbd12->ep2inbuf, ret, usb_read_complete, pdiusbd12); + if (usb_submit_urb(pdiusbd12->ep2inurb, GFP_KERNEL)) + return -EIO; + interruptible_sleep_on(&pdiusbd12->wq); + + if (pdiusbd12->errors) + return pdiusbd12->errors; + else { + if (copy_to_user(buf, pdiusbd12->ep2inbuf, pdiusbd12->ep2inlen)) + return -EFAULT; + else + return pdiusbd12->ep2inlen; + } +} + +static ssize_t pdiusbd12_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops) +{ + int len; + ssize_t ret = 0; + struct pdiusbd12_dev *pdiusbd12 = filp->private_data; + + count = count > sizeof(pdiusbd12->ep2outbuf) ? sizeof(pdiusbd12->ep2outbuf) : count; + if (copy_from_user(pdiusbd12->ep2outbuf, buf, count)) + return -EFAULT; + + ret = usb_bulk_msg(pdiusbd12->usbdev, pdiusbd12->pipe_ep2_out, pdiusbd12->ep2outbuf, count, &len, 10 * HZ); + if (ret) + return ret; + else + return len; +} + +long pdiusbd12_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret; + int len; + struct pdiusbd12_dev *pdiusbd12 = filp->private_data; + + if (_IOC_TYPE(cmd) != PDIUSBD12_MAGIC) + return -ENOTTY; + + switch (cmd) { + case PDIUSBD12_GET_KEY: + ret = usb_interrupt_msg(pdiusbd12->usbdev, pdiusbd12->pipe_ep1_in, pdiusbd12->ep1inbuf, 8, &len, 10 * HZ); + if (ret) + return ret; + else { + if (copy_to_user((unsigned char __user *)arg, pdiusbd12->ep1inbuf, len)) + return -EFAULT; + else + return 0; + } + break; + case PDIUSBD12_SET_LED: + if (copy_from_user(pdiusbd12->ep1outbuf, (unsigned char __user *)arg, 8)) + return -EFAULT; + ret = usb_interrupt_msg(pdiusbd12->usbdev, pdiusbd12->pipe_ep1_out, pdiusbd12->ep1outbuf, 8, &len, 10 * HZ); + if (ret) + return ret; + else + return 0; + default: + return -ENOTTY; + } + + return 0; +} + +static struct file_operations pdiusbd12_ops = { + .owner = THIS_MODULE, + .open = pdiusbd12_open, + .release = pdiusbd12_release, + .read = pdiusbd12_read, + .write = pdiusbd12_write, + .unlocked_ioctl = pdiusbd12_ioctl, +}; + +int pdiusbd12_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + static struct pdiusbd12_dev *pdiusbd12; + struct usb_device *usbdev; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + int ret = 0; + + pdiusbd12 = kmalloc(sizeof(struct pdiusbd12_dev), GFP_KERNEL); + if (!pdiusbd12) + return -ENOMEM; + + usbdev = interface_to_usbdev(intf); + interface = intf->cur_altsetting; + if (interface->desc.bNumEndpoints != 4) { + ret = -ENODEV; + goto out_no_dev; + } + + /* EP1 Interrupt IN */ + endpoint = &interface->endpoint[0].desc; + if (!(endpoint->bEndpointAddress & 0x80)) { /* IN */ + ret = -ENODEV; + goto out_no_dev; + } + if ((endpoint->bmAttributes & 0x7F) != 3) { /* Interrupt */ + ret = -ENODEV; + goto out_no_dev; + } + pdiusbd12->pipe_ep1_in = usb_rcvintpipe(usbdev, endpoint->bEndpointAddress); + pdiusbd12->maxp_ep1_in = usb_maxpacket(usbdev, pdiusbd12->pipe_ep1_in, usb_pipeout(pdiusbd12->pipe_ep1_in)); + + /* EP1 Interrupt Out */ + endpoint = &interface->endpoint[1].desc; + if (endpoint->bEndpointAddress & 0x80) { /* OUT */ + ret = -ENODEV; + goto out_no_dev; + } + if ((endpoint->bmAttributes & 0x7F) != 3) { /* Interrupt */ + ret = -ENODEV; + goto out_no_dev; + } + pdiusbd12->pipe_ep1_out = usb_sndintpipe(usbdev, endpoint->bEndpointAddress); + pdiusbd12->maxp_ep1_out = usb_maxpacket(usbdev, pdiusbd12->pipe_ep1_out, usb_pipeout(pdiusbd12->pipe_ep1_out)); + + /* EP2 Bulk IN */ + endpoint = &interface->endpoint[2].desc; + if (!(endpoint->bEndpointAddress & 0x80)) { /* IN */ + ret = -ENODEV; + goto out_no_dev; + } + if ((endpoint->bmAttributes & 0x7F) != 2) { /* Bulk */ + ret = -ENODEV; + goto out_no_dev; + } + pdiusbd12->pipe_ep2_in = usb_rcvintpipe(usbdev, endpoint->bEndpointAddress); + pdiusbd12->maxp_ep2_in = usb_maxpacket(usbdev, pdiusbd12->pipe_ep2_in, usb_pipeout(pdiusbd12->pipe_ep2_in)); + + endpoint = &interface->endpoint[3].desc; + if (endpoint->bEndpointAddress & 0x80) { /* OUT */ + ret = -ENODEV; + goto out_no_dev; + } + if ((endpoint->bmAttributes & 0x7F) != 2) { /* Bulk */ + ret = -ENODEV; + goto out_no_dev; + } + pdiusbd12->pipe_ep2_out = usb_sndintpipe(usbdev, endpoint->bEndpointAddress); + pdiusbd12->maxp_ep2_out = usb_maxpacket(usbdev, pdiusbd12->pipe_ep2_out, usb_pipeout(pdiusbd12->pipe_ep2_out)); + + pdiusbd12->ep2inurb = usb_alloc_urb(0, GFP_KERNEL); + pdiusbd12->usbdev = usbdev; + usb_set_intfdata(intf, pdiusbd12); + + pdiusbd12->dev = MKDEV(PDIUSBD12_MAJOR, minor++); + ret = register_chrdev_region (pdiusbd12->dev, 1, PDIUSBD12_DEV_NAME); + if (ret < 0) + goto out_reg_region; + + cdev_init(&pdiusbd12->cdev, &pdiusbd12_ops); + pdiusbd12->cdev.owner = THIS_MODULE; + ret = cdev_add(&pdiusbd12->cdev, pdiusbd12->dev, 1); + if (ret) + goto out_cdev_add; + + init_waitqueue_head(&pdiusbd12->wq); + + return 0; + +out_cdev_add: + unregister_chrdev_region(pdiusbd12->dev, 1); +out_reg_region: + usb_free_urb(pdiusbd12->ep2inurb); +out_no_dev: + kfree(pdiusbd12); + return ret; +} + +void pdiusbd12_disconnect(struct usb_interface *intf) +{ + struct pdiusbd12_dev *pdiusbd12 = usb_get_intfdata(intf); + + cdev_del(&pdiusbd12->cdev); + unregister_chrdev_region(pdiusbd12->dev, 1); + usb_kill_urb(pdiusbd12->ep2inurb); + usb_free_urb(pdiusbd12->ep2inurb); + kfree(pdiusbd12); +} + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x8888, 0x000b) }, + { } +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver pdiusbd12_driver = +{ + .name = "pdiusbd12", + .id_table = id_table, + .probe = pdiusbd12_probe, + .disconnect = pdiusbd12_disconnect, +}; + +module_usb_driver(pdiusbd12_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Jiang "); +MODULE_DESCRIPTION("PDIUSBD12 driver"); diff --git a/usb/ex1/pdiusbd12.h b/usb/ex1/pdiusbd12.h new file mode 100755 index 000000000..20ec5dd12 --- /dev/null +++ b/usb/ex1/pdiusbd12.h @@ -0,0 +1,17 @@ +#ifndef _PDIUSBD12_H +#define _PDIUSBD12_H + +struct d12key { + unsigned char key[8]; +}; + +struct d12led { + unsigned char led[8]; +}; + +#define PDIUSBD12_MAGIC 'p' + +#define PDIUSBD12_GET_KEY _IOR(PDIUSBD12_MAGIC, 0, struct d12key) +#define PDIUSBD12_SET_LED _IOW(PDIUSBD12_MAGIC, 1, struct d12led) + +#endif diff --git a/usb/ex1/test.c b/usb/ex1/test.c new file mode 100755 index 000000000..2c28f61ce --- /dev/null +++ b/usb/ex1/test.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "pdiusbd12.h" + +int main(int argc, char *argv[]) +{ + int fd; + int ret; + unsigned char key[8]; + unsigned char led[8]; + unsigned int count, i; + + fd = open("/dev/pdiusbd12", O_RDWR); + if (fd == -1) + goto fail; + + while (1) { + ret = ioctl(fd, PDIUSBD12_GET_KEY, key); + if (ret == -1) { + if (errno == ETIMEDOUT) + continue; + else + goto fail; + } + switch (key[0]) { + case 0x00: + puts("KEYn released"); + break; + case 0x01: + puts("KEY2 pressed"); + break; + case 0x02: + puts("KEY3 pressed"); + break; + case 0x04: + puts("KEY4 pressed"); + break; + case 0x08: + puts("KEY5 pressed"); + break; + case 0x10: + puts("KEY6 pressed"); + break; + case 0x20: + puts("KEY7 pressed"); + break; + case 0x40: + puts("KEY8 pressed"); + break; + case 0x80: + puts("KEY9 pressed"); + break; + } + + if (key[0] != 0) { + led[0] = key[0]; + ret = ioctl(fd, PDIUSBD12_SET_LED, key); + if (ret == -1) + goto fail; + } + } +fail: + perror("usb test"); + exit(EXIT_FAILURE); +} +