diff options
| author | John Ogness <john.ogness@linutronix.de> | 2019-02-15 13:10:21 +0106 |
|---|---|---|
| committer | John Ogness <john.ogness@linutronix.de> | 2019-02-15 13:10:21 +0106 |
| commit | aed79d1121a9c65dead95fb6ea8c2d8541d01143 (patch) | |
| tree | 6917e9570dfd2d60f357759e096cb013bc0c001c | |
| parent | 2d2484928560dd0ffec90069166b0161cdc84a54 (diff) | |
schulung_tools: hellodriver: add patches for use with leds
These patches are based heavily on the work by Manu to make the
driver lessons more interesting. Rather than create a new driver,
I took his work and created a series of patches that do
interesting modifications to the hello driver.
These patches can be used together with the "leds" program to
do live blinking demonstrations.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
7 files changed, 915 insertions, 0 deletions
diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/0001-hello-change-from-platform-to-pci-bus.patch b/schulung_tools/drivers/modules/hellodriver/patches-leds/0001-hello-change-from-platform-to-pci-bus.patch new file mode 100644 index 0000000..35dc817 --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/0001-hello-change-from-platform-to-pci-bus.patch @@ -0,0 +1,185 @@ +From 28357d61e0ec39851ca88a09b04ce876b8758448 Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Fri, 15 Feb 2019 12:11:27 +0100 +Subject: [PATCH 2/7] hello: change from platform to pci bus + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +--- + hello.c | 89 +++++++++++++++++++++++++++++++---------------------------------- + 1 file changed, 43 insertions(+), 46 deletions(-) + +diff --git a/hello.c b/hello.c +index 7f78d06..db50302 100644 +--- a/hello.c ++++ b/hello.c +@@ -5,9 +5,8 @@ + #include <linux/uaccess.h> + #include <linux/slab.h> + #include <linux/device.h> +-#include <linux/platform_device.h> ++#include <linux/pci.h> + #include <linux/cdev.h> +-#include <linux/of.h> + + struct hello_dev { + struct device *dev; +@@ -77,7 +76,7 @@ static const struct file_operations hello_fops = { + .write = hello_write, + }; + +-static int hello_probe(struct platform_device *pdev) ++static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { + struct hello_dev *hello; + struct device *dev; +@@ -90,15 +89,7 @@ static int hello_probe(struct platform_device *pdev) + return -ENOMEM; + } + +-#ifdef CONFIG_OF +- ret = of_property_read_u32(pdev->dev.of_node, "index", &hello->minor); +- if (ret < 0) { +- dev_err(&pdev->dev, "no index specified\n"); +- goto err_out; +- } +-#else +- hello->minor = (unsigned)pdev->id; +-#endif ++ hello->minor = 1; + + if (hello->minor >= HELLO_MAX_DEVICES) { + dev_err(&pdev->dev, "invalid index: %u\n", hello->minor); +@@ -107,7 +98,27 @@ static int hello_probe(struct platform_device *pdev) + } + + hello->dev = &pdev->dev; +- platform_set_drvdata(pdev, hello); ++ pci_set_drvdata(pdev, hello); ++ ++ ret = pci_enable_device(pdev); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to enable device\n"); ++ goto err_drvdata; ++ } ++ ++ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { ++ dev_err(&pdev->dev, "failed to find base address\n"); ++ ret = -ENODEV; ++ goto err_enable; ++ } ++ ++ ret = pci_request_regions(pdev, "hello"); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request resources\n"); ++ goto err_enable; ++ } ++ ++ pci_set_master(pdev); + + devt = MKDEV(MAJOR(hello_devt), hello->minor); + +@@ -116,7 +127,7 @@ static int hello_probe(struct platform_device *pdev) + ret = cdev_add(&hello->cdev, devt, 1); + if (ret != 0) { + dev_err(&pdev->dev, "cdev_add failed\n"); +- goto err_drvdata; ++ goto err_regions; + } + + dev = device_create(hello_class, &pdev->dev, devt, hello, +@@ -133,43 +144,41 @@ static int hello_probe(struct platform_device *pdev) + + err_cdev: + cdev_del(&hello->cdev); ++err_regions: ++ pci_release_regions(pdev); ++err_enable: ++ pci_disable_device(pdev); + err_drvdata: +- platform_set_drvdata(pdev, NULL); +-err_out: ++ pci_set_drvdata(pdev, NULL); + return ret; + } + +-static int hello_remove(struct platform_device *pdev) ++static void hello_remove(struct pci_dev *pdev) + { +- struct hello_dev *hello = platform_get_drvdata(pdev); ++ struct hello_dev *hello = pci_get_drvdata(pdev); + + device_destroy(hello_class, MKDEV(MAJOR(hello_devt), hello->minor)); + cdev_del(&hello->cdev); +- platform_set_drvdata(pdev, NULL); ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++ pci_set_drvdata(pdev, NULL); + + dev_info(&pdev->dev, "GOODBYE! I was hello device %d!\n", hello->minor); +- +- return 0; + } + +-static const struct of_device_id hello_match[] = { +- { .compatible = "virtual,hello", }, ++static const struct pci_device_id hello_id_table[] = { ++ { 0x1af4, 0x1110, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0 }, + { /* end of table */ } + }; ++MODULE_DEVICE_TABLE(pci, hello_id_table); + +-static struct platform_driver hello_driver = { +- .driver = { +- .name = "hello", +- .of_match_table = hello_match, +- }, ++static struct pci_driver hello_driver = { ++ .name = "hello", ++ .id_table = hello_id_table, + .probe = hello_probe, + .remove = hello_remove, + }; + +-#ifndef CONFIG_OF +-static struct platform_device *pdevs[3]; +-#endif +- + static int __init hello_init(void) + { + int ret; +@@ -187,16 +196,10 @@ static int __init hello_init(void) + goto err_region; + } + +- ret = platform_driver_register(&hello_driver); ++ ret = pci_register_driver(&hello_driver); + if (ret != 0) + goto err_class; + +-#ifndef CONFIG_OF +- pdevs[0] = platform_device_register_simple("hello", 1, NULL, 0); +- pdevs[1] = platform_device_register_simple("hello", 3, NULL, 0); +- pdevs[2] = platform_device_register_simple("hello", 5, NULL, 0); +-#endif +- + return 0; + + err_class: +@@ -210,13 +213,7 @@ static void __exit hello_exit(void) + { + printk(KERN_INFO "%s\n", __func__); + +-#ifndef CONFIG_OF +- platform_device_unregister(pdevs[0]); +- platform_device_unregister(pdevs[1]); +- platform_device_unregister(pdevs[2]); +-#endif +- +- platform_driver_unregister(&hello_driver); ++ pci_unregister_driver(&hello_driver); + class_destroy(hello_class); + unregister_chrdev_region(hello_devt, HELLO_MAX_DEVICES); + } +-- +2.11.0 + diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/0002-hello-add-pci-memory-mapping.patch b/schulung_tools/drivers/modules/hellodriver/patches-leds/0002-hello-add-pci-memory-mapping.patch new file mode 100644 index 0000000..0a11a57 --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/0002-hello-add-pci-memory-mapping.patch @@ -0,0 +1,64 @@ +From 3afec946845a02a8fce94d00abda9b4c8abcbce0 Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Fri, 15 Feb 2019 11:03:59 +0106 +Subject: [PATCH 3/7] hello: add pci memory mapping + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +--- + hello.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/hello.c b/hello.c +index db50302..58a64e5 100644 +--- a/hello.c ++++ b/hello.c +@@ -12,6 +12,7 @@ struct hello_dev { + struct device *dev; + struct cdev cdev; + unsigned int minor; ++ void __iomem *mem; + }; + + #define HELLO_MAX_DEVICES 10 +@@ -120,6 +121,12 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + pci_set_master(pdev); + ++ hello->mem = pci_iomap(pdev, 2, 0); ++ if (!hello->mem) { ++ ret = -ENOMEM; ++ goto err_regions; ++ } ++ + devt = MKDEV(MAJOR(hello_devt), hello->minor); + + cdev_init(&hello->cdev, &hello_fops); +@@ -127,7 +134,7 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + ret = cdev_add(&hello->cdev, devt, 1); + if (ret != 0) { + dev_err(&pdev->dev, "cdev_add failed\n"); +- goto err_regions; ++ goto err_iomap; + } + + dev = device_create(hello_class, &pdev->dev, devt, hello, +@@ -144,6 +151,8 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + err_cdev: + cdev_del(&hello->cdev); ++err_iomap: ++ pci_iounmap(pdev, hello->mem); + err_regions: + pci_release_regions(pdev); + err_enable: +@@ -159,6 +168,7 @@ static void hello_remove(struct pci_dev *pdev) + + device_destroy(hello_class, MKDEV(MAJOR(hello_devt), hello->minor)); + cdev_del(&hello->cdev); ++ pci_iounmap(pdev, hello->mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +-- +2.11.0 + diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/0003-hello-add-led-toggling-via-chardev-read-write.patch b/schulung_tools/drivers/modules/hellodriver/patches-leds/0003-hello-add-led-toggling-via-chardev-read-write.patch new file mode 100644 index 0000000..8f81e39 --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/0003-hello-add-led-toggling-via-chardev-read-write.patch @@ -0,0 +1,56 @@ +From c7a4c4448632af43383818654dd79d2251b27e3e Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Fri, 15 Feb 2019 11:04:56 +0106 +Subject: [PATCH 4/7] hello: add led toggling via chardev read/write + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +--- + hello.c | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/hello.c b/hello.c +index 58a64e5..f664121 100644 +--- a/hello.c ++++ b/hello.c +@@ -61,11 +61,37 @@ static ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l) + return len; + } + ++static void toggle_led(struct hello_dev *hello, int offset) ++{ ++ if (readb(hello->mem + offset)) ++ writeb(0, hello->mem + offset); ++ else ++ writeb(0xff, hello->mem + offset); ++} ++ + static ssize_t hello_write(struct file *f, const char __user *u, size_t s, + loff_t *l) + { + struct hello_dev *hello = f->private_data; +- dev_info(hello->dev, "%s: size=%zu offset=%llu\n", __func__, s, *l); ++ size_t sz = s; ++ char buf[32]; ++ ++ if (sz >= sizeof(buf)) ++ sz = sizeof(buf) - 1; ++ if (copy_from_user(buf, u, sz) != 0) ++ return -EFAULT; ++ buf[sz] = 0; ++ ++ dev_info(hello->dev, "%s: size=%zu offset=%llu buf=%s\n", __func__, ++ s, *l, buf); ++ ++ if (strstarts(buf, "heartbeat")) ++ toggle_led(hello, 0); ++ else if (strstarts(buf, "net")) ++ toggle_led(hello, 1); ++ else if (strstarts(buf, "disk")) ++ toggle_led(hello, 2); ++ + return s; + } + +-- +2.11.0 + diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/0004-hello-add-led-toggling-via-chardev-ioctl.patch b/schulung_tools/drivers/modules/hellodriver/patches-leds/0004-hello-add-led-toggling-via-chardev-ioctl.patch new file mode 100644 index 0000000..a67bf98 --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/0004-hello-add-led-toggling-via-chardev-ioctl.patch @@ -0,0 +1,124 @@ +From be59ddb43fbf039ed0bc848ac56b7f72f7a619c8 Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Fri, 15 Feb 2019 11:07:10 +0106 +Subject: [PATCH 5/7] hello: add led toggling via chardev ioctl + +Compile userspace application with: + +$ gcc -Wall -Werror hello-led.c -ohello-led + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +--- + hello-led.c | 38 ++++++++++++++++++++++++++++++++++++++ + hello.c | 22 ++++++++++++++++++++++ + hello.h | 7 +++++++ + 3 files changed, 67 insertions(+) + create mode 100644 hello-led.c + create mode 100644 hello.h + +diff --git a/hello-led.c b/hello-led.c +new file mode 100644 +index 0000000..43230cd +--- /dev/null ++++ b/hello-led.c +@@ -0,0 +1,38 @@ ++#include <stdio.h> ++#include <string.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <unistd.h> ++#include <sys/ioctl.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include "hello.h" ++ ++int main(int argc, char *argv[]) ++{ ++ int fd; ++ ++ if (argc != 3) { ++ fprintf(stderr, "usage: %s <device> <led>\n", argv[0]); ++ return 1; ++ } ++ ++ fd = open(argv[1], O_RDWR); ++ if (fd < 0) { ++ fprintf(stderr, "open() failed: %s\n", strerror(errno)); ++ return 1; ++ } ++ ++ if (strcmp(argv[2], "heartbeat") == 0) ++ ioctl(fd, HELLO_IOCTL_TOGGLE_LED, 0); ++ else if (strcmp(argv[2], "net") == 0) ++ ioctl(fd, HELLO_IOCTL_TOGGLE_LED, 1); ++ else if (strcmp(argv[2], "disk") == 0) ++ ioctl(fd, HELLO_IOCTL_TOGGLE_LED, 2); ++ else ++ fprintf(stderr, "unknown led\n"); ++ ++ close(fd); ++ ++ return 0; ++} +diff --git a/hello.c b/hello.c +index f664121..c42c75f 100644 +--- a/hello.c ++++ b/hello.c +@@ -7,6 +7,7 @@ + #include <linux/device.h> + #include <linux/pci.h> + #include <linux/cdev.h> ++#include "hello.h" + + struct hello_dev { + struct device *dev; +@@ -95,12 +96,33 @@ static ssize_t hello_write(struct file *f, const char __user *u, size_t s, + return s; + } + ++static long hello_ioctl(struct file *f, unsigned int cmd, unsigned long arg) ++{ ++ struct hello_dev *hello = f->private_data; ++ u32 val; ++ ++ dev_info(hello->dev, "%s: cmd=%u arg=%lu\n", __func__, cmd, arg); ++ ++ switch (cmd) { ++ case HELLO_IOCTL_TOGGLE_LED: ++ val = arg; ++ if (val >= 0 && val <= 2) ++ toggle_led(hello, val); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static const struct file_operations hello_fops = { + .owner = THIS_MODULE, + .open = hello_open, + .release = hello_release, + .read = hello_read, + .write = hello_write, ++ .unlocked_ioctl = hello_ioctl, + }; + + static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +diff --git a/hello.h b/hello.h +new file mode 100644 +index 0000000..cb172d9 +--- /dev/null ++++ b/hello.h +@@ -0,0 +1,7 @@ ++#ifndef HELLO_H ++#define HELLO_H ++ ++#define HELLO_BASE 0x9F ++#define HELLO_IOCTL_TOGGLE_LED _IOW(HELLO_BASE, 0x00, unsigned int) ++ ++#endif /* HELLO_H */ +-- +2.11.0 + diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/0005-hello-add-led-toggling-via-leds-subsystem.patch b/schulung_tools/drivers/modules/hellodriver/patches-leds/0005-hello-add-led-toggling-via-leds-subsystem.patch new file mode 100644 index 0000000..32f37ce --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/0005-hello-add-led-toggling-via-leds-subsystem.patch @@ -0,0 +1,142 @@ +From 3caece4ff394938f7544b994d35e784e2ce617cb Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Fri, 15 Feb 2019 11:10:09 +0106 +Subject: [PATCH 6/7] hello: add led toggling via leds subsystem + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +--- + hello.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 90 insertions(+) + +diff --git a/hello.c b/hello.c +index c42c75f..f9809f3 100644 +--- a/hello.c ++++ b/hello.c +@@ -7,6 +7,7 @@ + #include <linux/device.h> + #include <linux/pci.h> + #include <linux/cdev.h> ++#include <linux/leds.h> + #include "hello.h" + + struct hello_dev { +@@ -14,6 +15,10 @@ struct hello_dev { + struct cdev cdev; + unsigned int minor; + void __iomem *mem; ++ ++ struct led_classdev led_heartbeat; ++ struct led_classdev led_net; ++ struct led_classdev led_disk; + }; + + #define HELLO_MAX_DEVICES 10 +@@ -125,6 +130,67 @@ static const struct file_operations hello_fops = { + .unlocked_ioctl = hello_ioctl, + }; + ++static void set_brightness(struct hello_dev *hello, int offset, ++ enum led_brightness b) ++{ ++ if (b) ++ writeb(0xff, hello->mem + offset); ++ else ++ writeb(0, hello->mem + offset); ++} ++ ++static enum led_brightness get_brightness(struct hello_dev *hello, int offset) ++{ ++ if (readb(hello->mem + offset)) ++ return 1; ++ return 0; ++} ++ ++static void hello_led_heartbeat_set(struct led_classdev *ldev, ++ enum led_brightness b) ++{ ++ struct hello_dev *hello = container_of(ldev, struct hello_dev, ++ led_heartbeat); ++ set_brightness(hello, 0, b); ++} ++ ++static enum led_brightness hello_led_heartbeat_get(struct led_classdev *ldev) ++{ ++ struct hello_dev *hello = container_of(ldev, struct hello_dev, ++ led_heartbeat); ++ return get_brightness(hello, 0); ++} ++ ++static void hello_led_net_set(struct led_classdev *ldev, ++ enum led_brightness b) ++{ ++ struct hello_dev *hello = container_of(ldev, struct hello_dev, ++ led_net); ++ set_brightness(hello, 1, b); ++} ++ ++static enum led_brightness hello_led_net_get(struct led_classdev *ldev) ++{ ++ struct hello_dev *hello = container_of(ldev, struct hello_dev, ++ led_net); ++ return get_brightness(hello, 1); ++} ++ ++static void hello_led_disk_set(struct led_classdev *ldev, ++ enum led_brightness b) ++{ ++ struct hello_dev *hello = container_of(ldev, struct hello_dev, ++ led_disk); ++ set_brightness(hello, 2, b); ++} ++ ++static enum led_brightness hello_led_disk_get(struct led_classdev *ldev) ++{ ++ struct hello_dev *hello = container_of(ldev, struct hello_dev, ++ led_disk); ++ return get_brightness(hello, 2); ++} ++ + static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { + struct hello_dev *hello; +@@ -193,6 +259,27 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + goto err_cdev; + } + ++ hello->led_heartbeat.name = "heartbeat"; ++ hello->led_heartbeat.brightness = get_brightness(hello, 0); ++ hello->led_heartbeat.max_brightness = 1; ++ hello->led_heartbeat.brightness_set = hello_led_heartbeat_set; ++ hello->led_heartbeat.brightness_get = hello_led_heartbeat_get; ++ led_classdev_register(&pdev->dev, &hello->led_heartbeat); ++ ++ hello->led_net.name = "net"; ++ hello->led_net.brightness = get_brightness(hello, 2); ++ hello->led_net.max_brightness = 1; ++ hello->led_net.brightness_set = hello_led_net_set; ++ hello->led_net.brightness_get = hello_led_net_get; ++ led_classdev_register(&pdev->dev, &hello->led_net); ++ ++ hello->led_disk.name = "disk"; ++ hello->led_disk.brightness = get_brightness(hello, 2); ++ hello->led_disk.max_brightness = 1; ++ hello->led_disk.brightness_set = hello_led_disk_set; ++ hello->led_disk.brightness_get = hello_led_disk_get; ++ led_classdev_register(&pdev->dev, &hello->led_disk); ++ + dev_info(&pdev->dev, "HELLO! I am hello device %d!\n", hello->minor); + + return 0; +@@ -214,6 +301,9 @@ static void hello_remove(struct pci_dev *pdev) + { + struct hello_dev *hello = pci_get_drvdata(pdev); + ++ led_classdev_unregister(&hello->led_disk); ++ led_classdev_unregister(&hello->led_net); ++ led_classdev_unregister(&hello->led_heartbeat); + device_destroy(hello_class, MKDEV(MAJOR(hello_devt), hello->minor)); + cdev_del(&hello->cdev); + pci_iounmap(pdev, hello->mem); +-- +2.11.0 + diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/0006-hello-remove-chardev-use-only-leds-subsystem.patch b/schulung_tools/drivers/modules/hellodriver/patches-leds/0006-hello-remove-chardev-use-only-leds-subsystem.patch new file mode 100644 index 0000000..3274ccd --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/0006-hello-remove-chardev-use-only-leds-subsystem.patch @@ -0,0 +1,338 @@ +From 5f05842b160249563a7e4965aaa01998e562f487 Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Fri, 15 Feb 2019 11:33:24 +0100 +Subject: [PATCH 7/7] hello: remove chardev, use only leds subsystem + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +--- + hello-led.c | 38 ------------- + hello.c | 181 +----------------------------------------------------------- + hello.h | 7 --- + 3 files changed, 3 insertions(+), 223 deletions(-) + delete mode 100644 hello-led.c + delete mode 100644 hello.h + +diff --git a/hello-led.c b/hello-led.c +deleted file mode 100644 +index 43230cd..0000000 +--- a/hello-led.c ++++ /dev/null +@@ -1,38 +0,0 @@ +-#include <stdio.h> +-#include <string.h> +-#include <errno.h> +-#include <fcntl.h> +-#include <unistd.h> +-#include <sys/ioctl.h> +-#include <sys/types.h> +-#include <sys/stat.h> +-#include "hello.h" +- +-int main(int argc, char *argv[]) +-{ +- int fd; +- +- if (argc != 3) { +- fprintf(stderr, "usage: %s <device> <led>\n", argv[0]); +- return 1; +- } +- +- fd = open(argv[1], O_RDWR); +- if (fd < 0) { +- fprintf(stderr, "open() failed: %s\n", strerror(errno)); +- return 1; +- } +- +- if (strcmp(argv[2], "heartbeat") == 0) +- ioctl(fd, HELLO_IOCTL_TOGGLE_LED, 0); +- else if (strcmp(argv[2], "net") == 0) +- ioctl(fd, HELLO_IOCTL_TOGGLE_LED, 1); +- else if (strcmp(argv[2], "disk") == 0) +- ioctl(fd, HELLO_IOCTL_TOGGLE_LED, 2); +- else +- fprintf(stderr, "unknown led\n"); +- +- close(fd); +- +- return 0; +-} +diff --git a/hello.c b/hello.c +index f9809f3..52df6d7 100644 +--- a/hello.c ++++ b/hello.c +@@ -1,19 +1,12 @@ + // SPDX-License-Identifier: GPL-2.0 + #include <linux/init.h> + #include <linux/module.h> +-#include <linux/fs.h> +-#include <linux/uaccess.h> +-#include <linux/slab.h> + #include <linux/device.h> + #include <linux/pci.h> +-#include <linux/cdev.h> + #include <linux/leds.h> +-#include "hello.h" + + struct hello_dev { + struct device *dev; +- struct cdev cdev; +- unsigned int minor; + void __iomem *mem; + + struct led_classdev led_heartbeat; +@@ -21,115 +14,6 @@ struct hello_dev { + struct led_classdev led_disk; + }; + +-#define HELLO_MAX_DEVICES 10 +- +-static struct class *hello_class; +-static dev_t hello_devt; +- +-static int hello_open(struct inode *node, struct file *f) +-{ +- struct cdev *cd = node->i_cdev; +- struct hello_dev *hello = container_of(cd, struct hello_dev, cdev); +- dev_info(hello->dev, "%s\n", __func__); +- f->private_data = hello; +- return 0; +-} +- +-static int hello_release(struct inode *node, struct file *f) +-{ +- struct hello_dev *hello = f->private_data; +- dev_info(hello->dev, "%s\n", __func__); +- f->private_data = NULL; +- return 0; +-} +- +-static ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l) +-{ +- struct hello_dev *hello = f->private_data; +- char buf[10]; +- size_t len; +- +- dev_info(hello->dev, "%s: size=%zu offset=%llu\n", __func__, s, *l); +- +- if (*l >= 40) +- return 0; +- +- len = snprintf(buf, sizeof(buf), "hello:%d\n", hello->minor); +- +- if (s < len) +- len = s; +- +- if (copy_to_user(u, buf, len) != 0) +- return -EFAULT; +- +- *l += len; +- +- return len; +-} +- +-static void toggle_led(struct hello_dev *hello, int offset) +-{ +- if (readb(hello->mem + offset)) +- writeb(0, hello->mem + offset); +- else +- writeb(0xff, hello->mem + offset); +-} +- +-static ssize_t hello_write(struct file *f, const char __user *u, size_t s, +- loff_t *l) +-{ +- struct hello_dev *hello = f->private_data; +- size_t sz = s; +- char buf[32]; +- +- if (sz >= sizeof(buf)) +- sz = sizeof(buf) - 1; +- if (copy_from_user(buf, u, sz) != 0) +- return -EFAULT; +- buf[sz] = 0; +- +- dev_info(hello->dev, "%s: size=%zu offset=%llu buf=%s\n", __func__, +- s, *l, buf); +- +- if (strstarts(buf, "heartbeat")) +- toggle_led(hello, 0); +- else if (strstarts(buf, "net")) +- toggle_led(hello, 1); +- else if (strstarts(buf, "disk")) +- toggle_led(hello, 2); +- +- return s; +-} +- +-static long hello_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +-{ +- struct hello_dev *hello = f->private_data; +- u32 val; +- +- dev_info(hello->dev, "%s: cmd=%u arg=%lu\n", __func__, cmd, arg); +- +- switch (cmd) { +- case HELLO_IOCTL_TOGGLE_LED: +- val = arg; +- if (val >= 0 && val <= 2) +- toggle_led(hello, val); +- break; +- default: +- return -EINVAL; +- } +- +- return 0; +-} +- +-static const struct file_operations hello_fops = { +- .owner = THIS_MODULE, +- .open = hello_open, +- .release = hello_release, +- .read = hello_read, +- .write = hello_write, +- .unlocked_ioctl = hello_ioctl, +-}; +- + static void set_brightness(struct hello_dev *hello, int offset, + enum led_brightness b) + { +@@ -194,8 +78,6 @@ static enum led_brightness hello_led_disk_get(struct led_classdev *ldev) + static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { + struct hello_dev *hello; +- struct device *dev; +- dev_t devt; + int ret; + + hello = devm_kzalloc(&pdev->dev, sizeof(*hello), GFP_KERNEL); +@@ -204,14 +86,6 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + return -ENOMEM; + } + +- hello->minor = 1; +- +- if (hello->minor >= HELLO_MAX_DEVICES) { +- dev_err(&pdev->dev, "invalid index: %u\n", hello->minor); +- ret = -EINVAL; +- goto err_out; +- } +- + hello->dev = &pdev->dev; + pci_set_drvdata(pdev, hello); + +@@ -241,24 +115,6 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + goto err_regions; + } + +- devt = MKDEV(MAJOR(hello_devt), hello->minor); +- +- cdev_init(&hello->cdev, &hello_fops); +- hello->cdev.owner = THIS_MODULE; +- ret = cdev_add(&hello->cdev, devt, 1); +- if (ret != 0) { +- dev_err(&pdev->dev, "cdev_add failed\n"); +- goto err_iomap; +- } +- +- dev = device_create(hello_class, &pdev->dev, devt, hello, +- "hello%d", hello->minor); +- if (IS_ERR(dev)) { +- dev_err(&pdev->dev, "device_create failed\n"); +- ret = PTR_ERR(dev); +- goto err_cdev; +- } +- + hello->led_heartbeat.name = "heartbeat"; + hello->led_heartbeat.brightness = get_brightness(hello, 0); + hello->led_heartbeat.max_brightness = 1; +@@ -280,14 +136,10 @@ static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + hello->led_disk.brightness_get = hello_led_disk_get; + led_classdev_register(&pdev->dev, &hello->led_disk); + +- dev_info(&pdev->dev, "HELLO! I am hello device %d!\n", hello->minor); ++ dev_info(&pdev->dev, "HELLO! I am hello device!\n"); + + return 0; + +-err_cdev: +- cdev_del(&hello->cdev); +-err_iomap: +- pci_iounmap(pdev, hello->mem); + err_regions: + pci_release_regions(pdev); + err_enable: +@@ -304,14 +156,12 @@ static void hello_remove(struct pci_dev *pdev) + led_classdev_unregister(&hello->led_disk); + led_classdev_unregister(&hello->led_net); + led_classdev_unregister(&hello->led_heartbeat); +- device_destroy(hello_class, MKDEV(MAJOR(hello_devt), hello->minor)); +- cdev_del(&hello->cdev); + pci_iounmap(pdev, hello->mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + +- dev_info(&pdev->dev, "GOODBYE! I was hello device %d!\n", hello->minor); ++ dev_info(&pdev->dev, "GOODBYE! I was hello device!\n"); + } + + static const struct pci_device_id hello_id_table[] = { +@@ -329,32 +179,9 @@ static struct pci_driver hello_driver = { + + static int __init hello_init(void) + { +- int ret; +- + printk(KERN_INFO "%s\n", __func__); + +- ret = alloc_chrdev_region(&hello_devt, 0, HELLO_MAX_DEVICES, "hello"); +- if (ret < 0) +- return ret; +- +- hello_class = class_create(THIS_MODULE, "hello"); +- if (IS_ERR(hello_class)) { +- printk(KERN_ERR "%s: failed to create class\n", __func__); +- ret = PTR_ERR(hello_class); +- goto err_region; +- } +- +- ret = pci_register_driver(&hello_driver); +- if (ret != 0) +- goto err_class; +- +- return 0; +- +-err_class: +- class_destroy(hello_class); +-err_region: +- unregister_chrdev_region(hello_devt, HELLO_MAX_DEVICES); +- return ret; ++ return pci_register_driver(&hello_driver); + } + + static void __exit hello_exit(void) +@@ -362,8 +189,6 @@ static void __exit hello_exit(void) + printk(KERN_INFO "%s\n", __func__); + + pci_unregister_driver(&hello_driver); +- class_destroy(hello_class); +- unregister_chrdev_region(hello_devt, HELLO_MAX_DEVICES); + } + + module_init(hello_init); +diff --git a/hello.h b/hello.h +deleted file mode 100644 +index cb172d9..0000000 +--- a/hello.h ++++ /dev/null +@@ -1,7 +0,0 @@ +-#ifndef HELLO_H +-#define HELLO_H +- +-#define HELLO_BASE 0x9F +-#define HELLO_IOCTL_TOGGLE_LED _IOW(HELLO_BASE, 0x00, unsigned int) +- +-#endif /* HELLO_H */ +-- +2.11.0 + diff --git a/schulung_tools/drivers/modules/hellodriver/patches-leds/README b/schulung_tools/drivers/modules/hellodriver/patches-leds/README new file mode 100644 index 0000000..51bbffa --- /dev/null +++ b/schulung_tools/drivers/modules/hellodriver/patches-leds/README @@ -0,0 +1,6 @@ +This set of patches show how different subsystems can be used +by the driver to communicate with the hardware and to present +itself to the user. + +For live demonstrations with actual blinking leds, use the +"leds" program. (See the README there for details.) |
