Skip to content

Driver: Add an Infrared Recorder Unit. #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8f8733a
wip
wurmmi Feb 17, 2020
57d0885
add hdl units
wurmmi Feb 18, 2020
19e4f6a
implement infrared entity
wurmmi Feb 18, 2020
d22ef9b
instantiate counters
wurmmi Feb 18, 2020
9c8555d
fix errors
wurmmi Feb 18, 2020
5134bd3
create infrared_hw.tcl
wurmmi Feb 18, 2020
713f3b8
qsys with version 19.1
wurmmi Feb 18, 2020
048e60c
add ip component into qsys
wurmmi Feb 18, 2020
4deb429
update instantiatation
wurmmi Feb 18, 2020
f79ebf7
fix minor synthesis errors
wurmmi Feb 18, 2020
08a0f48
add vhdltool-config.yaml file
wurmmi Feb 18, 2020
b755326
move the yaml file
wurmmi Feb 18, 2020
916d588
fix width error
wurmmi Feb 19, 2020
b771e30
hook up irq to shared irq line
wurmmi Feb 19, 2020
8e16a88
implement a control register interface
wurmmi Feb 19, 2020
3a76deb
more magic number regs
wurmmi Feb 19, 2020
00632fe
update comments to signal
wurmmi Feb 19, 2020
f9f752d
add infrared driver
wurmmi Feb 19, 2020
e94301d
add testbench
wurmmi Feb 20, 2020
021a98c
more testbench stuff
wurmmi Feb 20, 2020
90aa106
std_ulogic
wurmmi Feb 20, 2020
fea3291
fix irq; testbench
wurmmi Feb 20, 2020
1ea255f
split into ctrl_addr
wurmmi Feb 21, 2020
dbc4499
fix addresses; tb read all regs
wurmmi Feb 21, 2020
0398261
extend sim time
wurmmi Feb 24, 2020
918dc42
fix interrupt generation
wurmmi Feb 24, 2020
7cd36c1
add user space infrared app
wurmmi Feb 24, 2020
f855ffd
read dummy stuff
wurmmi Feb 24, 2020
b99e237
remove debug cerr
wurmmi Feb 24, 2020
a278c0c
remove s0_wait_request; re-generate _hw.tcl
wurmmi Feb 24, 2020
edc412e
if else debug
wurmmi Feb 24, 2020
1d76bbe
remove debug stuff
wurmmi Feb 24, 2020
b06106f
rename modelsim.sh; extend tb
wurmmi Feb 24, 2020
8806478
indentation; simulation time
wurmmi Feb 24, 2020
5ea0ec9
implement ioctrl
wurmmi Feb 24, 2020
92b3a7d
todo comment
wurmmi Feb 24, 2020
df1d55d
add infrared_sender entity
wurmmi Feb 28, 2020
a3946cf
ctrl interface; instantiate;
wurmmi Feb 28, 2020
58a7998
extend tb; fix errors; instantiation
wurmmi Feb 28, 2020
d7d0bfe
fix errors, single replay only
wurmmi Feb 28, 2020
3ea62cf
fix ctrl_access
wurmmi Feb 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ drivers/**/.tmp_versions/
user/**/*.o
user/show_ip/show_ip
user/streaming_sensors/streaming_sensors
user/infrared/infrared

# ModelSim temporary files
work/
Expand All @@ -23,6 +24,7 @@ transcript

# Quartus temporary files
.qsys_edit/
subsystemHMI/
db/
HPSPlatform/
incremental_db/
Expand Down
23 changes: 23 additions & 0 deletions drivers/infrared/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
modulename := infrared

obj-m += $(modulename).o


all:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD)

modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install

clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symvers

deploy: all
scp $(modulename).ko "$(DEPLOYSSH):$(DEPLOYSSHPATH)/$(modulename).ko"
ssh $(DEPLOYSSH) "rmmod $(modulename)";
ssh $(DEPLOYSSH) "insmod $(DEPLOYSSHPATH)/$(modulename).ko";


