m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
path: root/char.c
blob: b13b08ae0e695c730de60374c94a55ed1e41fa34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "char.h"

#include "linux/cdev.h"
#include "linux/device.h"
#include "linux/fs.h"

#include "util.h"
#include "pci.h"

#define DOOMDEV_COUNT 256
#define DOOMDEV_NAME "doom"

dev_t first;
int major;
int next_minor = 0;

long doom_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	return -1;
}

int doom_open(struct inode *inode, struct file *filp)
{
	return -1;
}

struct file_operations doomdev_fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = doom_ioctl,
	.compat_ioctl = doom_ioctl,
	.open = doom_open
};
	
struct class *doom_class;

int new_doomdev(struct pci_dev *dev)
{
	int err = 0;
	int minor;
	dev_t devt;
	struct cdev *doom_cdev;
	struct device *doomdev;
	struct doom_data *doom_data;
	if (next_minor >= DOOMDEV_COUNT) {
		return -ENOMEM;
	}

	doom_cdev = cdev_alloc();
	if (doom_cdev == NULL) {
		return -ENOMEM;
	}

	doom_cdev->ops = &doomdev_fops;
	ORFAIL(cdev_add(doom_cdev, first, 1), error_add);
	minor = next_minor++;
	doom_data = kmalloc(sizeof(*doom_data), GFP_KERNEL);
	doom_data->minor = minor;
	pci_set_drvdata(dev, doom_data);
	devt = MKDEV(major, minor);
	ORFAIL_PTR(device_create(doom_class, NULL, devt, NULL,
				"doom%d", minor),
			doomdev, error_create);

error_create:
	cdev_del(doom_cdev);
error_add:
	return err;
}

void destroy_doomdev(struct pci_dev *dev)
{
	struct doom_data *data;
	data = pci_get_drvdata(dev);
	device_destroy(doom_class, MKDEV(major, data->minor));
	kfree(data);
}

int char_init(void)
{
	int err = 0;
	ORFAIL(alloc_chrdev_region(&first, 0, DOOMDEV_COUNT, DOOMDEV_NAME),
			error_region);
	major = MAJOR(first);
	doom_class = class_create(THIS_MODULE, "doom");
	if (IS_ERR(doom_class)) {
		err = PTR_ERR(doom_class);
		goto error_create;
	}

error_create:
	unregister_chrdev_region(first, DOOMDEV_COUNT);
error_region:
	return err;
}

void char_cleanup(void)
{
	unregister_chrdev_region(first, DOOMDEV_COUNT);
	class_unregister(doom_class);
}