diff options
| author | alexmoon <[email protected]> | 2022-03-25 16:46:14 -0400 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-06 05:38:11 +0200 |
| commit | bdc6e0481c42d20d5cca19dfc8ec56306e47296e (patch) | |
| tree | 6beb805dd6ffea30877b654aa42e5c83f5a36c0b /embassy-usb/src/lib.rs | |
| parent | 5c0db627feae071182dd9978ffb56b0524558d93 (diff) | |
Add support for USB classes handling control requests.
Diffstat (limited to 'embassy-usb/src/lib.rs')
| -rw-r--r-- | embassy-usb/src/lib.rs | 169 |
1 files changed, 67 insertions, 102 deletions
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 95f78804d..4082868fb 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -1,16 +1,19 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![feature(generic_associated_types)] | 2 | #![feature(generic_associated_types)] |
| 3 | #![feature(type_alias_impl_trait)] | ||
| 3 | 4 | ||
| 4 | // This mod MUST go first, so that the others see its macros. | 5 | // This mod MUST go first, so that the others see its macros. |
| 5 | pub(crate) mod fmt; | 6 | pub(crate) mod fmt; |
| 6 | 7 | ||
| 7 | mod builder; | 8 | mod builder; |
| 8 | mod control; | 9 | pub mod class; |
| 10 | pub mod control; | ||
| 9 | pub mod descriptor; | 11 | pub mod descriptor; |
| 10 | pub mod driver; | 12 | pub mod driver; |
| 11 | pub mod types; | 13 | pub mod types; |
| 12 | mod util; | 14 | mod util; |
| 13 | 15 | ||
| 16 | use self::class::{RequestStatus, UsbClass}; | ||
| 14 | use self::control::*; | 17 | use self::control::*; |
| 15 | use self::descriptor::*; | 18 | use self::descriptor::*; |
| 16 | use self::driver::*; | 19 | use self::driver::*; |
| @@ -48,10 +51,9 @@ pub const CONFIGURATION_VALUE: u8 = 1; | |||
| 48 | /// The default value for bAlternateSetting for all interfaces. | 51 | /// The default value for bAlternateSetting for all interfaces. |
| 49 | pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; | 52 | pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; |
| 50 | 53 | ||
| 51 | pub struct UsbDevice<'d, D: Driver<'d>> { | 54 | pub struct UsbDevice<'d, D: Driver<'d>, C: UsbClass<'d, D>> { |
| 52 | bus: D::Bus, | 55 | bus: D::Bus, |
| 53 | control_in: D::EndpointIn, | 56 | control: D::ControlPipe, |
| 54 | control_out: D::EndpointOut, | ||
| 55 | 57 | ||
| 56 | config: Config<'d>, | 58 | config: Config<'d>, |
| 57 | device_descriptor: &'d [u8], | 59 | device_descriptor: &'d [u8], |
| @@ -62,32 +64,21 @@ pub struct UsbDevice<'d, D: Driver<'d>> { | |||
| 62 | remote_wakeup_enabled: bool, | 64 | remote_wakeup_enabled: bool, |
| 63 | self_powered: bool, | 65 | self_powered: bool, |
| 64 | pending_address: u8, | 66 | pending_address: u8, |
| 67 | |||
| 68 | classes: C, | ||
| 65 | } | 69 | } |
| 66 | 70 | ||
| 67 | impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | 71 | impl<'d, D: Driver<'d>, C: UsbClass<'d, D>> UsbDevice<'d, D, C> { |
| 68 | pub(crate) fn build( | 72 | pub(crate) fn build( |
| 69 | mut driver: D, | 73 | mut driver: D, |
| 70 | config: Config<'d>, | 74 | config: Config<'d>, |
| 71 | device_descriptor: &'d [u8], | 75 | device_descriptor: &'d [u8], |
| 72 | config_descriptor: &'d [u8], | 76 | config_descriptor: &'d [u8], |
| 73 | bos_descriptor: &'d [u8], | 77 | bos_descriptor: &'d [u8], |
| 78 | classes: C, | ||
| 74 | ) -> Self { | 79 | ) -> Self { |
| 75 | let control_out = driver | 80 | let control = driver |
| 76 | .alloc_endpoint_out( | 81 | .alloc_control_pipe(config.max_packet_size_0 as u16) |
| 77 | Some(0x00.into()), | ||
| 78 | EndpointType::Control, | ||
| 79 | config.max_packet_size_0 as u16, | ||
| 80 | 0, | ||
| 81 | ) | ||
| 82 | .expect("failed to alloc control endpoint"); | ||
| 83 | |||
| 84 | let control_in = driver | ||
| 85 | .alloc_endpoint_in( | ||
| 86 | Some(0x80.into()), | ||
| 87 | EndpointType::Control, | ||
| 88 | config.max_packet_size_0 as u16, | ||
| 89 | 0, | ||
| 90 | ) | ||
| 91 | .expect("failed to alloc control endpoint"); | 82 | .expect("failed to alloc control endpoint"); |
| 92 | 83 | ||
| 93 | // Enable the USB bus. | 84 | // Enable the USB bus. |
| @@ -97,8 +88,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 97 | Self { | 88 | Self { |
| 98 | bus: driver, | 89 | bus: driver, |
| 99 | config, | 90 | config, |
| 100 | control_in, | 91 | control, |
| 101 | control_out, | ||
| 102 | device_descriptor, | 92 | device_descriptor, |
| 103 | config_descriptor, | 93 | config_descriptor, |
| 104 | bos_descriptor, | 94 | bos_descriptor, |
| @@ -106,14 +96,13 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 106 | remote_wakeup_enabled: false, | 96 | remote_wakeup_enabled: false, |
| 107 | self_powered: false, | 97 | self_powered: false, |
| 108 | pending_address: 0, | 98 | pending_address: 0, |
| 99 | classes, | ||
| 109 | } | 100 | } |
| 110 | } | 101 | } |
| 111 | 102 | ||
| 112 | pub async fn run(&mut self) { | 103 | pub async fn run(&mut self) { |
| 113 | let mut buf = [0; 8]; | ||
| 114 | |||
| 115 | loop { | 104 | loop { |
| 116 | let control_fut = self.control_out.read(&mut buf); | 105 | let control_fut = self.control.setup(); |
| 117 | let bus_fut = self.bus.poll(); | 106 | let bus_fut = self.bus.poll(); |
| 118 | match select(bus_fut, control_fut).await { | 107 | match select(bus_fut, control_fut).await { |
| 119 | Either::Left(evt) => match evt { | 108 | Either::Left(evt) => match evt { |
| @@ -124,11 +113,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 124 | self.remote_wakeup_enabled = false; | 113 | self.remote_wakeup_enabled = false; |
| 125 | self.pending_address = 0; | 114 | self.pending_address = 0; |
| 126 | 115 | ||
| 127 | // TODO | 116 | self.classes.reset(); |
| 128 | //self.control.reset(); | ||
| 129 | //for cls in classes { | ||
| 130 | // cls.reset(); | ||
| 131 | //} | ||
| 132 | } | 117 | } |
| 133 | Event::Resume => {} | 118 | Event::Resume => {} |
| 134 | Event::Suspend => { | 119 | Event::Suspend => { |
| @@ -136,16 +121,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 136 | self.device_state = UsbDeviceState::Suspend; | 121 | self.device_state = UsbDeviceState::Suspend; |
| 137 | } | 122 | } |
| 138 | }, | 123 | }, |
| 139 | Either::Right(n) => { | 124 | Either::Right(req) => { |
| 140 | let n = n.unwrap(); | ||
| 141 | assert_eq!(n, 8); | ||
| 142 | let req = Request::parse(&buf).unwrap(); | ||
| 143 | info!("control request: {:x}", req); | 125 | info!("control request: {:x}", req); |
| 144 | 126 | ||
| 145 | // Now that we have properly parsed the setup packet, ensure the end-point is no longer in | ||
| 146 | // a stalled state. | ||
| 147 | self.control_out.set_stalled(false); | ||
| 148 | |||
| 149 | match req.direction { | 127 | match req.direction { |
| 150 | UsbDirection::In => self.handle_control_in(req).await, | 128 | UsbDirection::In => self.handle_control_in(req).await, |
| 151 | UsbDirection::Out => self.handle_control_out(req).await, | 129 | UsbDirection::Out => self.handle_control_out(req).await, |
| @@ -155,36 +133,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 155 | } | 133 | } |
| 156 | } | 134 | } |
| 157 | 135 | ||
| 158 | async fn write_chunked(&mut self, data: &[u8]) -> Result<(), driver::WriteError> { | ||
| 159 | for c in data.chunks(8) { | ||
| 160 | self.control_in.write(c).await?; | ||
| 161 | } | ||
| 162 | if data.len() % 8 == 0 { | ||
| 163 | self.control_in.write(&[]).await?; | ||
| 164 | } | ||
| 165 | Ok(()) | ||
| 166 | } | ||
| 167 | |||
| 168 | async fn control_out_accept(&mut self, req: Request) { | ||
| 169 | info!("control out accept"); | ||
| 170 | // status phase | ||
| 171 | // todo: cleanup | ||
| 172 | self.control_out.read(&mut []).await.unwrap(); | ||
| 173 | } | ||
| 174 | |||
| 175 | async fn control_in_accept(&mut self, req: Request, data: &[u8]) { | ||
| 176 | info!("control accept {:x}", data); | ||
| 177 | |||
| 178 | let len = data.len().min(req.length as _); | ||
| 179 | if let Err(e) = self.write_chunked(&data[..len]).await { | ||
| 180 | info!("write_chunked failed: {:?}", e); | ||
| 181 | } | ||
| 182 | |||
| 183 | // status phase | ||
| 184 | // todo: cleanup | ||
| 185 | self.control_out.read(&mut []).await.unwrap(); | ||
| 186 | } | ||
| 187 | |||
| 188 | async fn control_in_accept_writer( | 136 | async fn control_in_accept_writer( |
| 189 | &mut self, | 137 | &mut self, |
| 190 | req: Request, | 138 | req: Request, |
| @@ -193,17 +141,26 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 193 | let mut buf = [0; 256]; | 141 | let mut buf = [0; 256]; |
| 194 | let mut w = DescriptorWriter::new(&mut buf); | 142 | let mut w = DescriptorWriter::new(&mut buf); |
| 195 | f(&mut w); | 143 | f(&mut w); |
| 196 | let pos = w.position(); | 144 | let pos = w.position().min(usize::from(req.length)); |
| 197 | self.control_in_accept(req, &buf[..pos]).await; | 145 | self.control.accept_in(&buf[..pos]).await; |
| 198 | } | ||
| 199 | |||
| 200 | fn control_reject(&mut self, req: Request) { | ||
| 201 | info!("control reject"); | ||
| 202 | self.control_out.set_stalled(true); | ||
| 203 | } | 146 | } |
| 204 | 147 | ||
| 205 | async fn handle_control_out(&mut self, req: Request) { | 148 | async fn handle_control_out(&mut self, req: Request) { |
| 206 | // TODO actually read the data if there's an OUT data phase. | 149 | { |
| 150 | let mut buf = [0; 128]; | ||
| 151 | let data = if req.length > 0 { | ||
| 152 | let size = self.control.data_out(&mut buf).await.unwrap(); | ||
| 153 | &buf[0..size] | ||
| 154 | } else { | ||
| 155 | &[] | ||
| 156 | }; | ||
| 157 | |||
| 158 | match self.classes.control_out(req, data).await { | ||
| 159 | RequestStatus::Accepted => return self.control.accept(), | ||
| 160 | RequestStatus::Rejected => return self.control.reject(), | ||
| 161 | RequestStatus::Unhandled => (), | ||
| 162 | } | ||
| 163 | } | ||
| 207 | 164 | ||
| 208 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; | 165 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; |
| 209 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; | 166 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; |
| @@ -217,12 +174,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 217 | Request::FEATURE_DEVICE_REMOTE_WAKEUP, | 174 | Request::FEATURE_DEVICE_REMOTE_WAKEUP, |
| 218 | ) => { | 175 | ) => { |
| 219 | self.remote_wakeup_enabled = false; | 176 | self.remote_wakeup_enabled = false; |
| 220 | self.control_out_accept(req).await; | 177 | self.control.accept(); |
| 221 | } | 178 | } |
| 222 | 179 | ||
| 223 | (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { | 180 | (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { |
| 224 | //self.bus.set_stalled(((req.index as u8) & 0x8f).into(), false); | 181 | //self.bus.set_stalled(((req.index as u8) & 0x8f).into(), false); |
| 225 | self.control_out_accept(req).await; | 182 | self.control.accept(); |
| 226 | } | 183 | } |
| 227 | 184 | ||
| 228 | ( | 185 | ( |
| @@ -231,51 +188,61 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 231 | Request::FEATURE_DEVICE_REMOTE_WAKEUP, | 188 | Request::FEATURE_DEVICE_REMOTE_WAKEUP, |
| 232 | ) => { | 189 | ) => { |
| 233 | self.remote_wakeup_enabled = true; | 190 | self.remote_wakeup_enabled = true; |
| 234 | self.control_out_accept(req).await; | 191 | self.control.accept(); |
| 235 | } | 192 | } |
| 236 | 193 | ||
| 237 | (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { | 194 | (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { |
| 238 | self.bus | 195 | self.bus |
| 239 | .set_stalled(((req.index as u8) & 0x8f).into(), true); | 196 | .set_stalled(((req.index as u8) & 0x8f).into(), true); |
| 240 | self.control_out_accept(req).await; | 197 | self.control.accept(); |
| 241 | } | 198 | } |
| 242 | 199 | ||
| 243 | (Recipient::Device, Request::SET_ADDRESS, 1..=127) => { | 200 | (Recipient::Device, Request::SET_ADDRESS, 1..=127) => { |
| 244 | self.pending_address = req.value as u8; | 201 | self.pending_address = req.value as u8; |
| 245 | 202 | ||
| 246 | // on NRF the hardware auto-handles SET_ADDRESS. | 203 | // on NRF the hardware auto-handles SET_ADDRESS. |
| 247 | self.control_out_accept(req).await; | 204 | self.control.accept(); |
| 248 | } | 205 | } |
| 249 | 206 | ||
| 250 | (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { | 207 | (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { |
| 251 | self.device_state = UsbDeviceState::Configured; | 208 | self.device_state = UsbDeviceState::Configured; |
| 252 | self.control_out_accept(req).await; | 209 | self.control.accept(); |
| 253 | } | 210 | } |
| 254 | 211 | ||
| 255 | (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => { | 212 | (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => { |
| 256 | match self.device_state { | 213 | match self.device_state { |
| 257 | UsbDeviceState::Default => { | 214 | UsbDeviceState::Default => { |
| 258 | self.control_out_accept(req).await; | 215 | self.control.accept(); |
| 259 | } | 216 | } |
| 260 | _ => { | 217 | _ => { |
| 261 | self.device_state = UsbDeviceState::Addressed; | 218 | self.device_state = UsbDeviceState::Addressed; |
| 262 | self.control_out_accept(req).await; | 219 | self.control.accept(); |
| 263 | } | 220 | } |
| 264 | } | 221 | } |
| 265 | } | 222 | } |
| 266 | 223 | ||
| 267 | (Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => { | 224 | (Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => { |
| 268 | // TODO: do something when alternate settings are implemented | 225 | // TODO: do something when alternate settings are implemented |
| 269 | self.control_out_accept(req).await; | 226 | self.control.accept(); |
| 270 | } | 227 | } |
| 271 | 228 | ||
| 272 | _ => self.control_reject(req), | 229 | _ => self.control.reject(), |
| 273 | }, | 230 | }, |
| 274 | _ => self.control_reject(req), | 231 | _ => self.control.reject(), |
| 275 | } | 232 | } |
| 276 | } | 233 | } |
| 277 | 234 | ||
| 278 | async fn handle_control_in(&mut self, req: Request) { | 235 | async fn handle_control_in(&mut self, req: Request) { |
| 236 | match self | ||
| 237 | .classes | ||
| 238 | .control_in(req, class::ControlIn::new(&mut self.control)) | ||
| 239 | .await | ||
| 240 | .status() | ||
| 241 | { | ||
| 242 | RequestStatus::Accepted | RequestStatus::Rejected => return, | ||
| 243 | RequestStatus::Unhandled => (), | ||
| 244 | } | ||
| 245 | |||
| 279 | match req.request_type { | 246 | match req.request_type { |
| 280 | RequestType::Standard => match (req.recipient, req.request) { | 247 | RequestType::Standard => match (req.recipient, req.request) { |
| 281 | (Recipient::Device, Request::GET_STATUS) => { | 248 | (Recipient::Device, Request::GET_STATUS) => { |
| @@ -286,12 +253,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 286 | if self.remote_wakeup_enabled { | 253 | if self.remote_wakeup_enabled { |
| 287 | status |= 0x0002; | 254 | status |= 0x0002; |
| 288 | } | 255 | } |
| 289 | self.control_in_accept(req, &status.to_le_bytes()).await; | 256 | self.control.accept_in(&status.to_le_bytes()).await; |
| 290 | } | 257 | } |
| 291 | 258 | ||
| 292 | (Recipient::Interface, Request::GET_STATUS) => { | 259 | (Recipient::Interface, Request::GET_STATUS) => { |
| 293 | let status: u16 = 0x0000; | 260 | let status: u16 = 0x0000; |
| 294 | self.control_in_accept(req, &status.to_le_bytes()).await; | 261 | self.control.accept_in(&status.to_le_bytes()).await; |
| 295 | } | 262 | } |
| 296 | 263 | ||
| 297 | (Recipient::Endpoint, Request::GET_STATUS) => { | 264 | (Recipient::Endpoint, Request::GET_STATUS) => { |
| @@ -300,7 +267,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 300 | if self.bus.is_stalled(ep_addr) { | 267 | if self.bus.is_stalled(ep_addr) { |
| 301 | status |= 0x0001; | 268 | status |= 0x0001; |
| 302 | } | 269 | } |
| 303 | self.control_in_accept(req, &status.to_le_bytes()).await; | 270 | self.control.accept_in(&status.to_le_bytes()).await; |
| 304 | } | 271 | } |
| 305 | 272 | ||
| 306 | (Recipient::Device, Request::GET_DESCRIPTOR) => { | 273 | (Recipient::Device, Request::GET_DESCRIPTOR) => { |
| @@ -312,17 +279,17 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 312 | UsbDeviceState::Configured => CONFIGURATION_VALUE, | 279 | UsbDeviceState::Configured => CONFIGURATION_VALUE, |
| 313 | _ => CONFIGURATION_NONE, | 280 | _ => CONFIGURATION_NONE, |
| 314 | }; | 281 | }; |
| 315 | self.control_in_accept(req, &status.to_le_bytes()).await; | 282 | self.control.accept_in(&status.to_le_bytes()).await; |
| 316 | } | 283 | } |
| 317 | 284 | ||
| 318 | (Recipient::Interface, Request::GET_INTERFACE) => { | 285 | (Recipient::Interface, Request::GET_INTERFACE) => { |
| 319 | // TODO: change when alternate settings are implemented | 286 | // TODO: change when alternate settings are implemented |
| 320 | let status = DEFAULT_ALTERNATE_SETTING; | 287 | let status = DEFAULT_ALTERNATE_SETTING; |
| 321 | self.control_in_accept(req, &status.to_le_bytes()).await; | 288 | self.control.accept_in(&status.to_le_bytes()).await; |
| 322 | } | 289 | } |
| 323 | _ => self.control_reject(req), | 290 | _ => self.control.reject(), |
| 324 | }, | 291 | }, |
| 325 | _ => self.control_reject(req), | 292 | _ => self.control.reject(), |
| 326 | } | 293 | } |
| 327 | } | 294 | } |
| 328 | 295 | ||
| @@ -331,11 +298,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 331 | let config = self.config.clone(); | 298 | let config = self.config.clone(); |
| 332 | 299 | ||
| 333 | match dtype { | 300 | match dtype { |
| 334 | descriptor_type::BOS => self.control_in_accept(req, self.bos_descriptor).await, | 301 | descriptor_type::BOS => self.control.accept_in(self.bos_descriptor).await, |
| 335 | descriptor_type::DEVICE => self.control_in_accept(req, self.device_descriptor).await, | 302 | descriptor_type::DEVICE => self.control.accept_in(self.device_descriptor).await, |
| 336 | descriptor_type::CONFIGURATION => { | 303 | descriptor_type::CONFIGURATION => self.control.accept_in(self.config_descriptor).await, |
| 337 | self.control_in_accept(req, self.config_descriptor).await | ||
| 338 | } | ||
| 339 | descriptor_type::STRING => { | 304 | descriptor_type::STRING => { |
| 340 | if index == 0 { | 305 | if index == 0 { |
| 341 | self.control_in_accept_writer(req, |w| { | 306 | self.control_in_accept_writer(req, |w| { |
| @@ -363,11 +328,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 363 | self.control_in_accept_writer(req, |w| w.string(s).unwrap()) | 328 | self.control_in_accept_writer(req, |w| w.string(s).unwrap()) |
| 364 | .await; | 329 | .await; |
| 365 | } else { | 330 | } else { |
| 366 | self.control_reject(req) | 331 | self.control.reject() |
| 367 | } | 332 | } |
| 368 | } | 333 | } |
| 369 | } | 334 | } |
| 370 | _ => self.control_reject(req), | 335 | _ => self.control.reject(), |
| 371 | } | 336 | } |
| 372 | } | 337 | } |
| 373 | } | 338 | } |
