@@ -24,59 +24,135 @@ pub struct DriverRegistration {
24
24
this_module : & ' static crate :: ThisModule ,
25
25
registered : bool ,
26
26
name : CStr < ' static > ,
27
- probe : Option < SpiMethod > ,
28
- remove : Option < SpiMethod > ,
29
- shutdown : Option < SpiMethodVoid > ,
30
27
spi_driver : Option < bindings:: spi_driver > ,
31
28
}
32
29
30
+ pub struct ToUse {
31
+ pub probe : bool ,
32
+ pub remove : bool ,
33
+ pub shutdown : bool ,
34
+ }
35
+
36
+ pub const USE_NONE : ToUse = ToUse {
37
+ probe : false ,
38
+ remove : false ,
39
+ shutdown : false ,
40
+ } ;
41
+
42
+ pub trait SpiMethods {
43
+ const TO_USE : ToUse ;
44
+
45
+ fn probe ( _spi_dev : SpiDevice ) -> Result {
46
+ Ok ( ( ) )
47
+ }
48
+
49
+ fn remove ( _spi_dev : SpiDevice ) -> Result {
50
+ Ok ( ( ) )
51
+ }
52
+
53
+ fn shutdown ( _spi_dev : SpiDevice ) { }
54
+ }
55
+
56
+ /// Populate the TO_USE field in the `SpiMethods` implementer
57
+ ///
58
+ /// ```rust
59
+ /// impl SpiMethods for MySpiMethods {
60
+ /// /// Let's say you only want a probe and remove method, no shutdown
61
+ /// declare_spi_methods!(probe, remove);
62
+ ///
63
+ /// /// Define your probe and remove methods. If you don't, default implementations
64
+ /// /// will be used instead. These default implementations do NOT correspond to the
65
+ /// /// kernel's default implementations! If you wish to use the Kernel's default
66
+ /// /// spi functions implementations, do not declare them using the `declare_spi_methods`
67
+ /// /// macro. For example, here our Driver will use the Kernel's shutdown method.
68
+ /// fn probe(spi_dev: SpiDevice) -> Result {
69
+ /// // ...
70
+ ///
71
+ /// Ok(())
72
+ /// }
73
+ ///
74
+ /// fn remove(spi_dev: SpiDevice) -> Result {
75
+ /// // ...
76
+ ///
77
+ /// Ok(())
78
+ /// }
79
+ /// }
80
+ /// ```
81
+ #[ macro_export]
82
+ macro_rules! declare_spi_methods {
83
+ ( ) => {
84
+ const TO_USE : $crate:: spi:: ToUse = $crate:: spi:: USE_NONE ;
85
+ } ;
86
+ ( $( $method: ident) ,+) => {
87
+ const TO_USE : $crate:: spi:: ToUse = $crate:: spi:: ToUse {
88
+ $( $method: true ) ,+,
89
+ ..$crate:: spi:: USE_NONE
90
+ } ;
91
+ } ;
92
+ }
93
+
33
94
impl DriverRegistration {
34
- fn new (
35
- this_module : & ' static crate :: ThisModule ,
36
- name : CStr < ' static > ,
37
- probe : Option < SpiMethod > ,
38
- remove : Option < SpiMethod > ,
39
- shutdown : Option < SpiMethodVoid > ,
40
- ) -> Self {
95
+ fn new ( this_module : & ' static crate :: ThisModule , name : CStr < ' static > ) -> Self {
41
96
DriverRegistration {
42
97
this_module,
43
98
name,
44
99
registered : false ,
45
- probe,
46
- remove,
47
- shutdown,
48
100
spi_driver : None ,
49
101
}
50
102
}
51
103
52
104
// FIXME: Add documentation
53
- pub fn new_pinned (
105
+ pub fn new_pinned < T : SpiMethods > (
54
106
this_module : & ' static crate :: ThisModule ,
55
107
name : CStr < ' static > ,
56
- probe : Option < SpiMethod > ,
57
- remove : Option < SpiMethod > ,
58
- shutdown : Option < SpiMethodVoid > ,
59
108
) -> Result < Pin < Box < Self > > > {
60
- let mut registration = Pin :: from ( Box :: try_new ( Self :: new (
61
- this_module,
62
- name,
63
- probe,
64
- remove,
65
- shutdown,
66
- ) ) ?) ;
109
+ let mut registration = Pin :: from ( Box :: try_new ( Self :: new ( this_module, name) ) ?) ;
67
110
68
- registration. as_mut ( ) . register ( ) ?;
111
+ registration. as_mut ( ) . register :: < T > ( ) ?;
69
112
70
113
Ok ( registration)
71
114
}
72
115
116
+ unsafe extern "C" fn probe_wrapper < T : SpiMethods > (
117
+ spi_dev : * mut bindings:: spi_device ,
118
+ ) -> c_types:: c_int {
119
+ // SAFETY: The spi_dev pointer is provided by the kernel and is sure to be valid
120
+ match T :: probe ( SpiDevice :: from_ptr ( spi_dev) ) {
121
+ Ok ( _) => 0 ,
122
+ Err ( e) => e. to_kernel_errno ( ) ,
123
+ }
124
+ }
125
+
126
+ unsafe extern "C" fn remove_wrapper < T : SpiMethods > (
127
+ spi_dev : * mut bindings:: spi_device ,
128
+ ) -> c_types:: c_int {
129
+ // SAFETY: The spi_dev pointer is provided by the kernel and is sure to be valid
130
+ match T :: remove ( SpiDevice :: from_ptr ( spi_dev) ) {
131
+ Ok ( _) => 0 ,
132
+ Err ( e) => e. to_kernel_errno ( ) ,
133
+ }
134
+ }
135
+
136
+ unsafe extern "C" fn shutdown_wrapper < T : SpiMethods > ( spi_dev : * mut bindings:: spi_device ) {
137
+ // SAFETY: The spi_dev pointer is provided by the kernel and is sure to be valid
138
+ T :: shutdown ( SpiDevice :: from_ptr ( spi_dev) )
139
+ }
140
+
73
141
// FIXME: Add documentation
74
- pub fn register ( self : Pin < & mut Self > ) -> Result {
142
+ pub fn register < T : SpiMethods > ( self : Pin < & mut Self > ) -> Result {
143
+ fn maybe_get_wrapper < F > ( vtable_value : bool , func : F ) -> Option < F > {
144
+ match vtable_value {
145
+ false => None ,
146
+ true => Some ( func) ,
147
+ }
148
+ }
149
+
75
150
let mut spi_driver = bindings:: spi_driver:: default ( ) ;
76
151
spi_driver. driver . name = self . name . as_ptr ( ) as * const c_types:: c_char ;
77
- spi_driver. probe = self . probe ;
78
- spi_driver. remove = self . remove ;
79
- spi_driver. shutdown = self . shutdown ;
152
+
153
+ spi_driver. probe = maybe_get_wrapper ( T :: TO_USE . probe , DriverRegistration :: probe_wrapper :: < T > ) ;
154
+ spi_driver. remove = maybe_get_wrapper ( T :: TO_USE . remove , DriverRegistration :: remove_wrapper :: < T > ) ;
155
+ spi_driver. shutdown = maybe_get_wrapper ( T :: TO_USE . shutdown , DriverRegistration :: shutdown_wrapper :: < T > ) ;
80
156
81
157
let this = unsafe { self . get_unchecked_mut ( ) } ;
82
158
if this. registered {
@@ -115,36 +191,6 @@ unsafe impl Sync for DriverRegistration {}
115
191
// SAFETY: All functions work from any thread.
116
192
unsafe impl Send for DriverRegistration { }
117
193
118
- type SpiMethod = unsafe extern "C" fn ( * mut bindings:: spi_device ) -> c_types:: c_int ;
119
- type SpiMethodVoid = unsafe extern "C" fn ( * mut bindings:: spi_device ) -> ( ) ;
120
-
121
- #[ macro_export]
122
- macro_rules! spi_method {
123
- ( fn $method_name: ident ( mut $device_name: ident : SpiDevice ) -> Result $block: block) => {
124
- unsafe extern "C" fn $method_name( dev: * mut kernel:: bindings:: spi_device) -> kernel:: c_types:: c_int {
125
- use kernel:: spi:: SpiDevice ;
126
-
127
- fn inner( mut $device_name: SpiDevice ) -> Result $block
128
-
129
- // SAFETY: The dev pointer is provided by the kernel and is sure to be valid
130
- match inner( unsafe { SpiDevice :: from_ptr( dev) } ) {
131
- Ok ( _) => 0 ,
132
- Err ( e) => e. to_kernel_errno( ) ,
133
- }
134
- }
135
- } ;
136
- ( fn $method_name: ident ( mut $device_name: ident : SpiDevice ) $block: block) => {
137
- unsafe extern "C" fn $method_name( dev: * mut kernel:: bindings:: spi_device) {
138
- use kernel:: spi:: SpiDevice ;
139
-
140
- fn inner( mut $device_name: SpiDevice ) $block
141
-
142
- // SAFETY: The dev pointer is provided by the kernel and is sure to be valid
143
- inner( unsafe { SpiDevice :: from_ptr( dev) } )
144
- }
145
- } ;
146
- }
147
-
148
194
pub struct Spi ;
149
195
150
196
impl Spi {
0 commit comments