blob: b45bee9ce80651ac553ea09e2940a64ec0b7325f [file] [log] [blame]
/**
* \file
*
* \brief USB Device Human Interface Device (HID) mouse interface.
*
* Copyright (C) 2009 Atmel Corporation. All rights reserved.
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel AVR product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include "conf_usb.h"
#include "usb_protocol.h"
#include "udd.h"
#include "udc.h"
#include "udi_hid.h"
#include "udi_hid_mouse.h"
#include <string.h>
/**
* \addtogroup udi_hid_mouse_group
* @{
*/
/**
* \name Interface for UDC
*/
//@{
bool udi_hid_mouse_enable(void);
void udi_hid_mouse_disable(void);
bool udi_hid_mouse_setup(void);
uint8_t udi_hid_mouse_getsetting(void);
//! Global structure which contains standard UDI interface for UDC
UDC_DESC_STORAGE udi_api_t udi_api_hid_mouse = {
.enable = (bool(*)(void))udi_hid_mouse_enable,
.disable = (void (*)(void))udi_hid_mouse_disable,
.setup = (bool(*)(void))udi_hid_mouse_setup,
.getsetting = (uint8_t(*)(void))udi_hid_mouse_getsetting,
};
//@}
/**
* \name Internal defines and variables to manage HID mouse
*/
//@{
//! Size of report for standard HID mouse
#define UDI_HID_MOUSE_REPORT_SIZE 4
//! To store current rate of HID mouse
static uint8_t udi_hid_mouse_rate;
//! To store current protocol of HID mouse
static uint8_t udi_hid_mouse_protocol;
//! To signal if a valid report is ready to send
static bool udi_hid_mouse_b_report_valid;
//! Report ready to send
static uint8_t udi_hid_mouse_report[UDI_HID_MOUSE_REPORT_SIZE];
//! Signal if a report transfer is on going
static bool udi_hid_mouse_report_trans_ongoing;
//! Buffer used to send report
COMPILER_WORD_ALIGNED
static uint8_t
udi_hid_mouse_report_trans[UDI_HID_MOUSE_REPORT_SIZE];
/**
* \brief Callback for set report setup request
*
* \return \c 1 always, because it is not used on mouse interface
*/
static bool udi_hid_mouse_setreport(void);
//@}
//! HID report descriptor for standard HID mouse
UDC_DESC_STORAGE udi_hid_mouse_report_desc_t udi_hid_mouse_report_desc = {
{
0x05, 0x01, /* Usage Page (Generic Desktop), */
0x09, 0x02, /* Usage (Mouse), */
0xA1, 0x01, /* Collection (Application), */
0x09, 0x01, /* Usage (Pointer), */
0xA1, 0x00, /* Collection (Physical), */
0x05, 0x09, /* Usage Page (Buttons), */
0x19, 0x01, /* Usage Minimum (01), */
0x29, 0x03, /* Usage Maximum (03), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x03, /* Report Count (3), */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0x75, 0x05, /* Report Size (5), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x01, /* Input (Constant), */
0x05, 0x01, /* Usage Page (Generic Desktop), */
0x09, 0x30, /* Usage (X), */
0x09, 0x31, /* Usage (Y), */
0x09, 0x38, /* Usage (Scroll), */
0x15, 0x81, /* Logical Minimum (-127), */
0x25, 0x7F, /* Logical Maximum (127), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x03, /* Report Count (2), */
0x81, 0x06, /* Input (Data, Variable, Relative) */
0xC0, /* End Collection, */
0xC0, /* End Collection */
}
};
/**
* \name Internal routines
*/
//@{
/**
* \brief Moves an axe
*
* \param pos Signed value to move
* \param index_report Index of report to move
* (3=scroll wheel, 2=axe Y, 1=axe X))
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
static bool udi_hid_mouse_move(int8_t pos, uint8_t index_report);
/**
* \brief Changes a button state
*
* \param b_state New button state
* \param btn Index of button to change (4=middle, 2=right, 1=left)
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
static bool udi_hid_mouse_btn(bool b_state, uint8_t btn);
/**
* \brief Send the report
*
* \return \c 1 if send on going, \c 0 if delay.
*/
static bool udi_hid_mouse_send_report(void);
/**
* \brief Callback called when the report is sent
*
* \param status UDD_EP_TRANSFER_OK, if transfer finish
* \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
* \param nb_sent number of data transfered
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
void udi_hid_mouse_report_sent(udd_ep_status_t status, iram_size_t nb_sent);
//@}
//--------------------------------------------
//------ Interface for UDI HID level
bool udi_hid_mouse_enable(void)
{
// Initialize internal value
udi_hid_mouse_rate = 0;
udi_hid_mouse_protocol = 0;
udi_hid_mouse_report_trans_ongoing = false;
memset(udi_hid_mouse_report, 0, UDI_HID_MOUSE_REPORT_SIZE);
udi_hid_mouse_b_report_valid = false;
return UDI_HID_MOUSE_ENABLE_EXT();
}
void udi_hid_mouse_disable(void)
{
UDI_HID_MOUSE_DISABLE_EXT();
}
bool udi_hid_mouse_setup(void)
{
return udi_hid_setup(&udi_hid_mouse_rate,
&udi_hid_mouse_protocol,
(uint8_t *) &udi_hid_mouse_report_desc,
udi_hid_mouse_setreport);
}
uint8_t udi_hid_mouse_getsetting(void)
{
return 0;
}
static bool udi_hid_mouse_setreport(void)
{
return false;
}
//--------------------------------------------
//------ Interface for application
bool udi_hid_mouse_moveScroll(int8_t pos)
{
return udi_hid_mouse_move(pos, 3);
}
bool udi_hid_mouse_moveY(int8_t pos_y)
{
return udi_hid_mouse_move(pos_y, 2);
}
bool udi_hid_mouse_moveX(int8_t pos_x)
{
return udi_hid_mouse_move(pos_x, 1);
}
bool udi_hid_mouse_btnmiddle(bool b_state)
{
return udi_hid_mouse_btn(b_state, 0x04);
}
bool udi_hid_mouse_btnright(bool b_state)
{
return udi_hid_mouse_btn(b_state, 0x02);
}
bool udi_hid_mouse_btnleft(bool b_state)
{
return udi_hid_mouse_btn(b_state, 0x01);
}
//--------------------------------------------
//------ Internal routines
static bool udi_hid_mouse_move(int8_t pos, uint8_t index_report)
{
int16_t s16_newpos;
irqflags_t flags = cpu_irq_save();
// Add position in HID mouse report
s16_newpos = (int8_t) udi_hid_mouse_report[index_report];
s16_newpos += pos;
if ((-127 > s16_newpos) || (127 < s16_newpos)) {
cpu_irq_restore(flags);
return false; // Overflow of report
}
udi_hid_mouse_report[index_report] = (uint8_t) s16_newpos;
// Valid and send report
udi_hid_mouse_b_report_valid = true;
udi_hid_mouse_send_report();
cpu_irq_restore(flags);
return true;
}
static bool udi_hid_mouse_btn(bool b_state, uint8_t btn)
{
// Modify buttons report
if (HID_MOUSE_BTN_DOWN == b_state)
udi_hid_mouse_report[0] |= btn;
else
udi_hid_mouse_report[0] &= ~btn;
// Use mouse move routine
return udi_hid_mouse_move(0, 1);
}
static bool udi_hid_mouse_send_report(void)
{
if (udi_hid_mouse_report_trans_ongoing)
return false; // Transfer on going then send this one after transfer complete
// Copy report on other array used only for transfer
memcpy(udi_hid_mouse_report_trans, udi_hid_mouse_report,
UDI_HID_MOUSE_REPORT_SIZE);
memset(&udi_hid_mouse_report[1], 0, 3); // Keep status of btn for next report
udi_hid_mouse_b_report_valid = false;
// Send report
udi_hid_mouse_report_trans_ongoing =
udd_ep_run( UDI_HID_MOUSE_EP_IN,
false,
udi_hid_mouse_report_trans,
UDI_HID_MOUSE_REPORT_SIZE,
udi_hid_mouse_report_sent);
return udi_hid_mouse_report_trans_ongoing;
}
void udi_hid_mouse_report_sent(udd_ep_status_t status, iram_size_t nb_sent)
{
// Valid report sending
udi_hid_mouse_report_trans_ongoing = false;
if (udi_hid_mouse_b_report_valid) {
// Send new valid report
udi_hid_mouse_send_report();
}
}
//@}