diff --git a/src/lib.rs b/src/lib.rs index 39b95aa..ddff50a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,139 @@ #![no_std] +use core::cmp::max; + +use avr_device::interrupt::free; +use usb_device::{ + bus::{PollResult, UsbBus}, + endpoint::{EndpointAddress, EndpointType}, + Result as UsbResult, UsbDirection, UsbError, +}; + mod types; +use types::{UsbDevice, DPRAM_SIZE, ENDPOINTS_ALLOC_LAYOUT}; + +impl UsbBus for UsbDevice { + fn alloc_ep( + &mut self, + ep_dir: UsbDirection, + ep_addr: Option, + ep_type: EndpointType, + max_packet_size: u16, + _interval: u8, + ) -> UsbResult { + // Handle first endpoint. // + if ep_addr == Some(EndpointAddress::from_parts(0, UsbDirection::In)) { + return Ok(ep_addr.unwrap()); + } + + let address = match ep_addr { + // If current endpoint doesn't allocated, assign ep_addr to variable. // + Some(ep_addr) if !self.ep_table[ep_addr.index()].is_allocated => ep_addr, + + // If ep_aadr not provided, or current endpoint is allocated, try to find next free endpoint, otherwise return UsbError. // + None | Some(_) => { + let endpoint = self + .ep_table + .iter() + .enumerate() + .skip(1) + .find(|(i, &ep)| { + !ep.is_allocated && max_packet_size <= ENDPOINTS_ALLOC_LAYOUT[*i] + }) + .ok_or(UsbError::EndpointMemoryOverflow)?; + + EndpointAddress::from_parts(endpoint.0, ep_dir) + } + }; + + // Select endpoint info by address index. // + + let target_endpoint = &mut self.ep_table[address.index()]; + + // Endpoint allocation marker. // + + if DPRAM_SIZE - self.dpram_already_used <= max_packet_size || max_packet_size >= 512 { + Err(UsbError::EndpointMemoryOverflow) + } else { + // Get power of two number of endpoint size. // + + let max_packet_size = max(8, max_packet_size.next_power_of_two()); + + // Set endpoint parameters. // + + target_endpoint.set_size(max_packet_size); + target_endpoint.set_dir(ep_dir); + target_endpoint.set_type(ep_type); + target_endpoint.is_allocated = true; + + // Add used dpram memory. // + + self.dpram_already_used += max_packet_size; + + Ok(address) + } + } + + fn enable(&mut self) { + free(|cs| { + let (pll, usb) = (self.pll.borrow(cs), self.usb.borrow(cs)); + + // Enable USB pads regulators. // + + usb.uhwcon.modify(|_, w| w.uvrege().set_bit()); + + // Enable USB interface. // + + usb.usbcon + .modify(|_, w| w.usbe().set_bit().frzclk().set_bit()); + + // Configuring PLL. // + + pll.pllfrq + .modify(|_, w| w.pdiv().mhz96().plltm().factor_15().pllusb().set_bit()); + + // Enable PLL. // + + pll.pllcsr + .modify(|_, w| w.pindiv().set_bit().plle().set_bit()); + + while pll.pllcsr.read().plock().bit_is_clear() {} + + // Unfreeze clock. // + + usb.usbcon + .modify(|_, w| w.frzclk().clear_bit().otgpade().set_bit()); + + // Interrupts. // + + usb.udien + .modify(|_, w| w.eorste().set_bit().sofe().set_bit()); + + // Set high speed and attach the USB. // + + usb.udcon + .modify(|_, w| w.lsm().set_bit().detach().clear_bit()); + }) + } + + fn force_reset(&self) -> UsbResult<()> { + free(|cs| { + let usb = self.usb.borrow(cs); + + usb.usbcon.modify(|_, w| w.usbe().clear_bit()); + usb.usbcon.modify(|_, w| w.usbe().set_bit()); + + Ok(()) + }) + } + + fn is_stalled(&self, ep_addr: EndpointAddress) -> bool { + free(|cs| match self.select_endpoint(cs, ep_addr.index()) { + Ok(_) => self.usb.borrow(cs).ueconx.read().stallrq().bit_is_clear(), + Err(_) => false, + }) + } + fn poll(&self) -> PollResult { free(|cs| { let usb = self.usb.borrow(cs); @@ -121,6 +254,106 @@ mod types; } }) } + + fn reset(&self) { + free(|cs| { + let usb = self.usb.borrow(cs); + + usb.udint.modify(|_, w| w.eorsti().clear_bit()); + + // Disabling all endpoints before it reset // + + self.ep_table + .iter() + .filter(|&&ep| ep.is_allocated) + .enumerate() + .for_each(|(index, _ep)| { + if self.select_endpoint(cs, index).is_ok() { + usb.ueconx.modify(|_, w| w.epen().clear_bit()); + } + }); + + // Reset endpoints // + + usb.uerst.modify(|_, w| unsafe { w.bits(u8::MAX >> 1) }); + + // Clear resume informations. // + + usb.udint + .modify(|_, w| w.wakeupi().clear_bit().suspi().clear_bit()); + usb.udien + .modify(|_, w| w.wakeupe().clear_bit().suspe().set_bit()); + }) + } + + fn resume(&self) { + free(|cs| { + let usb = self.usb.borrow(cs); + let pll = self.pll.borrow(cs); + + // Enable PLL and wait PLL lock. // + + pll.pllcsr.modify(|_, w| w.plle().set_bit()); + + while pll.pllcsr.read().plock().bit_is_clear() {} + + // Unfreeze USB clock. // + + usb.usbcon.modify(|_, w| w.frzclk().clear_bit()); + + // Clear resume informations. // + + usb.udint + .modify(|_, w| w.wakeupi().clear_bit().suspi().clear_bit()); + + usb.udien + .modify(|_, w| w.wakeupe().clear_bit().suspe().set_bit()); + }) + } + + fn set_device_address(&self, addr: u8) { + free(|cs| { + let usb = self.usb.borrow(cs); + + // Set address. // + + usb.udaddr.modify(|_, w| w.uadd().bits(addr)); + + // Note: ADDEN and UADD shall not be written at the same time. + // (written in atmega32u4/16u4 docs) + + // Enable. // + + usb.udaddr.modify(|_, w| w.adden().set_bit()); + }); + } + + fn set_stalled(&self, ep_addr: EndpointAddress, stalled: bool) { + free(|cs| { + let usb = self.usb.borrow(cs); + if self.select_endpoint(cs, ep_addr.index()).is_ok() { + usb.ueconx + .modify(|_, w| w.stallrq().bit(stalled).stallrqc().bit(!stalled)); + } + }); + } + + fn suspend(&self) { + free(|cs| { + let usb = self.usb.borrow(cs); + let pll = self.pll.borrow(cs); + + usb.udint + .modify(|_, w| w.suspi().clear_bit().wakeupi().clear_bit()); + usb.udien + .modify(|_, w| w.suspe().clear_bit().wakeupe().clear_bit()); + + usb.usbcon.modify(|_, w| w.frzclk().set_bit()); + + pll.pllcsr.modify(|_, w| w.plle().clear_bit()); + }) + } + fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> UsbResult { free(|cs| { let usb = self.usb.borrow(cs); @@ -171,3 +404,4 @@ mod types; } }) } +} diff --git a/src/types/usb_device.rs b/src/types/usb_device.rs index d5525b7..6de6d7b 100644 --- a/src/types/usb_device.rs +++ b/src/types/usb_device.rs @@ -149,189 +149,3 @@ impl UsbDevice { } } -impl UsbBus for UsbDevice { - fn alloc_ep( - &mut self, - ep_dir: UsbDirection, - ep_addr: Option, - ep_type: EndpointType, - max_packet_size: u16, - _interval: u8, - ) -> UsbResult { - // Handle first endpoint. // - if ep_addr == Some(EndpointAddress::from_parts(0, UsbDirection::In)) { - return Ok(ep_addr.unwrap()); - } - - let address = match ep_addr { - // If current endpoint doesn't allocated, assign ep_addr to variable. // - Some(ep_addr) if !self.ep_table[ep_addr.index()].is_allocated => ep_addr, - - // If ep_aadr not provided, or current endpoint is allocated, try to find next free endpoint, otherwise return UsbError. // - None | Some(_) => { - let endpoint = self - .ep_table - .iter() - .enumerate() - .skip(1) - .find(|(i, &ep)| { - !ep.is_allocated && max_packet_size <= ENDPOINTS_ALLOC_LAYOUT[*i] - }) - .ok_or(UsbError::EndpointMemoryOverflow)?; - - EndpointAddress::from_parts(endpoint.0, ep_dir) - } - }; - - // Select endpoint info by address index. // - - let target_endpoint = &mut self.ep_table[address.index()]; - - // Endpoint allocation marker. // - - if DPRAM_SIZE - self.dpram_already_used <= max_packet_size || max_packet_size >= 512 { - Err(UsbError::EndpointMemoryOverflow) - } else { - - // Get power of two number of endpoint size. // - - let max_packet_size = max(8, max_packet_size.next_power_of_two()); - - // Set endpoint parameters. // - - target_endpoint.set_size(max_packet_size); - target_endpoint.set_dir(ep_dir); - target_endpoint.set_type(ep_type); - target_endpoint.is_allocated = true; - - // Add used dpram memory. // - - self.dpram_already_used += max_packet_size; - - Ok(address) - } - } - - fn enable(&mut self) { - free(|cs| { - let (pll, usb) = (self.pll.borrow(cs), self.usb.borrow(cs)); - - // Enable USB pads regulators. // - - usb.uhwcon.modify(|_, w| w.uvrege().set_bit()); - - // Enable USB interface. // - - usb.usbcon - .modify(|_, w| w.usbe().set_bit().frzclk().set_bit()); - - // Configuring PLL. // - - pll.pllfrq - .modify(|_, w| w.pdiv().mhz96().plltm().factor_15().pllusb().set_bit()); - - // Enable PLL. // - - pll.pllcsr - .modify(|_, w| w.pindiv().set_bit().plle().set_bit()); - - while pll.pllcsr.read().plock().bit_is_clear() {} - - // Unfreeze clock. // - - usb.usbcon - .modify(|_, w| w.frzclk().clear_bit().otgpade().set_bit()); - - // Interrupts. // - - usb.udien - .modify(|_, w| w.eorste().set_bit().sofe().set_bit()); - - // Set high speed and attach the USB. // - - usb.udcon - .modify(|_, w| w.lsm().set_bit().detach().clear_bit()); - }) - } - - fn force_reset(&self) -> usb_device::Result<()> { - free(|cs| { - let usb = self.usb.borrow(cs); - - usb.usbcon.modify(|_, w| w.usbe().clear_bit()); - usb.usbcon.modify(|_, w| w.usbe().set_bit()); - - Ok(()) - }) - } - - fn is_stalled(&self, ep_addr: EndpointAddress) -> bool { - todo!(); - } - - fn poll(&self) -> PollResult { - todo!(); - } - - fn read(&self, ep_addr: EndpointAddress, buf: &mut [u8]) -> usb_device::Result { - todo!(); - } - - fn reset(&self) { - todo!(); - } - - fn resume(&self) { - free(|cs| { - let usb = self.usb.borrow(cs); - let pll = self.pll.borrow(cs); - - // Enable PLL and wait PLL lock. // - - pll.pllcsr.modify(|_, w| w.plle().set_bit()); - - while pll.pllcsr.read().plock().bit_is_clear() {} - - // Unfreeze USB clock. // - - usb.usbcon.modify(|_, w| w.frzclk().clear_bit()); - - // Clear resume informations. // - - usb.udint - .modify(|_, w| w.wakeupi().clear_bit().suspi().clear_bit()); - - usb.udien - .modify(|_, w| w.wakeupe().clear_bit().suspe().set_bit()); - }) - } - - fn set_device_address(&self, addr: u8) { - free(|cs| { - let usb = self.usb.borrow(cs); - - // Set address. // - - usb.udaddr.modify(|_, w| w.uadd().bits(addr)); - - // Note: ADDEN and UADD shall not be written at the same time. - // (written in atmega32u4/16u4 docs) - - // Enable. // - - usb.udaddr.modify(|_, w| w.adden().set_bit()); - }); - } - - fn set_stalled(&self, ep_addr: EndpointAddress, stalled: bool) { - todo!(); - } - - fn suspend(&self) { - todo!(); - } - - fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> UsbResult { - todo!(); - } -}