26#include "switchtec/portable.h"
28#include "switchtec/utils.h"
29#include "../switchtec_priv.h"
33#include "windows/switchtec_public.h"
41struct switchtec_windows {
42 struct switchtec_dev dev;
46#define to_switchtec_windows(d) \
47 ((struct switchtec_windows *) \
48 ((char *)d - offsetof(struct switchtec_windows, dev)))
50static int earlier_error = 0;
52const char *platform_strerror(
void)
54 static char errmsg[500] =
"";
55 int err = GetLastError();
57 if (!err && earlier_error)
60 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |
61 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
62 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
63 errmsg,
sizeof (errmsg), NULL);
66 sprintf(errmsg,
"Error %d", err);
70static void platform_perror(
const char *msg)
72 fprintf(stderr,
"%s: %s\n", msg, platform_strerror());
75static int count_devices(
void)
79 SP_DEVICE_INTERFACE_DATA deviface;
81 devinfo = SetupDiGetClassDevs(&SWITCHTEC_INTERFACE_GUID,
82 NULL, NULL, DIGCF_DEVICEINTERFACE |
85 deviface.cbSize =
sizeof(SP_DEVICE_INTERFACE_DATA);
87 while (SetupDiEnumDeviceInterfaces(devinfo, NULL,
88 &SWITCHTEC_INTERFACE_GUID,
94static BOOL get_path(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *deviface,
95 SP_DEVINFO_DATA *devdata,
char *path,
size_t path_size)
98 SP_DEVICE_INTERFACE_DETAIL_DATA *devdetail;
102 devdata->cbSize =
sizeof(SP_DEVINFO_DATA);
104 SetupDiGetDeviceInterfaceDetail(devinfo, deviface, NULL, 0, &size,
107 devdetail = malloc(size);
109 perror(
"Enumeration");
113 devdetail->cbSize =
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
115 status = SetupDiGetDeviceInterfaceDetail(devinfo, deviface, devdetail,
116 size, NULL, devdata);
118 platform_perror(
"SetupDiGetDeviceInterfaceDetail");
122 strcpy_s(path, path_size, devdetail->DevicePath);
125 hash = strrchr(path,
'#');
134static BOOL get_pci_address(HDEVINFO devinfo, SP_DEVINFO_DATA *devdata,
135 int *bus,
int *dev,
int *func)
141 status = SetupDiGetDeviceRegistryProperty(devinfo, devdata,
142 SPDRP_LOCATION_INFORMATION, NULL,
143 (BYTE *)loc,
sizeof(loc), NULL);
145 platform_perror(
"SetupDiGetDeviceRegistryProperty (LOC)");
149 ret = sscanf(loc,
"PCI bus %d, device %d, function %d", bus, dev, func);
151 fprintf(stderr,
"Error parsing PCI BUS: '%s'\n", loc);
158static void get_pci_address_str(HDEVINFO devinfo, SP_DEVINFO_DATA *devdata,
159 char *res,
size_t res_size)
164 status = get_pci_address(devinfo, devdata, &bus, &dev, &func);
166 snprintf(res, res_size,
"??:??.?");
168 snprintf(res, res_size,
"%02x:%02x.%x", bus, dev, func);
171static void get_description(HDEVINFO devinfo, SP_DEVINFO_DATA *devdata,
172 char *res,
size_t res_size)
174 SetupDiGetDeviceRegistryProperty(devinfo, devdata,
175 SPDRP_DEVICEDESC, NULL,(BYTE *)res, res_size, NULL);
182WINSETUPAPI WINBOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO DeviceInfoSet,
183 PSP_DEVINFO_DATA DeviceInfoData,
const DEVPROPKEY *PropertyKey,
184 DEVPROPTYPE *PropertyType, PBYTE PropertyBuffer,
185 DWORD PropertyBufferSize, PDWORD RequiredSize,
188static void get_property(HDEVINFO devinfo, SP_DEVINFO_DATA *devdata,
189 const DEVPROPKEY *propkey,
char *res,
size_t res_size)
194 SetupDiGetDevicePropertyW(devinfo, devdata, propkey, &ptype,
195 (PBYTE)buf,
sizeof(buf), NULL, 0);
196 wcstombs(res, buf, res_size);
199static void get_fw_property(HDEVINFO devinfo, SP_DEVINFO_DATA *devdata,
200 char *res,
size_t res_size)
205 get_property(devinfo, devdata, &SWITCHTEC_PROP_FW_VERSION,
208 fw_ver = strtol(buf, NULL, 16);
211 snprintf(res, res_size,
"unknown");
213 version_to_string(fw_ver, res, res_size);
216static void append_guid(
const char *path,
char *path_with_guid,
size_t bufsize,
219 snprintf(path_with_guid, bufsize,
220 "%s#{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
221 path, guid->Data1, guid->Data2, guid->Data3,
222 guid->Data4[0], guid->Data4[1], guid->Data4[2],
223 guid->Data4[3], guid->Data4[4], guid->Data4[5],
224 guid->Data4[6], guid->Data4[7]);
228#define __force __attribute__((force))
233static BOOL map_gas(
struct switchtec_windows *wdev)
238 status = DeviceIoControl(wdev->hdl, IOCTL_SWITCHTEC_GAS_MAP, NULL, 0,
239 &map,
sizeof(map), NULL, NULL);
241 earlier_error = GetLastError();
245 wdev->dev.gas_map = (
gasptr_t __force)map.gas;
246 wdev->dev.gas_map_size = map.length;
250static void unmap_gas(
struct switchtec_windows *wdev)
253 .gas = (
void * __force)wdev->dev.gas_map,
254 .length = wdev->dev.gas_map_size,
257 DeviceIoControl(wdev->hdl, IOCTL_SWITCHTEC_GAS_UNMAP, &map,
sizeof(map),
258 NULL, 0, NULL, NULL);
261static void windows_close(
struct switchtec_dev *dev)
263 struct switchtec_windows *wdev = to_switchtec_windows(dev);
266 CloseHandle(wdev->hdl);
272 SP_DEVICE_INTERFACE_DATA deviface;
273 SP_DEVINFO_DATA devdata;
280 dl = *devlist = calloc(count_devices(),
287 devinfo = SetupDiGetClassDevs(&SWITCHTEC_INTERFACE_GUID,
288 NULL, NULL, DIGCF_DEVICEINTERFACE |
290 if (devinfo == INVALID_HANDLE_VALUE)
293 deviface.cbSize =
sizeof(SP_DEVICE_INTERFACE_DATA);
295 while (SetupDiEnumDeviceInterfaces(devinfo, NULL,
296 &SWITCHTEC_INTERFACE_GUID,
299 snprintf(dl[cnt].
name,
sizeof(dl[cnt].
name),
300 "switchtec%ld", idx++);
302 status = get_path(devinfo, &deviface, &devdata,
303 dl[cnt].
path,
sizeof(dl[cnt].
path));
307 get_pci_address_str(devinfo, &devdata, dl[cnt].
pci_dev,
309 get_description(devinfo, &devdata, dl[cnt].desc,
310 sizeof(dl[cnt].desc));
312 get_property(devinfo, &devdata, &SWITCHTEC_PROP_PRODUCT_ID,
314 get_property(devinfo, &devdata, &SWITCHTEC_PROP_PRODUCT_REV,
316 get_fw_property(devinfo, &devdata, dl[cnt].
fw_version,
321 SetupDiDestroyDeviceInfoList(devinfo);
326static int windows_cmd(
struct switchtec_dev *dev, uint32_t cmd,
327 const void *payload,
size_t payload_len,
void *resp,
330 struct switchtec_windows *wdev = to_switchtec_windows(dev);
334 struct switchtec_mrpc_cmd *mcmd;
335 struct switchtec_mrpc_result *mres;
336 size_t mcmd_len, mres_len;
338 mcmd_len = offsetof(
struct switchtec_mrpc_cmd, data) + payload_len;
339 mres_len = offsetof(
struct switchtec_mrpc_result, data) + resp_len;
341 mcmd = calloc(1, mcmd_len);
345 mres = calloc(1, mres_len);
352 memcpy(mcmd->data, payload, payload_len);
354 status = DeviceIoControl(wdev->hdl, IOCTL_SWITCHTEC_MRPC,
355 mcmd, (DWORD)mcmd_len,
356 mres, (DWORD)mres_len,
364 memcpy(resp, mres->data, resp_len);
376static int windows_event_wait(
struct switchtec_dev *dev,
int timeout_ms)
378 struct switchtec_windows *wdev = to_switchtec_windows(dev);
379 OVERLAPPED overlap = {
380 .hEvent = CreateEvent(NULL, TRUE, FALSE, NULL),
391 DeviceIoControl(wdev->hdl, IOCTL_SWITCHTEC_WAIT_FOR_EVENT, NULL, 0,
392 NULL, 0, NULL, &overlap);
393 if (GetLastError() != ERROR_IO_PENDING)
396 ret = WaitForSingleObject(overlap.hEvent, timeout_ms);
397 if (ret == WAIT_TIMEOUT) {
398 CancelIoEx(wdev->hdl, &overlap);
404 error = GetOverlappedResult(wdev->hdl, &overlap, &transferred, FALSE);
411static gasptr_t windows_gas_map(
struct switchtec_dev *dev,
int writeable,
417 *map_size = dev->gas_map_size;
419 ret = gasop_access_check(dev);
422 return SWITCHTEC_MAP_FAILED;
427static const struct switchtec_ops windows_ops = {
428 .close = windows_close,
430 .gas_map = windows_gas_map,
431 .event_wait = windows_event_wait,
433 .get_device_id = gasop_get_device_id,
434 .get_fw_version = gasop_get_fw_version,
435 .pff_to_port = gasop_pff_to_port,
436 .port_to_pff = gasop_port_to_pff,
437 .flash_part = gasop_flash_part,
438 .event_summary = gasop_event_summary,
439 .event_ctl = gasop_event_ctl,
441 .gas_read8 = mmap_gas_read8,
442 .gas_read16 = mmap_gas_read16,
443 .gas_read32 = mmap_gas_read32,
444 .gas_read64 = mmap_gas_read64,
445 .gas_write8 = mmap_gas_write8,
446 .gas_write16 = mmap_gas_write16,
447 .gas_write32 = mmap_gas_write32,
448 .gas_write32_no_retry = mmap_gas_write32,
449 .gas_write64 = mmap_gas_write64,
450 .memcpy_to_gas = mmap_memcpy_to_gas,
451 .memcpy_from_gas = mmap_memcpy_from_gas,
452 .write_from_gas = mmap_write_from_gas,
457 struct switchtec_windows *wdev;
458 char path_with_guid[MAX_PATH];
461 if (sscanf(path,
"/dev/switchtec%d", &idx) == 1)
464 wdev = malloc(
sizeof(*wdev));
468 append_guid(path, path_with_guid,
sizeof(path_with_guid),
469 &SWITCHTEC_INTERFACE_GUID);
471 wdev->hdl = CreateFile(path_with_guid, GENERIC_READ | GENERIC_WRITE,
472 FILE_SHARE_READ | FILE_SHARE_WRITE,
473 NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
475 if (wdev->hdl == INVALID_HANDLE_VALUE)
481 wdev->dev.ops = &windows_ops;
483 gasop_set_partition_info(&wdev->dev);
488 CloseHandle(wdev->hdl);
497 SP_DEVICE_INTERFACE_DATA deviface;
498 SP_DEVINFO_DATA devdata;
500 struct switchtec_dev *dev = NULL;
503 devinfo = SetupDiGetClassDevs(&SWITCHTEC_INTERFACE_GUID,
504 NULL, NULL, DIGCF_DEVICEINTERFACE |
506 if (devinfo == INVALID_HANDLE_VALUE)
509 deviface.cbSize =
sizeof(SP_DEVICE_INTERFACE_DATA);
511 status = SetupDiEnumDeviceInterfaces(devinfo, NULL,
512 &SWITCHTEC_INTERFACE_GUID,
519 status = get_path(devinfo, &deviface, &devdata,
527 SetupDiDestroyDeviceInfoList(devinfo);
532 int device,
int func)
535 SP_DEVICE_INTERFACE_DATA deviface;
536 SP_DEVINFO_DATA devdata;
538 struct switchtec_dev *dev = NULL;
540 int dbus, ddevice, dfunc;
543 devinfo = SetupDiGetClassDevs(&SWITCHTEC_INTERFACE_GUID,
544 NULL, NULL, DIGCF_DEVICEINTERFACE |
546 if (devinfo == INVALID_HANDLE_VALUE)
549 deviface.cbSize =
sizeof(SP_DEVICE_INTERFACE_DATA);
551 while (SetupDiEnumDeviceInterfaces(devinfo, NULL,
552 &SWITCHTEC_INTERFACE_GUID,
555 status = get_path(devinfo, &deviface, &devdata,
560 get_pci_address(devinfo, &devdata, &dbus, &ddevice, &dfunc);
561 if (dbus == bus && ddevice == device && dfunc == func) {
570 SetupDiDestroyDeviceInfoList(devinfo);
580struct switchtec_dev *switchtec_open_i2c_by_adapter(
int adapter,
int i2c_addr)
struct switchtec_dev * switchtec_open_uart(int fd)
Open a switchtec device behind a uart device.
int switchtec_list(struct switchtec_device_info **devlist)
List all the switchtec devices in the system.
struct switchtec_dev * switchtec_open_by_index(int index)
Open a switchtec device by index.
struct switchtec_dev * switchtec_open_i2c(const char *path, int i2c_addr)
Open a switchtec device behind an I2C device.
struct switchtec_dev * switchtec_open_by_path(const char *path)
Open a switchtec device by path.
struct switchtec_dev * switchtec_open_eth(const char *ip, const int inst)
Open a switchtec device over ethernet.
struct switchtec_dev * switchtec_open_by_pci_addr(int domain, int bus, int device, int func)
Open a switchtec device by PCI address (BDF)
gasptr_t switchtec_gas_map(struct switchtec_dev *dev, int writeable, size_t *map_size)
Map the GAS and return a pointer to access the gas.
Gas Operations for platforms that the gas is mapped into the address space.
Represents a Switchtec device in the switchtec_list() function.
char fw_version[32]
Firmware version.
char pci_dev[256]
PCI BDF string.
char path[PATH_MAX]
Path to the device.
char name[256]
Device name, eg. switchtec0.
char product_id[32]
Product ID.
char product_rev[8]
Product revision.
__gas struct switchtec_gas * gasptr_t
Shortform for a pointer to the GAS register space.