/** * \file * \brief ATCA Hardware abstraction layer for Linux using kit protocol over a USB HID device. * * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. * * \page License * * Subject to your compliance with these terms, you may use Microchip software * and any derivatives exclusively with Microchip products. It is your * responsibility to comply with third party license terms applicable to your * use of third party software (including open source software) that may * accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR * THIS SOFTWARE. */ #include #include #include #include #include "atca_hal.h" #include "hal_linux_kit_hid.h" #include "hal/kit_protocol.h" /** \defgroup hal_ Hardware abstraction layer (hal_) * * \brief * These methods define the hardware abstraction layer for communicating with a CryptoAuth device * @{ */ // File scope globals atcahid_t _gHid; /** \brief discover hid buses available for this hardware * this maintains a list of logical to physical bus mappings freeing the application * of the a-priori knowledge.This function is currently not implemented. * \param[in] cdc_buses - an array of logical bus numbers * \param[in] max_buses - maximum number of buses the app wants to attempt to discover * \return ATCA_UNIMPLEMENTED */ ATCA_STATUS hal_kit_hid_discover_buses(int hid_buses[], int max_buses) { return ATCA_UNIMPLEMENTED; } /** \brief discover any CryptoAuth devices on a given logical bus number.This function is currently not implemented. * \param[in] bus_num - logical bus number on which to look for CryptoAuth devices * \param[out] cfg[] - pointer to head of an array of interface config structures which get filled in by this method * \param[out] *found - number of devices found on this bus * \return ATCA_UNIMPLEMENTED */ ATCA_STATUS hal_kit_hid_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found) { return ATCA_UNIMPLEMENTED; } /** \brief HAL implementation of Kit USB HID init * \param[in] hal pointer to HAL specific data that is maintained by this HAL * \param[in] cfg pointer to HAL specific configuration data that is used to initialize this HAL * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_init(void* hal, ATCAIfaceCfg* cfg) { ATCAHAL_t *phal = (ATCAHAL_t*)hal; int status = 0; struct udev *udev = NULL; struct udev_enumerate *enumerate = NULL; struct udev_list_entry *list = NULL; struct udev_list_entry *list_entry = NULL; struct udev_device *syspath_device = NULL; struct udev_device *device = NULL; int i = 0; char hid_filter[20]; char device_hid[20]; FILE *file_descriptor = NULL; int index = 0; // Check the input variables if ((cfg == NULL) || (phal == NULL)) { return ATCA_BAD_PARAM; } // Initialize the _gHid structure memset(&_gHid, 0, sizeof(_gHid)); for (i = 0; i < HID_DEVICES_MAX; i++) { _gHid.kits[i].read_handle = NULL; _gHid.kits[i].write_handle = NULL; } _gHid.num_kits_found = 0; // Create the udev object udev = udev_new(); if (udev == NULL) { return ATCA_COMM_FAIL; } // Create the enumerate object enumerate = udev_enumerate_new(udev); if (enumerate == NULL) { // Free the udev object udev_unref(udev); return ATCA_COMM_FAIL; } // Create the list of available USB devices status = udev_enumerate_add_match_subsystem(enumerate, "hidraw"); if (status >= 0) { status = udev_enumerate_scan_devices(enumerate); if (status >= 0) { list = udev_enumerate_get_list_entry(enumerate); } } // Create the HID filter string memset(hid_filter, 0, sizeof(hid_filter)); sprintf(hid_filter, "vid_%04x&pid_%04x", cfg->atcahid.vid, cfg->atcahid.pid); // Find the available kit USB devices udev_list_entry_foreach(list_entry, list) { // Get the udev device syspath_device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); device = udev_device_get_parent_with_subsystem_devtype(syspath_device, "usb", "usb_device"); // Create the device HID string memset(device_hid, 0, sizeof(device_hid)); sprintf(device_hid, "vid_%s&pid_%s", udev_device_get_sysattr_value(device, "idVendor"), udev_device_get_sysattr_value(device, "idProduct")); // Determine if this is the correct kit USB device if (strcasecmp(device_hid, hid_filter) == 0) { // Open the kit USB device for reading and writing if (_gHid.kits[index].read_handle != NULL) { fclose(_gHid.kits[index].read_handle); } if (_gHid.kits[index].write_handle != NULL) { fclose(_gHid.kits[index].write_handle); } file_descriptor = fopen(udev_device_get_devnode(syspath_device), "rb+"); if (file_descriptor != NULL) { _gHid.kits[index].read_handle = file_descriptor; _gHid.kits[index].write_handle = file_descriptor; // Increment the opened kit USB device index index++; #ifdef KIT_DEBUG printf("Kit USB Device Node: %s\n", udev_device_get_devnode(syspath_device)); printf(" Manufacturer %s (%s)\n", udev_device_get_sysattr_value(device, "manufacturer"), udev_device_get_sysattr_value(device, "product")); printf(" VID/PID: %s %s\n", udev_device_get_sysattr_value(device, "idVendor"), udev_device_get_sysattr_value(device, "idProduct")); #endif // KIT_DEBUG } else { #ifdef KIT_DEBUG printf("fopen(\"%s\") failed with errno=%d\n", udev_device_get_devnode(syspath_device), errno); #endif // KIT_DEBUG } } // Free the udev device object udev_device_unref(syspath_device); } // Save the results of this discovery of HID if (index > 0) { _gHid.num_kits_found = index; phal->hal_data = &_gHid; } // Free the enumerator object udev_enumerate_unref(enumerate); // Free the udev object udev_unref(udev); return ATCA_SUCCESS; } /** \brief HAL implementation of Kit HID post init * \param[in] iface instance * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_post_init(ATCAIface iface) { ATCA_STATUS status = ATCA_SUCCESS; atcahid_t* pHid = atgetifacehaldat(iface); ATCAIfaceCfg *pCfg = atgetifacecfg(iface); int i = 0; if ((pHid == NULL) || (pCfg == NULL)) { return ATCA_BAD_PARAM; } // Perform the kit protocol init for (i = 0; i < pHid->num_kits_found; i++) { status = kit_init(iface); if (status != ATCA_SUCCESS) { BREAK(status, "kit_init() Failed"); } } return status; } /** \brief HAL implementation of send over Kit protocol.This function is called by the top layer. * \param[in] iface instance * \param[in] txdata pointer to bytes to send * \param[in] txlength number of bytes to send * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS kit_phy_send(ATCAIface iface, uint8_t* txdata, int txlength) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); atcahid_t* pHid = (atcahid_t*)atgetifacehaldat(iface); size_t bytes_written = 0; if ((txdata == NULL) || (cfg == NULL) || (pHid == NULL)) { return ATCA_BAD_PARAM; } if (pHid->kits[cfg->atcahid.idx].write_handle == NULL) { return ATCA_COMM_FAIL; } // Send the data to the kit USB device if (txlength > 0) { bytes_written = fwrite(txdata, sizeof(uint8_t), txlength, pHid->kits[cfg->atcahid.idx].write_handle); if (bytes_written != txlength) { clearerr(pHid->kits[cfg->atcahid.idx].write_handle); return ATCA_TX_FAIL; } } return ATCA_SUCCESS; } /** \brief HAL implementation of kit protocol receive.This function is called by the top layer. * \param[in] iface instance * \param[out] rxdata pointer to space to receive the data * \param[inout] rxsize ptr to expected number of receive bytes to request * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS kit_phy_receive(ATCAIface iface, uint8_t* rxdata, int* rxsize) { ATCAIfaceCfg *cfg = atgetifacecfg(iface); atcahid_t* pHid = (atcahid_t*)atgetifacehaldat(iface); bool continue_read = true; size_t bytes_read = 0; size_t total_bytes_read = 0; if ((rxdata == NULL) || (rxsize == NULL) || (cfg == NULL) || (pHid == NULL)) { return ATCA_BAD_PARAM; } if (pHid->kits[cfg->atcahid.idx].read_handle == NULL) { return ATCA_COMM_FAIL; } // Receive the data from the kit USB device do { bytes_read = fread(&rxdata[total_bytes_read], sizeof(uint8_t), 1, pHid->kits[cfg->atcahid.idx].read_handle); if (ferror(pHid->kits[cfg->atcahid.idx].read_handle) != 0) { clearerr(pHid->kits[cfg->atcahid.idx].read_handle); return ATCA_RX_FAIL; } total_bytes_read += bytes_read; // Check if the kit protocol message has been received if (strstr((char*)rxdata, "\n") != NULL) { continue_read = false; } } while (continue_read == true); // Save the total bytes read *rxsize = total_bytes_read; return ATCA_SUCCESS; } /** \brief Number of USB HID devices found * \param[out] num_found * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS kit_phy_num_found(int8_t* num_found) { *num_found = _gHid.num_kits_found; return ATCA_SUCCESS; } /** \brief HAL implementation of kit protocol send over USB HID * \param[in] iface instance * \param[in] txdata pointer to bytes to send * \param[in] txlength number of bytes to send * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_send(ATCAIface iface, uint8_t* txdata, int txlength) { // Call the kit_send() function that will call phy_send() implemented below return kit_send(iface, txdata, txlength); } /** \brief HAL implementation of send over USB HID * \param[in] iface instance * \param[in] rxdata pointer to space to receive the data * \param[inout] rxsize ptr to expected number of receive bytes to request * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_receive(ATCAIface iface, uint8_t* rxdata, uint16_t* rxsize) { // Call the kit_receive() function that will call phy_receive() implemented below return kit_receive(iface, rxdata, rxsize); } /** \brief Call the wake for kit protocol over USB HID * \param[in] iface ATCAIface instance that is the interface object to send the bytes over * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_wake(ATCAIface iface) { // Call the kit_wake() function that will call phy_send() and phy_receive() return kit_wake(iface); } /** \brief Call the idle for kit protocol over USB HID * \param[in] iface ATCAIface instance that is the interface object to send the bytes over * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_idle(ATCAIface iface) { // Call the kit_idle() function that will call phy_send() and phy_receive() return kit_idle(iface); } /** \brief Call the sleep for kit protocol over USB HID * \param[in] iface ATCAIface instance that is the interface object to send the bytes over * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_sleep(ATCAIface iface) { // Call the kit_sleep() function that will call phy_send() and phy_receive() return kit_sleep(iface); } /** \brief Close the physical port for HID * \param[in] hal_data The hardware abstraction data specific to this HAL * \return ATCA_SUCCESS on success, otherwise an error code. */ ATCA_STATUS hal_kit_hid_release(void* hal_data) { atcahid_t* phaldat = (atcahid_t*)hal_data; int i = 0; if (phaldat == NULL) { return ATCA_BAD_PARAM; } // Close all kit USB devices for (i = 0; i < phaldat->num_kits_found; i++) { if (_gHid.kits[i].read_handle != NULL) { fclose(_gHid.kits[i].read_handle); _gHid.kits[i].read_handle = NULL; _gHid.kits[i].write_handle = NULL; } } return ATCA_SUCCESS; } /** @} */