mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-13 13:32:53 +08:00
393 lines
9.9 KiB
C
393 lines
9.9 KiB
C
/*
|
|
* This file is part of the DSLogic project.
|
|
*/
|
|
|
|
#include "libsigrok.h"
|
|
#include "hardware/DSLogic/dslogic.h"
|
|
|
|
#ifdef __linux__
|
|
#include <poll.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#endif/*__linux__*/
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
|
|
#include <initguid.h>
|
|
#include <ddk/usbiodef.h>
|
|
#include <Setupapi.h>
|
|
|
|
#include <tchar.h>
|
|
#include <conio.h>
|
|
#include <dbt.h>
|
|
#include <stdio.h>
|
|
#include <winuser.h>
|
|
|
|
#endif/*_WIN32*/
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
static void dev_list_add(struct libusbhp_t *h, const char *path,
|
|
unsigned short vid, unsigned short pid)
|
|
{
|
|
struct dev_list_t *dev =
|
|
(struct dev_list_t*)malloc(sizeof(struct dev_list_t));
|
|
dev->path = strdup(path);
|
|
dev->vid = vid;
|
|
dev->pid = pid;
|
|
dev->next = NULL;
|
|
|
|
struct dev_list_t *p = h->devlist;
|
|
if(!p) {
|
|
h->devlist = dev;
|
|
return;
|
|
}
|
|
|
|
while(p->next) {
|
|
p = p->next;
|
|
}
|
|
|
|
p->next = dev;
|
|
}
|
|
|
|
static int dev_list_remove(struct libusbhp_t *h, const char *path)
|
|
{
|
|
struct dev_list_t *p = h->devlist;
|
|
if(!p) return 1;
|
|
|
|
if(!strcmp(p->path, path)) {
|
|
h->devlist = p->next;
|
|
free(p->path);
|
|
free(p);
|
|
return 0;
|
|
}
|
|
|
|
while(p->next) {
|
|
if(!strcmp(p->next->path, path)) {
|
|
struct dev_list_t *pp = p->next;
|
|
p->next = pp->next;
|
|
free(pp->path);
|
|
free(pp->next);
|
|
free(pp);
|
|
return 0;
|
|
}
|
|
p = p->next;
|
|
}
|
|
|
|
// Not found
|
|
return 1;
|
|
}
|
|
|
|
static int dev_list_find(struct libusbhp_t *h, const char *path,
|
|
unsigned short *vid, unsigned short *pid)
|
|
{
|
|
struct dev_list_t *p = h->devlist;
|
|
while(p) {
|
|
if(!strcmp(p->path, path)) {
|
|
*vid = p->vid;
|
|
*pid = p->pid;
|
|
return 0;
|
|
}
|
|
p = p->next;
|
|
}
|
|
|
|
// Not found
|
|
return 1;
|
|
}
|
|
#endif/*__linux__*/
|
|
|
|
#ifdef _WIN32
|
|
SR_PRIV LRESULT CALLBACK WinProcCallback(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
{
|
|
struct libusbhp_t *h = (struct libusbhp_t*)GetWindowLong(hwnd, GWL_USERDATA);
|
|
|
|
switch(msg) {
|
|
case WM_DEVICECHANGE:
|
|
{
|
|
PDEV_BROADCAST_HDR phdr = (PDEV_BROADCAST_HDR)lp;
|
|
|
|
if(!phdr || phdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
|
|
|
|
PDEV_BROADCAST_DEVICEINTERFACE devif =
|
|
(PDEV_BROADCAST_DEVICEINTERFACE)lp;
|
|
|
|
HDEVINFO devinfolist = SetupDiCreateDeviceInfoList(NULL, NULL);
|
|
|
|
SP_DEVICE_INTERFACE_DATA devifdata;
|
|
memset(&devifdata, 0, sizeof(devifdata));
|
|
devifdata.cbSize = sizeof(devifdata);
|
|
BOOL b = SetupDiOpenDeviceInterface(devinfolist, devif->dbcc_name, 0,
|
|
&devifdata);
|
|
|
|
DWORD required;
|
|
SP_DEVICE_INTERFACE_DETAIL_DATA devdetaildata;
|
|
memset(&devdetaildata, 0, sizeof(devdetaildata));
|
|
devdetaildata.cbSize = sizeof(devdetaildata);
|
|
|
|
SP_DEVINFO_DATA devinfodata;
|
|
memset(&devinfodata, 0, sizeof(devinfodata));
|
|
devinfodata.cbSize = sizeof(devinfodata);
|
|
b = SetupDiGetDeviceInterfaceDetail(devinfolist, &devifdata,
|
|
&devdetaildata,
|
|
sizeof(devdetaildata),
|
|
&required, &devinfodata);
|
|
|
|
TCHAR deviceidw[1024];
|
|
b = SetupDiGetDeviceInstanceIdW(devinfolist, &devinfodata, deviceidw,
|
|
sizeof(deviceidw), NULL);
|
|
|
|
char deviceid[1024];
|
|
//size_t sz;
|
|
//wcstombs_s(&sz, deviceid, deviceidw, sizeof(deviceid) - 1);
|
|
wcstombs(deviceid, deviceidw, sizeof(deviceid) - 1);
|
|
|
|
char *vid = strstr(deviceid, "VID_");
|
|
if(vid != NULL) vid += 4;
|
|
|
|
char *pid = strstr(deviceid, "PID_");
|
|
if(pid != NULL) pid += 4;
|
|
|
|
struct libusbhp_device_t *device = NULL;
|
|
|
|
if(pid || vid) {
|
|
device =
|
|
(struct libusbhp_device_t*)malloc(sizeof(struct libusbhp_device_t));
|
|
}
|
|
|
|
if(pid) {
|
|
pid[4] = '\0';
|
|
device->idProduct = (unsigned short)strtol(pid, NULL, 16);
|
|
}
|
|
|
|
if(vid) {
|
|
vid[4] = '\0';
|
|
device->idVendor = (unsigned short)strtol(vid, NULL, 16);
|
|
}
|
|
|
|
if ((device->idVendor == supported_fx2[0].vid) &&
|
|
(device->idProduct == supported_fx2[0].pid)) {
|
|
switch(wp) {
|
|
case DBT_DEVICEARRIVAL:
|
|
if(h->attach) h->attach(device, h->user_data);
|
|
break;
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
if(h->detach) h->detach(device, h->user_data);
|
|
break;
|
|
case DBT_DEVNODES_CHANGED:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(device) free(device);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hwnd, msg, wp, lp);
|
|
}
|
|
#endif/*OS_WINDOWS*/
|
|
|
|
SR_API int libusbhp_init(struct libusbhp_t **handle)
|
|
{
|
|
struct libusbhp_t *h = (struct libusbhp_t *)malloc(sizeof(struct libusbhp_t));
|
|
|
|
h->attach = NULL;
|
|
h->detach = NULL;
|
|
h->user_data = NULL;
|
|
|
|
#ifdef __linux__
|
|
h->devlist = NULL;
|
|
|
|
// create the udev object
|
|
h->hotplug = udev_new();
|
|
if(!h->hotplug)
|
|
{
|
|
printf("Cannot create udev object\n");
|
|
free(h);
|
|
return 1;
|
|
}
|
|
|
|
// create the udev monitor
|
|
h->hotplug_monitor = udev_monitor_new_from_netlink(h->hotplug, "udev");
|
|
|
|
// start receiving hotplug events
|
|
udev_monitor_filter_add_match_subsystem_devtype(h->hotplug_monitor,
|
|
"usb", "usb_device");
|
|
udev_monitor_enable_receiving(h->hotplug_monitor);
|
|
|
|
struct udev_enumerate *de = udev_enumerate_new (h->hotplug);
|
|
udev_enumerate_add_match_subsystem(de, "usb");
|
|
udev_enumerate_scan_devices(de);
|
|
|
|
struct udev_list_entry *lst = udev_enumerate_get_list_entry(de);
|
|
while(lst) {
|
|
struct udev_device *dev =
|
|
udev_device_new_from_syspath(h->hotplug,
|
|
udev_list_entry_get_name(lst));
|
|
|
|
if(udev_device_get_devnode(dev)) {
|
|
unsigned short idVendor =
|
|
strtol(udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16);
|
|
unsigned short idProduct =
|
|
strtol(udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16);
|
|
|
|
dev_list_add(h, udev_device_get_devnode(dev), idVendor, idProduct);
|
|
}
|
|
|
|
udev_device_unref(dev);
|
|
|
|
lst = udev_list_entry_get_next(lst);
|
|
}
|
|
|
|
udev_enumerate_unref(de);
|
|
|
|
#endif/*__linux__*/
|
|
|
|
#ifdef _WIN32
|
|
memset(&h->wcex, 0, sizeof(h->wcex));
|
|
h->wcex.cbSize = sizeof(WNDCLASSEX);
|
|
h->wcex.lpfnWndProc = WinProcCallback;
|
|
h->wcex.hInstance = GetModuleHandle(NULL);
|
|
h->wcex.lpszClassName = TEXT("UsbHotplugClass");
|
|
h->wcex.cbWndExtra = sizeof(struct libusbhp_t*); // Size of data.
|
|
|
|
RegisterClassEx(&h->wcex);
|
|
|
|
h->hwnd =
|
|
CreateWindowEx(0, h->wcex.lpszClassName, TEXT("UsbHotplug"), 0, 0, 0, 0,
|
|
0, 0, NULL, GetModuleHandle(NULL), NULL);
|
|
|
|
SetWindowLong(h->hwnd, GWL_USERDATA, (LONG)h);
|
|
|
|
|
|
DEV_BROADCAST_DEVICEINTERFACE *filter =
|
|
(DEV_BROADCAST_DEVICEINTERFACE*)malloc(sizeof(DEV_BROADCAST_DEVICEINTERFACE));
|
|
|
|
memset(filter, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
|
|
filter->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
|
|
filter->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
|
filter->dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
|
|
|
|
h->hDeviceNotify =
|
|
RegisterDeviceNotification(h->hwnd, filter, DEVICE_NOTIFY_WINDOW_HANDLE);
|
|
|
|
if(h->hDeviceNotify == 0) {
|
|
//printf("RegisterDeviceNotification error\n");
|
|
free(h);
|
|
return 1;
|
|
}
|
|
#endif/*_WIN32*/
|
|
|
|
*handle = h;
|
|
return 0;
|
|
}
|
|
|
|
SR_API void libusbhp_exit(struct libusbhp_t *h)
|
|
{
|
|
#ifdef __linux__
|
|
// destroy the udev monitor
|
|
udev_monitor_unref(h->hotplug_monitor);
|
|
|
|
// destroy the udev object
|
|
udev_unref(h->hotplug);
|
|
#endif/*__linux__*/
|
|
|
|
#ifdef _WIN32
|
|
UnregisterDeviceNotification(h->hDeviceNotify);
|
|
DestroyWindow(h->hwnd);
|
|
UnregisterClass(h->wcex.lpszClassName, h->wcex.hInstance);
|
|
#endif/*_WIN32*/
|
|
|
|
free(h);
|
|
}
|
|
|
|
SR_API int libusbhp_handle_events_timeout(struct libusbhp_t *h, struct timeval *tv)
|
|
{
|
|
int ms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
|
|
|
|
#ifdef __linux__
|
|
// create the poll item
|
|
struct pollfd items[1];
|
|
items[0].fd = udev_monitor_get_fd(h->hotplug_monitor);
|
|
items[0].events = POLLIN;
|
|
items[0].revents = 0;
|
|
|
|
// while there are hotplug events to process
|
|
while(poll(items, 1, ms) > 0) {
|
|
// receive the relevant device
|
|
struct udev_device* dev = udev_monitor_receive_device(h->hotplug_monitor);
|
|
if(!dev) {
|
|
// error receiving device, skip it
|
|
continue;
|
|
}
|
|
|
|
if(!strcmp(udev_device_get_action(dev), "add")) {
|
|
struct libusbhp_device_t device;
|
|
|
|
device.idVendor =
|
|
strtol(udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16);
|
|
device.idProduct =
|
|
strtol(udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16);
|
|
|
|
dev_list_add(h, udev_device_get_devnode(dev),
|
|
device.idVendor, device.idProduct);
|
|
|
|
if(h->attach) h->attach(&device, h->user_data);
|
|
}
|
|
|
|
if(!strcmp(udev_device_get_action(dev), "remove")) {
|
|
struct libusbhp_device_t device;
|
|
|
|
int res = dev_list_find(h, udev_device_get_devnode(dev),
|
|
&device.idVendor, &device.idProduct);
|
|
|
|
if(res) {
|
|
if(h->detach) h->detach(NULL, h->user_data);
|
|
} else {
|
|
dev_list_remove(h, udev_device_get_devnode(dev));
|
|
if(h->detach) h->detach(&device, h->user_data);
|
|
}
|
|
}
|
|
|
|
// destroy the relevant device
|
|
udev_device_unref(dev);
|
|
|
|
// clear the revents
|
|
items[0].revents = 0;
|
|
}
|
|
#endif/*__linux__*/
|
|
|
|
#ifdef _WIN32
|
|
UINT_PTR timer = SetTimer(h->hwnd, 0, ms, NULL);
|
|
|
|
MSG msg;
|
|
int ret = GetMessage(&msg, NULL, 0, 0);
|
|
|
|
if(ret <= 0) return 0;
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
|
|
KillTimer(h->hwnd, timer);
|
|
#endif/*_WIN32*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
SR_API void libusbhp_register_hotplug_listeners(struct libusbhp_t *handle,
|
|
libusbhp_hotplug_cb_fn connected_cb,
|
|
libusbhp_hotplug_cb_fn disconnected_cb,
|
|
void *user_data)
|
|
{
|
|
handle->attach = connected_cb;
|
|
handle->detach = disconnected_cb;
|
|
handle->user_data = user_data;
|
|
}
|