#include <libudev.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "atca_hal.h"
#include "hal_linux_kit_hid.h"
#include "hal/kit_protocol.h"
atcahid_t _gHid;
ATCA_STATUS hal_kit_hid_discover_buses(int hid_buses[], int max_buses)
{
return ATCA_UNIMPLEMENTED;
}
ATCA_STATUS hal_kit_hid_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found)
{
return ATCA_UNIMPLEMENTED;
}
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;
if ((cfg == NULL) || (phal == NULL))
{
return ATCA_BAD_PARAM;
}
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;
udev = udev_new();
if (udev == NULL)
{
return ATCA_COMM_FAIL;
}
enumerate = udev_enumerate_new(udev);
if (enumerate == NULL)
{
udev_unref(udev);
return ATCA_COMM_FAIL;
}
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);
}
}
memset(hid_filter, 0, sizeof(hid_filter));
sprintf(hid_filter, "vid_%04x&pid_%04x", cfg->atcahid.vid, cfg->atcahid.pid);
udev_list_entry_foreach(list_entry, list)
{
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");
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"));
if (strcasecmp(device_hid, hid_filter) == 0)
{
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;
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 }
else
{
#ifdef KIT_DEBUG
printf("fopen(\"%s\") failed with errno=%d\n",
udev_device_get_devnode(syspath_device),
errno);
#endif }
}
udev_device_unref(syspath_device);
}
if (index > 0)
{
_gHid.num_kits_found = index;
phal->hal_data = &_gHid;
}
udev_enumerate_unref(enumerate);
udev_unref(udev);
return ATCA_SUCCESS;
}
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;
}
for (i = 0; i < pHid->num_kits_found; i++)
{
status = kit_init(iface);
if (status != ATCA_SUCCESS)
{
BREAK(status, "kit_init() Failed");
}
}
return status;
}
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;
}
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;
}
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;
}
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;
if (strstr((char*)rxdata, "\n") != NULL)
{
continue_read = false;
}
}
while (continue_read == true);
*rxsize = total_bytes_read;
return ATCA_SUCCESS;
}
ATCA_STATUS kit_phy_num_found(int8_t* num_found)
{
*num_found = _gHid.num_kits_found;
return ATCA_SUCCESS;
}
ATCA_STATUS hal_kit_hid_send(ATCAIface iface, uint8_t* txdata, int txlength)
{
return kit_send(iface, txdata, txlength);
}
ATCA_STATUS hal_kit_hid_receive(ATCAIface iface, uint8_t* rxdata, uint16_t* rxsize)
{
return kit_receive(iface, rxdata, rxsize);
}
ATCA_STATUS hal_kit_hid_wake(ATCAIface iface)
{
return kit_wake(iface);
}
ATCA_STATUS hal_kit_hid_idle(ATCAIface iface)
{
return kit_idle(iface);
}
ATCA_STATUS hal_kit_hid_sleep(ATCAIface iface)
{
return kit_sleep(iface);
}
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;
}
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;
}