aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/stm32/can.c24
-rw-r--r--lib/stm32/desig.c22
-rw-r--r--lib/stm32/f1/dma.c5
-rw-r--r--lib/stm32/f1/gpio.c4
-rw-r--r--lib/stm32/f1/rcc.c167
-rw-r--r--lib/stm32/f1/rtc.c2
-rw-r--r--lib/stm32/i2c.c144
-rw-r--r--lib/usb/usb.c3
-rw-r--r--lib/usb/usb_control.c5
-rw-r--r--lib/usb/usb_private.h1
-rw-r--r--lib/usb/usb_standard.c73
11 files changed, 417 insertions, 33 deletions
diff --git a/lib/stm32/can.c b/lib/stm32/can.c
index 9b2f22a..7fde585 100644
--- a/lib/stm32/can.c
+++ b/lib/stm32/can.c
@@ -85,7 +85,8 @@ Initialize the selected CAN peripheral block.
@returns int 0 on success, 1 on initialization failure.
*/
int can_init(u32 canport, bool ttcm, bool abom, bool awum, bool nart,
- bool rflm, bool txfp, u32 sjw, u32 ts1, u32 ts2, u32 brp)
+ bool rflm, bool txfp, u32 sjw, u32 ts1, u32 ts2, u32 brp,
+ bool loopback, bool silent)
{
u32 wait_ack = 0x00000000;
u32 can_msr_inak_timeout = 0x0000FFFF;
@@ -107,6 +108,9 @@ int can_init(u32 canport, bool ttcm, bool abom, bool awum, bool nart,
if ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK)
return 1;
+ /* clear can timing bits */
+ CAN_BTR(canport) = 0;
+
/* Set the automatic bus-off management. */
if (ttcm)
CAN_MCR(canport) |= CAN_MCR_TTCM;
@@ -138,8 +142,19 @@ int can_init(u32 canport, bool ttcm, bool abom, bool awum, bool nart,
else
CAN_MCR(canport) &= ~CAN_MCR_TXFP;
+ if (silent)
+ CAN_BTR(canport) |= CAN_BTR_SILM;
+ else
+ CAN_BTR(canport) &= ~CAN_BTR_SILM;
+
+ if (loopback)
+ CAN_BTR(canport) |= CAN_BTR_LBKM;
+ else
+ CAN_BTR(canport) &= ~CAN_BTR_LBKM;
+
+
/* Set bit timings. */
- CAN_BTR(canport) = sjw | ts2 | ts1 |
+ CAN_BTR(canport) |= sjw | ts2 | ts1 |
(u32)(CAN_BTR_BRP_MASK & (brp - 1));
/* Request initialization "leave". */
@@ -456,3 +471,8 @@ void can_receive(u32 canport, u8 fifo, bool release, u32 *id, bool *ext,
if (release)
can_fifo_release(canport, fifo);
}
+
+bool can_available_mailbox(u32 canport)
+{
+ return CAN_TSR(canport) & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2);
+}
diff --git a/lib/stm32/desig.c b/lib/stm32/desig.c
index 0743dc8..ea861aa 100644
--- a/lib/stm32/desig.c
+++ b/lib/stm32/desig.c
@@ -35,3 +35,25 @@ void desig_get_unique_id(u32 result[])
result[1] = bits63_32;
result[2] = bits31_16 << 16 | bits15_0;
}
+
+void desig_get_unique_id_as_string(char *string,
+ unsigned int string_len)
+{
+ int i, len;
+ u8 device_id[12];
+ static const char chars[] = "0123456789ABCDEF";
+
+ desig_get_unique_id((u32 *)device_id);
+
+ /* Each byte produces two characters */
+ len = (2 * sizeof(device_id) < string_len) ?
+ 2 * sizeof(device_id) : string_len - 1;
+
+ for (i = 0; i < len; i += 2) {
+ string[i] = chars[(device_id[i / 2] >> 0) & 0x0F];
+ string[i + 1] = chars[(device_id[i / 2] >> 4) & 0x0F];
+ }
+
+ string[len] = '\0';
+}
+
diff --git a/lib/stm32/f1/dma.c b/lib/stm32/f1/dma.c
index fa7fb72..1f06c11 100644
--- a/lib/stm32/f1/dma.c
+++ b/lib/stm32/f1/dma.c
@@ -433,5 +433,10 @@ void dma_set_number_of_data(u32 dma, u8 channel, u16 number)
{
DMA_CNDTR(dma, channel) = number;
}
+
+void dma_clear_flag(u32 dma, u32 flag)
+{
+ DMA_ISR(dma) &= ~flag;
+}
/**@}*/
diff --git a/lib/stm32/f1/gpio.c b/lib/stm32/f1/gpio.c
index f0b7f70..2b33cad 100644
--- a/lib/stm32/f1/gpio.c
+++ b/lib/stm32/f1/gpio.c
@@ -164,7 +164,7 @@ value cannot be ascertained from the hardware.
*/
void gpio_primary_remap(u8 swjdisable, u32 maps)
{
- AFIO_MAPR = swjdisable | (maps & 0x1FFFFF);
+ AFIO_MAPR |= swjdisable | (maps & 0x1FFFFF);
}
/*-----------------------------------------------------------------------------*/
@@ -182,7 +182,7 @@ The AFIO remapping feature is used only with the STM32F10x series.
*/
void gpio_secondary_remap(u32 maps)
{
- AFIO_MAPR2 = maps;
+ AFIO_MAPR2 |= maps;
}
/**@}*/
diff --git a/lib/stm32/f1/rcc.c b/lib/stm32/f1/rcc.c
index ab3350b..9cd8658 100644
--- a/lib/stm32/f1/rcc.c
+++ b/lib/stm32/f1/rcc.c
@@ -71,6 +71,12 @@ void rcc_osc_ready_int_clear(osc_t osc)
case PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
+ case PLL2:
+ RCC_CIR |= RCC_CIR_PLL2RDYC;
+ break;
+ case PLL3:
+ RCC_CIR |= RCC_CIR_PLL3RDYC;
+ break;
case HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
@@ -98,6 +104,12 @@ void rcc_osc_ready_int_enable(osc_t osc)
case PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
+ case PLL2:
+ RCC_CIR |= RCC_CIR_PLL2RDYIE;
+ break;
+ case PLL3:
+ RCC_CIR |= RCC_CIR_PLL3RDYIE;
+ break;
case HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
@@ -125,6 +137,12 @@ void rcc_osc_ready_int_disable(osc_t osc)
case PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
+ case PLL2:
+ RCC_CIR &= ~RCC_CIR_PLL2RDYIE;
+ break;
+ case PLL3:
+ RCC_CIR &= ~RCC_CIR_PLL3RDYIE;
+ break;
case HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
@@ -153,6 +171,12 @@ int rcc_osc_ready_int_flag(osc_t osc)
case PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
+ case PLL2:
+ return ((RCC_CIR & RCC_CIR_PLL2RDYF) != 0);
+ break;
+ case PLL3:
+ return ((RCC_CIR & RCC_CIR_PLL3RDYF) != 0);
+ break;
case HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
@@ -203,6 +227,12 @@ void rcc_wait_for_osc_ready(osc_t osc)
case PLL:
while ((RCC_CR & RCC_CR_PLLRDY) == 0);
break;
+ case PLL2:
+ while ((RCC_CR & RCC_CR_PLL2RDY) == 0);
+ break;
+ case PLL3:
+ while ((RCC_CR & RCC_CR_PLL3RDY) == 0);
+ break;
case HSE:
while ((RCC_CR & RCC_CR_HSERDY) == 0);
break;
@@ -238,6 +268,12 @@ void rcc_osc_on(osc_t osc)
case PLL:
RCC_CR |= RCC_CR_PLLON;
break;
+ case PLL2:
+ RCC_CR |= RCC_CR_PLL2ON;
+ break;
+ case PLL3:
+ RCC_CR |= RCC_CR_PLL3ON;
+ break;
case HSE:
RCC_CR |= RCC_CR_HSEON;
break;
@@ -273,6 +309,12 @@ void rcc_osc_off(osc_t osc)
case PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
+ case PLL2:
+ RCC_CR &= ~RCC_CR_PLL2ON;
+ break;
+ case PLL3:
+ RCC_CR &= ~RCC_CR_PLL3ON;
+ break;
case HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
@@ -331,6 +373,8 @@ void rcc_osc_bypass_enable(osc_t osc)
RCC_BDCR |= RCC_BDCR_LSEBYP;
break;
case PLL:
+ case PLL2:
+ case PLL3:
case HSI:
case LSI:
/* Do nothing, only HSE/LSE allowed here. */
@@ -361,6 +405,8 @@ void rcc_osc_bypass_disable(osc_t osc)
RCC_BDCR &= ~RCC_BDCR_LSEBYP;
break;
case PLL:
+ case PLL2:
+ case PLL3:
case HSI:
case LSI:
/* Do nothing, only HSE/LSE allowed here. */
@@ -485,6 +531,40 @@ void rcc_set_pll_multiplication_factor(u32 mul)
}
/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL2 Multiplication Factor.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+*/
+
+void rcc_set_pll2_multiplication_factor(u32 mul)
+{
+ u32 reg32;
+
+ reg32 = RCC_CFGR2;
+ reg32 &= ~((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8));
+ RCC_CFGR2 = (reg32 | (mul << 8));
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL3 Multiplication Factor.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+*/
+
+void rcc_set_pll3_multiplication_factor(u32 mul)
+{
+ u32 reg32;
+
+ reg32 = RCC_CFGR2;
+ reg32 &= ~((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12));
+ RCC_CFGR2 = (reg32 | (mul << 12));
+}
+
+/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the PLL Clock Source.
@note This only has effect when the PLL is disabled.
@@ -602,6 +682,36 @@ void rcc_set_usbpre(u32 usbpre)
RCC_CFGR = (reg32 | (usbpre << 22));
}
+void rcc_set_prediv1(u32 prediv)
+{
+ u32 reg32;
+ reg32 = RCC_CFGR2;
+ reg32 &= ~(1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
+ RCC_CFGR2 |= (reg32 | prediv);
+}
+
+void rcc_set_prediv2(u32 prediv)
+{
+ u32 reg32;
+ reg32 = RCC_CFGR2;
+ reg32 &= ~(1 << 7) | (1 << 6) | (1 << 5) | (1 << 4);
+ RCC_CFGR2 |= (reg32 | (prediv << 4));
+}
+
+void rcc_set_prediv1_source(u32 rccsrc)
+{
+ RCC_CFGR2 &= ~(1 << 16);
+ RCC_CFGR2 |= (rccsrc << 16);
+}
+
+void rcc_set_mco(u32 mcosrc)
+{
+ u32 reg32;
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24));
+ RCC_CFGR |= (reg32 | (mcosrc << 24));
+}
+
/*-----------------------------------------------------------------------------*/
/** @brief RCC Get the System Clock Source.
@@ -1031,6 +1141,63 @@ void rcc_clock_setup_in_hse_16mhz_out_72mhz(void)
}
/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 72MHz from HSE at 25MHz
+
+*/
+
+void rcc_clock_setup_in_hse_25mhz_out_72mhz(void)
+{
+ /* Enable external high-speed oscillator 25MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
+
+ /*
+ * Sysclk runs with 72MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_LATENCY_2WS);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+
+ /* Set pll2 prediv and multiplier */
+ rcc_set_prediv2(RCC_CFGR2_PREDIV2_DIV5);
+ rcc_set_pll2_multiplication_factor(RCC_CFGR2_PLL2MUL_PLL2_CLK_MUL8);
+
+ /* Enable PLL2 oscillator and wait for it to stabilize */
+ rcc_osc_on(PLL2);
+ rcc_wait_for_osc_ready(PLL2);
+
+ /* Set pll1 prediv/multiplier, prediv1 src, and usb predivider */
+ rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
+ rcc_set_prediv1_source(RCC_CFGR2_PREDIV1SRC_PLL2_CLK);
+ rcc_set_prediv1(RCC_CFGR2_PREDIV_DIV5);
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9);
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_PREDIV1_CLK);
+ rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3);
+
+ /* enable PLL1 and wait for it to stabilize */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 36000000;
+ rcc_ppre2_frequency = 72000000;
+}
+
+/*-----------------------------------------------------------------------------*/
/** @brief RCC Reset the backup domain
The backup domain register is reset to disable all controls.
diff --git a/lib/stm32/f1/rtc.c b/lib/stm32/f1/rtc.c
index 08a4953..cfc5f5b 100644
--- a/lib/stm32/f1/rtc.c
+++ b/lib/stm32/f1/rtc.c
@@ -67,6 +67,8 @@ void rtc_awake_from_off(osc_t clock_source)
RCC_BDCR |= (1 << 9) | (1 << 8);
break;
case PLL:
+ case PLL2:
+ case PLL3:
case HSI:
/* Unusable clock source, here to prevent warnings. */
/* Turn off clock sources to RTC. */
diff --git a/lib/stm32/i2c.c b/lib/stm32/i2c.c
index e1d3a09..a67bece 100644
--- a/lib/stm32/i2c.c
+++ b/lib/stm32/i2c.c
@@ -125,6 +125,18 @@ void i2c_send_stop(u32 i2c)
}
/*-----------------------------------------------------------------------------*/
+/** @brief I2C Clear Stop Flag.
+
+Clear the "Send Stop" flag in the I2C config register
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_clear_stop(u32 i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_STOP;
+}
+
+/*-----------------------------------------------------------------------------*/
/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
This sets an address for Slave mode operation, in 7 bit form.
@@ -269,5 +281,135 @@ void i2c_send_data(u32 i2c, u8 data)
I2C_DR(i2c) = data;
}
-/**@}*/
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Get Data.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+uint8_t i2c_get_data(u32 i2c)
+{
+ return I2C_DR(i2c) & 0xff;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Enable Interrupt
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] interrupt Unsigned int32. Interrupt to enable.
+*/
+void i2c_enable_interrupt(u32 i2c, u32 interrupt)
+{
+ I2C_CR2(i2c) |= interrupt;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Disable Interrupt
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] interrupt Unsigned int32. Interrupt to disable.
+*/
+void i2c_disable_interrupt(u32 i2c, u32 interrupt)
+{
+ I2C_CR2(i2c) &= ~interrupt;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Enable ACK
+
+Enables acking of own 7/10 bit address
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_enable_ack(u32 i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_ACK;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Disable ACK
+
+Disables acking of own 7/10 bit address
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_disable_ack(u32 i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C NACK Next Byte
+
+Causes the I2C controller to NACK the reception of the next byte
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_nack_next(u32 i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_POS;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C NACK Next Byte
+
+Causes the I2C controller to NACK the reception of the current byte
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_nack_current(u32 i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_POS;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Set clock duty cycle
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle.
+*/
+void i2c_set_dutycycle(u32 i2c, u32 dutycycle)
+{
+ if (dutycycle == I2C_CCR_DUTY_DIV2)
+ I2C_CCR(i2c) &= ~I2C_CCR_DUTY;
+ else
+ I2C_CCR(i2c) |= I2C_CCR_DUTY;
+}
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Enable DMA
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_enable_dma(u32 i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_DMAEN;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Disable DMA
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_disable_dma(u32 i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_DMAEN;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Set DMA last transfer
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_set_dma_last_transfer(u32 i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_LAST;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief I2C Clear DMA last transfer
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_clear_dma_last_transfer(u32 i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_LAST;
+}
+
+/**@}*/
diff --git a/lib/usb/usb.c b/lib/usb/usb.c
index ecebde2..0799202 100644
--- a/lib/usb/usb.c
+++ b/lib/usb/usb.c
@@ -44,7 +44,7 @@ u8 usbd_control_buffer[128] __attribute__((weak));
usbd_device *usbd_init(const usbd_driver *driver,
const struct usb_device_descriptor *dev,
const struct usb_config_descriptor *conf,
- const char **strings)
+ const char **strings, int num_strings)
{
usbd_device *usbd_dev;
@@ -54,6 +54,7 @@ usbd_device *usbd_init(const usbd_driver *driver,
usbd_dev->desc = dev;
usbd_dev->config = conf;
usbd_dev->strings = strings;
+ usbd_dev->num_strings = num_strings;
usbd_dev->ctrl_buf = usbd_control_buffer;
usbd_dev->ctrl_buf_len = sizeof(usbd_control_buffer);
diff --git a/lib/usb/usb_control.c b/lib/usb/usb_control.c
index 245ab1c..82843df 100644
--- a/lib/usb/usb_control.c
+++ b/lib/usb/usb_control.c
@@ -99,11 +99,12 @@ static int usb_control_request_dispatch(usbd_device *usbd_dev,
&(usbd_dev->control_state.ctrl_buf),
&(usbd_dev->control_state.ctrl_len),
&(usbd_dev->control_state.complete));
- if (result)
+ if (result == USBD_REQ_HANDLED ||
+ result == USBD_REQ_NOTSUPP)
return result;
}
}
-
+
/* Try standard request if not already handled. */
return _usbd_standard_request(usbd_dev, req,
&(usbd_dev->control_state.ctrl_buf),
diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h
index 2506ba5..454e8c6 100644
--- a/lib/usb/usb_private.h
+++ b/lib/usb/usb_private.h
@@ -29,6 +29,7 @@ struct _usbd_device {
const struct usb_device_descriptor *desc;
const struct usb_config_descriptor *config;
const char **strings;
+ int num_strings;
u8 *ctrl_buf; /**< Internal buffer used for control transfers */
u16 ctrl_buf_len;
diff --git a/lib/usb/usb_standard.c b/lib/usb/usb_standard.c
index 5a92cd8..e14fee3 100644
--- a/lib/usb/usb_standard.c
+++ b/lib/usb/usb_standard.c
@@ -90,52 +90,75 @@ static u16 build_config_descriptor(usbd_device *usbd_dev,
return total;
}
+static int usb_descriptor_type(u16 wValue)
+{
+ return wValue >> 8;
+}
+
+static int usb_descriptor_index(u16 wValue)
+{
+ return wValue & 0xFF;
+}
+
static int usb_standard_get_descriptor(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
- int i;
+ int i, array_idx, descr_idx;
struct usb_string_descriptor *sd;
- switch (req->wValue >> 8) {
+ descr_idx = usb_descriptor_index(req->wValue);
+
+ switch (usb_descriptor_type(req->wValue)) {
case USB_DT_DEVICE:
*buf = (u8 *) usbd_dev->desc;
*len = MIN(*len, usbd_dev->desc->bLength);
- return 1;
+ return USBD_REQ_HANDLED;
case USB_DT_CONFIGURATION:
*buf = usbd_dev->ctrl_buf;
- *len = build_config_descriptor(usbd_dev, req->wValue & 0xff,
- *buf, *len);
- return 1;
+ *len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len);
+ return USBD_REQ_HANDLED;
case USB_DT_STRING:
sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf;
- if (!usbd_dev->strings)
- return 0; /* Device doesn't support strings. */
+ if (descr_idx == 0) {
+ /* Send sane Language ID descriptor... */
+ sd->wData[0] = USB_LANGID_ENGLISH_US;
+ sd->bLength = sizeof(sd->bLength) + sizeof(sd->bDescriptorType)
+ + sizeof(sd->wData[0]);
- /* Check that string index is in range. */
- for (i = 0; i <= (req->wValue & 0xff); i++)
- if (usbd_dev->strings[i] == NULL)
- return 0;
+ *len = MIN(*len, sd->bLength);
+ } else {
+ array_idx = descr_idx - 1;
- sd->bLength = strlen(usbd_dev->strings[req->wValue & 0xff])
- * 2 + 2;
- sd->bDescriptorType = USB_DT_STRING;
+ if (!usbd_dev->strings)
+ return USBD_REQ_NOTSUPP; /* Device doesn't support strings. */
+ /* Check that string index is in range. */
+ if (array_idx >= usbd_dev->num_strings)
+ return USBD_REQ_NOTSUPP;
- *buf = (u8 *)sd;
- *len = MIN(*len, sd->bLength);
+ /* Strings with Language ID differnet from
+ * USB_LANGID_ENGLISH_US are not supported */
+ if (req->wIndex != USB_LANGID_ENGLISH_US)
+ return USBD_REQ_NOTSUPP;
- for (i = 0; i < (*len / 2) - 1; i++)
- sd->wData[i] =
- usbd_dev->strings[req->wValue & 0xff][i];
+ /* Ths string is returned as UTF16, hence the multiplication */
+ sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 +
+ sizeof(sd->bLength) + sizeof(sd->bDescriptorType);
- /* Send sane Language ID descriptor... */
- if ((req->wValue & 0xff) == 0)
- sd->wData[0] = 0x409;
+ *len = MIN(*len, sd->bLength);
- return 1;
+ for (i = 0; i < (*len / 2) - 1; i++)
+ sd->wData[i] =
+ usbd_dev->strings[array_idx][i];
+ }
+
+ sd->bDescriptorType = USB_DT_STRING;
+ *buf = (u8 *)sd;
+
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static int usb_standard_set_address(usbd_device *usbd_dev,