.PHONY: all clean deploy
265 changes: 265 additions & 0 deletions drivers/infrared/infrared.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
/*
* Terasic DE1-SoC Sensor Driver for Infrared (IR) Sensor
*
* Copyright (C) 2020 Michael Wurm <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
#include <linux/sched/signal.h>

#define DRIVER_NAME "infrared"

#define SIGNAL_EVENT 12 // User space has to listen for this event number (SIGUSR2)

#define NUM_TIMESTAMPS 256
#define NUM_BYTE_TIMESTAMP_DATA (NUM_TIMESTAMPS * sizeof(uint32_t))
#define NUM_BYTE_MAGIC_NRS (4 * sizeof(uint32_t))
#define NUM_BYTE_IRQS_ACTIVE (sizeof(uint32_t))

#define SIZEOF_DATA_T (NUM_BYTE_TIMESTAMP_DATA + \
NUM_BYTE_MAGIC_NRS)

#define MEM_OFFSET_DATA_MAGIC_NR0 (NUM_BYTE_TIMESTAMP_DATA + 0x0)
#define MEM_OFFSET_DATA_MAGIC_NR1 (NUM_BYTE_TIMESTAMP_DATA + 0x4)
#define MEM_OFFSET_DATA_MAGIC_NR2 (NUM_BYTE_TIMESTAMP_DATA + 0x8)
#define MEM_OFFSET_DATA_MAGIC_NR3 (NUM_BYTE_TIMESTAMP_DATA + 0xC)
#define MEM_OFFSET_DATA_IRQ (NUM_BYTE_TIMESTAMP_DATA + 0x10)

/* IO Control (IOCTL) */
#define IOC_SET_PID 0
#define IOC_CMD_SET_PID _IO(4711, IOC_SET_PID)

typedef struct
{
uint32_t timestamp[NUM_TIMESTAMPS];
uint32_t magic_number[4];
} __attribute__((packed)) buffer_t;

struct data
{
void *regs;
buffer_t buffer_data;
uint32_t pid;
uint32_t mode;
uint32_t size;
uint32_t irq_nr;
uint32_t irq_count;
uint32_t irqs_active;
struct miscdevice misc;
};

static irqreturn_t irq_handler(int nr, void *data_ptr)
{
struct data *dev = data_ptr;
struct siginfo info;
struct task_struct *t;

pr_info("INFRARED Interrupt occured.\n");

/* Determine which interrupt occured */
dev->irqs_active = ioread32(dev->regs + MEM_OFFSET_DATA_IRQ);

if (dev->irqs_active == 0x1)
{
dev->irq_count++;
pr_info("INFRARED Received interrupt [Occured %i times so far.]\n", dev->irq_count);
}
else
{
/* Another device asserted the shared interrupt line */
pr_info("INFRARED Shared interrupt wasn't me.");
return IRQ_NONE;
}

/* Send signal to user space */
t = pid_task(find_vpid(dev->pid), PIDTYPE_PID);
if (t == NULL)
{
printk(KERN_ERR "A Task with PID %i does not exist.\n", dev->pid);
return IRQ_HANDLED;
}

memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIGNAL_EVENT;
info.si_code = SI_QUEUE;
info.si_int = 4711;

send_sig_info(SIGNAL_EVENT, &info, t);

return IRQ_HANDLED;
}

/*
* @brief This function gets executed on fread.
*/
static int dev_read(struct file *filep, char *buf, size_t count,
loff_t *offp)
{
struct data *dev = container_of(filep->private_data,
struct data, misc);
int i;

if (SIZEOF_DATA_T != sizeof(dev->buffer_data))
{
printk(KERN_ERR "Data struct buffer_t is not allocated as expected.\n");
return -ENOEXEC;
}

/* check out of bound access */
if ((*offp < 0) || (*offp >= SIZEOF_DATA_T))
return 0;

/* limit number of readable bytes to maximum which is still possible */
if ((*offp + count) > SIZEOF_DATA_T)
count = SIZEOF_DATA_T - *offp;

// Read timestamps from FPGA RAM
for (i = 0; i < NUM_TIMESTAMPS; i++)
{
dev->buffer_data.timestamp[i] = ioread32(dev->regs + i * 4);
}

dev->buffer_data.magic_number[0] = ioread32(dev->regs + MEM_OFFSET_DATA_MAGIC_NR0);
dev->buffer_data.magic_number[1] = ioread32(dev->regs + MEM_OFFSET_DATA_MAGIC_NR1);
dev->buffer_data.magic_number[2] = ioread32(dev->regs + MEM_OFFSET_DATA_MAGIC_NR2);
dev->buffer_data.magic_number[3] = ioread32(dev->regs + MEM_OFFSET_DATA_MAGIC_NR3);

/* copy data from kernel space buffer into user space */
if (count > 0)
count = count - copy_to_user(buf, (char *)&dev->buffer_data + *offp, count);

*offp += count;

return count;
}

