1
1
/*
2
2
* Copyright (C) 2010 Broadcom
3
3
* Copyright (C) 2015 Noralf Trønnes
4
+ * Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
4
5
*
5
6
* This program is free software; you can redistribute it and/or modify
6
7
* it under the terms of the GNU General Public License version 2 as
7
8
* published by the Free Software Foundation.
8
9
*
9
10
*/
10
11
11
- #define pr_fmt (fmt ) KBUILD_MODNAME ": " fmt
12
-
13
12
#include <linux/cdev.h>
14
13
#include <linux/device.h>
15
14
#include <linux/fs.h>
19
18
#include <linux/slab.h>
20
19
#include <linux/uaccess.h>
21
20
#include <linux/compat.h>
21
+ #include <linux/miscdevice.h>
22
22
#include <soc/bcm2835/raspberrypi-firmware.h>
23
23
24
- #define MBOX_CHAN_PROPERTY 8
25
-
24
+ #define MODULE_NAME "vcio"
26
25
#define VCIO_IOC_MAGIC 100
27
26
#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
28
27
#ifdef CONFIG_COMPAT
29
28
#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
30
29
#endif
31
30
32
- static struct {
33
- dev_t devt ;
34
- struct cdev cdev ;
35
- struct class * class ;
31
+ struct vcio_data {
36
32
struct rpi_firmware * fw ;
37
- } vcio ;
33
+ struct miscdevice misc_dev ;
34
+ };
38
35
39
- static int vcio_user_property_list (void * user )
36
+ static int vcio_user_property_list (struct vcio_data * vcio , void * user )
40
37
{
41
38
u32 * buf , size ;
42
39
int ret ;
@@ -55,7 +52,7 @@ static int vcio_user_property_list(void *user)
55
52
}
56
53
57
54
/* Strip off protocol encapsulation */
58
- ret = rpi_firmware_property_list (vcio . fw , & buf [2 ], size - 12 );
55
+ ret = rpi_firmware_property_list (vcio -> fw , & buf [2 ], size - 12 );
59
56
if (ret ) {
60
57
kfree (buf );
61
58
return ret ;
@@ -87,9 +84,12 @@ static int vcio_device_release(struct inode *inode, struct file *file)
87
84
static long vcio_device_ioctl (struct file * file , unsigned int ioctl_num ,
88
85
unsigned long ioctl_param )
89
86
{
87
+ struct vcio_data * vcio = container_of (file -> private_data ,
88
+ struct vcio_data , misc_dev );
89
+
90
90
switch (ioctl_num ) {
91
91
case IOCTL_MBOX_PROPERTY :
92
- return vcio_user_property_list ((void * )ioctl_param );
92
+ return vcio_user_property_list (vcio , (void * )ioctl_param );
93
93
default :
94
94
pr_err ("unknown ioctl: %x\n" , ioctl_num );
95
95
return - EINVAL ;
@@ -100,9 +100,12 @@ static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
100
100
static long vcio_device_compat_ioctl (struct file * file , unsigned int ioctl_num ,
101
101
unsigned long ioctl_param )
102
102
{
103
+ struct vcio_data * vcio = container_of (file -> private_data ,
104
+ struct vcio_data , misc_dev );
105
+
103
106
switch (ioctl_num ) {
104
107
case IOCTL_MBOX_PROPERTY32 :
105
- return vcio_user_property_list (compat_ptr (ioctl_param ));
108
+ return vcio_user_property_list (vcio , compat_ptr (ioctl_param ));
106
109
default :
107
110
pr_err ("unknown ioctl: %x\n" , ioctl_num );
108
111
return - EINVAL ;
@@ -119,77 +122,65 @@ const struct file_operations vcio_fops = {
119
122
.release = vcio_device_release ,
120
123
};
121
124
122
- static int __init vcio_init ( void )
125
+ static int vcio_probe ( struct platform_device * pdev )
123
126
{
124
- struct device_node * np ;
125
- static struct device * dev ;
126
- int ret ;
127
-
128
- np = of_find_compatible_node (NULL , NULL ,
129
- "raspberrypi,bcm2835-firmware" );
130
- if (!of_device_is_available (np ))
131
- return - ENODEV ;
132
-
133
- vcio .fw = rpi_firmware_get (np );
134
- if (!vcio .fw )
135
- return - ENODEV ;
136
-
137
- ret = alloc_chrdev_region (& vcio .devt , 0 , 1 , "vcio" );
138
- if (ret ) {
139
- pr_err ("failed to allocate device number\n" );
140
- return ret ;
141
- }
142
-
143
- cdev_init (& vcio .cdev , & vcio_fops );
144
- vcio .cdev .owner = THIS_MODULE ;
145
- ret = cdev_add (& vcio .cdev , vcio .devt , 1 );
146
- if (ret ) {
147
- pr_err ("failed to register device\n" );
148
- goto err_unregister_chardev ;
149
- }
127
+ struct device * dev = & pdev -> dev ;
128
+ struct device_node * np = dev -> of_node ;
129
+ struct device_node * fw_node ;
130
+ struct rpi_firmware * fw ;
131
+ struct vcio_data * vcio ;
150
132
151
- /*
152
- * Create sysfs entries
153
- * 'bcm2708_vcio' is used for backwards compatibility so we don't break
154
- * userspace. Raspian has a udev rule that changes the permissions.
155
- */
156
- vcio .class = class_create (THIS_MODULE , "bcm2708_vcio" );
157
- if (IS_ERR (vcio .class )) {
158
- ret = PTR_ERR (vcio .class );
159
- pr_err ("failed to create class\n" );
160
- goto err_cdev_del ;
133
+ fw_node = of_get_parent (np );
134
+ if (!fw_node ) {
135
+ dev_err (dev , "Missing firmware node\n" );
136
+ return - ENOENT ;
161
137
}
162
138
163
- dev = device_create (vcio .class , NULL , vcio .devt , NULL , "vcio" );
164
- if (IS_ERR (dev )) {
165
- ret = PTR_ERR (dev );
166
- pr_err ("failed to create device\n" );
167
- goto err_class_destroy ;
168
- }
139
+ fw = rpi_firmware_get (fw_node );
140
+ of_node_put (fw_node );
141
+ if (!fw )
142
+ return - EPROBE_DEFER ;
169
143
170
- return 0 ;
144
+ vcio = devm_kzalloc (dev , sizeof (struct vcio_data ), GFP_KERNEL );
145
+ if (!vcio )
146
+ return - ENOMEM ;
171
147
172
- err_class_destroy :
173
- class_destroy (vcio .class );
174
- err_cdev_del :
175
- cdev_del (& vcio .cdev );
176
- err_unregister_chardev :
177
- unregister_chrdev_region (vcio .devt , 1 );
148
+ vcio -> fw = fw ;
149
+ vcio -> misc_dev .fops = & vcio_fops ;
150
+ vcio -> misc_dev .minor = MISC_DYNAMIC_MINOR ;
151
+ vcio -> misc_dev .name = "vcio" ;
152
+ vcio -> misc_dev .parent = dev ;
178
153
179
- return ret ;
154
+ return misc_register ( & vcio -> misc_dev ) ;
180
155
}
181
- module_init (vcio_init );
182
156
183
- static void __exit vcio_exit ( void )
157
+ static int vcio_remove ( struct platform_device * pdev )
184
158
{
185
- device_destroy ( vcio . class , vcio . devt ) ;
186
- class_destroy ( vcio . class );
187
- cdev_del ( & vcio . cdev );
188
- unregister_chrdev_region ( vcio . devt , 1 ) ;
159
+ struct device * dev = & pdev -> dev ;
160
+
161
+ misc_deregister ( dev_get_drvdata ( dev ) );
162
+ return 0 ;
189
163
}
190
- module_exit (vcio_exit );
164
+
165
+ static const struct of_device_id vcio_ids [] = {
166
+ { .compatible = "raspberrypi,vcio" },
167
+ { }
168
+ };
169
+ MODULE_DEVICE_TABLE (of , vcio_ids );
170
+
171
+ static struct platform_driver vcio_driver = {
172
+ .driver = {
173
+ .name = MODULE_NAME ,
174
+ .of_match_table = of_match_ptr (vcio_ids ),
175
+ },
176
+ .probe = vcio_probe ,
177
+ .remove = vcio_remove ,
178
+ };
179
+
180
+ module_platform_driver (vcio_driver );
191
181
192
182
MODULE_AUTHOR ("Gray Girling" );
193
183
MODULE_AUTHOR ("Noralf Trønnes" );
194
184
MODULE_DESCRIPTION ("Mailbox userspace access" );
195
185
MODULE_LICENSE ("GPL" );
186
+ MODULE_ALIAS ("platform:rpi-vcio" );
0 commit comments