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
+ #define MODULE_NAME "vcio"
13
+ #define pr_fmt (fmt ) MODULE_NAME ": " fmt
12
14
13
15
#include <linux/cdev.h>
14
16
#include <linux/device.h>
19
21
#include <linux/slab.h>
20
22
#include <linux/uaccess.h>
21
23
#include <linux/compat.h>
24
+ #include <linux/miscdevice.h>
22
25
#include <soc/bcm2835/raspberrypi-firmware.h>
23
26
24
- #define MBOX_CHAN_PROPERTY 8
25
-
26
27
#define VCIO_IOC_MAGIC 100
27
28
#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
28
29
#ifdef CONFIG_COMPAT
29
30
#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
30
31
#endif
31
32
32
- static struct {
33
- dev_t devt ;
34
- struct cdev cdev ;
35
- struct class * class ;
33
+ struct vcio_data {
36
34
struct rpi_firmware * fw ;
37
- } vcio ;
35
+ struct miscdevice misc_dev ;
36
+ };
38
37
39
- static int vcio_user_property_list (void * user )
38
+ static int vcio_user_property_list (struct vcio_data * vcio , void * user )
40
39
{
41
40
u32 * buf , size ;
42
41
int ret ;
@@ -55,7 +54,7 @@ static int vcio_user_property_list(void *user)
55
54
}
56
55
57
56
/* Strip off protocol encapsulation */
58
- ret = rpi_firmware_property_list (vcio . fw , & buf [2 ], size - 12 );
57
+ ret = rpi_firmware_property_list (vcio -> fw , & buf [2 ], size - 12 );
59
58
if (ret ) {
60
59
kfree (buf );
61
60
return ret ;
@@ -87,9 +86,12 @@ static int vcio_device_release(struct inode *inode, struct file *file)
87
86
static long vcio_device_ioctl (struct file * file , unsigned int ioctl_num ,
88
87
unsigned long ioctl_param )
89
88
{
89
+ struct vcio_data * vcio = container_of (file -> private_data ,
90
+ struct vcio_data , misc_dev );
91
+
90
92
switch (ioctl_num ) {
91
93
case IOCTL_MBOX_PROPERTY :
92
- return vcio_user_property_list ((void * )ioctl_param );
94
+ return vcio_user_property_list (vcio , (void * )ioctl_param );
93
95
default :
94
96
pr_err ("unknown ioctl: %x\n" , ioctl_num );
95
97
return - EINVAL ;
@@ -100,9 +102,12 @@ static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
100
102
static long vcio_device_compat_ioctl (struct file * file , unsigned int ioctl_num ,
101
103
unsigned long ioctl_param )
102
104
{
105
+ struct vcio_data * vcio = container_of (file -> private_data ,
106
+ struct vcio_data , misc_dev );
107
+
103
108
switch (ioctl_num ) {
104
109
case IOCTL_MBOX_PROPERTY32 :
105
- return vcio_user_property_list (compat_ptr (ioctl_param ));
110
+ return vcio_user_property_list (vcio , compat_ptr (ioctl_param ));
106
111
default :
107
112
pr_err ("unknown ioctl: %x\n" , ioctl_num );
108
113
return - EINVAL ;
@@ -119,77 +124,65 @@ const struct file_operations vcio_fops = {
119
124
.release = vcio_device_release ,
120
125
};
121
126
122
- static int __init vcio_init ( void )
127
+ static int vcio_probe ( struct platform_device * pdev )
123
128
{
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
- }
129
+ struct device * dev = & pdev -> dev ;
130
+ struct device_node * np = dev -> of_node ;
131
+ struct device_node * fw_node ;
132
+ struct rpi_firmware * fw ;
133
+ struct vcio_data * vcio ;
150
134
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 ;
135
+ fw_node = of_get_parent (np );
136
+ if (!fw_node ) {
137
+ dev_err (dev , "Missing firmware node\n" );
138
+ return - ENOENT ;
161
139
}
162
140
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
- }
141
+ fw = rpi_firmware_get (fw_node );
142
+ of_node_put (fw_node );
143
+ if (!fw )
144
+ return - EPROBE_DEFER ;
169
145
170
- return 0 ;
146
+ vcio = devm_kzalloc (dev , sizeof (struct vcio_data ), GFP_KERNEL );
147
+ if (!vcio )
148
+ return - ENOMEM ;
171
149
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 );
150
+ vcio -> fw = fw ;
151
+ vcio -> misc_dev .fops = & vcio_fops ;
152
+ vcio -> misc_dev .minor = MISC_DYNAMIC_MINOR ;
153
+ vcio -> misc_dev .name = "vcio" ;
154
+ vcio -> misc_dev .parent = dev ;
178
155
179
- return ret ;
156
+ return misc_register ( & vcio -> misc_dev ) ;
180
157
}
181
- module_init (vcio_init );
182
158
183
- static void __exit vcio_exit ( void )
159
+ static int vcio_remove ( struct platform_device * pdev )
184
160
{
185
- device_destroy ( vcio . class , vcio . devt ) ;
186
- class_destroy ( vcio . class );
187
- cdev_del ( & vcio . cdev );
188
- unregister_chrdev_region ( vcio . devt , 1 ) ;
161
+ struct device * dev = & pdev -> dev ;
162
+
163
+ misc_deregister ( dev_get_drvdata ( dev ) );
164
+ return 0 ;
189
165
}
190
- module_exit (vcio_exit );
166
+
167
+ static const struct of_device_id vcio_ids [] = {
168
+ { .compatible = "raspberrypi,vcio" },
169
+ { }
170
+ };
171
+ MODULE_DEVICE_TABLE (of , vcio_ids );
172
+
173
+ static struct platform_driver vcio_driver = {
174
+ .driver = {
175
+ .name = MODULE_NAME ,
176
+ .of_match_table = of_match_ptr (vcio_ids ),
177
+ },
178
+ .probe = vcio_probe ,
179
+ .remove = vcio_remove ,
180
+ };
181
+
182
+ module_platform_driver (vcio_driver );
191
183
192
184
MODULE_AUTHOR ("Gray Girling" );
193
185
MODULE_AUTHOR ("Noralf Trønnes" );
194
186
MODULE_DESCRIPTION ("Mailbox userspace access" );
195
187
MODULE_LICENSE ("GPL" );
188
+ MODULE_ALIAS ("platform:rpi-vcio" );
0 commit comments