/*
* @brief This function gets executed on ioctl.
*/
static long dev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
struct data *dev = container_of(filep->private_data, struct data, misc);

switch (cmd)
{
case IOC_CMD_SET_PID:
/* Get the PID of the currently executing process.
* The `current` variable is defined in linux/sched/signal.h */
dev->pid = task_pid_nr(current);
pr_info("dev_ioctl: Set current PID to %i.\n", dev->pid);
break;
default:
/* it seems like ioctl is also called for all invocations of fread with cmd 0x5041 (TCGETS) */
// pr_info("dev_ioctl: Unknown cmd (%u). Exit.\n", cmd);
break;
}
return 0;
}

static const struct file_operations dev_fops = {
.owner = THIS_MODULE,
.read = dev_read,
.unlocked_ioctl = dev_ioctl};

static int dev_probe(struct platform_device *pdev)
{
struct data *dev;
struct resource *io;
int retval;

/* Allocate memory for private data */
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
platform_set_drvdata(pdev, dev);

/* Get resources */
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->regs = devm_ioremap_resource(&pdev->dev, io);
if (IS_ERR(dev->regs))
return PTR_ERR(dev->regs);

dev->size = io->end - io->start + 1;
dev->misc.name = DRIVER_NAME;
dev->misc.minor = MISC_DYNAMIC_MINOR;
dev->misc.fops = &dev_fops;
dev->misc.parent = &pdev->dev;
retval = misc_register(&dev->misc);
if (retval)
{
dev_err(&pdev->dev, "Register misc device failed!\n");
return retval;
}

/* Get interrupt */
dev->irq_nr = platform_get_irq(pdev, 0);
retval = devm_request_irq(&pdev->dev, dev->irq_nr, &irq_handler,
IRQF_SHARED, dev_name(&pdev->dev), dev);
if (retval != 0)
{
dev_err(&pdev->dev, "Request interrupt failed!\n");
return retval;
}

/* Enable interrupt generation in FPGA device */
// iowrite32(0x3, dev->regs + MEM_OFFSET_BUF_IEN);

dev_info(&pdev->dev, "Infrared (IR) sensor driver loaded!");

return 0;
}

static int dev_remove(struct platform_device *pdev)
{
struct data *dev = platform_get_drvdata(pdev);

/* Disable interrupt generation in FPGA device */
// iowrite32(0x0, dev->regs + MEM_OFFSET_BUF_IEN);
devm_free_irq(&pdev->dev, dev->irq_nr, dev);

misc_deregister(&dev->misc);
platform_set_drvdata(pdev, NULL);

return 0;
}

static const struct of_device_id dev_of_match[] = {
{
.compatible = "wur,infrared-1.0",
},
{},
};
MODULE_DEVICE_TABLE(of, dev_of_match);

static struct platform_driver dev_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(dev_of_match),
},
.probe = dev_probe,
.remove = dev_remove,
};

module_platform_driver(dev_driver);

MODULE_AUTHOR("M.Wurm");
MODULE_DESCRIPTION("Altera/Terasic Infrared (IR) sensor driver");
MODULE_LICENSE("GPL v2");
2 changes: 1 addition & 1 deletion drivers/mpu9250/mpu9250.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#define DRIVER_NAME "mpu9250"

#define SIGNAL_EVENT 10 // User space has to listen for this event number
#define SIGNAL_EVENT 10 // User space has to listen for this event number (SIGUSR1)

#define NUM_BYTE_SENSOR_DATA (3 * 3 * sizeof(uint16_t))
#define NUM_BYTE_TIMESTAMP (2 * sizeof(uint32_t))
Expand Down
Loading