// SPDX-License-Identifier: LGPL-2.1-or-later /* * This file is part of libgpiod. * * Copyright (C) 2019 Bartosz Golaszewski */ #include #include typedef struct { PyObject_HEAD struct gpio_mockup *mockup; } gpiomockup_MockupObject; enum { gpiomockup_FLAG_NAMED_LINES = 1, }; static int gpiomockup_Mockup_init(gpiomockup_MockupObject *self, PyObject *Py_UNUSED(ignored0), PyObject *Py_UNUSED(ignored1)) { Py_BEGIN_ALLOW_THREADS; self->mockup = gpio_mockup_new(); Py_END_ALLOW_THREADS; if (!self->mockup) { PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; } static void gpiomockup_Mockup_dealloc(gpiomockup_MockupObject *self) { if (self->mockup) { Py_BEGIN_ALLOW_THREADS; gpio_mockup_unref(self->mockup); Py_END_ALLOW_THREADS; } PyObject_Del(self); } static PyObject *gpiomockup_Mockup_probe(gpiomockup_MockupObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "chip_sizes", "flags", NULL }; PyObject *chip_sizes_obj, *iter, *next; unsigned int *chip_sizes; int ret, flags = 0, i; Py_ssize_t num_chips; ret = PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &chip_sizes_obj, &flags); if (!ret) return NULL; num_chips = PyObject_Size(chip_sizes_obj); if (num_chips < 0) { return NULL; } else if (num_chips == 0) { PyErr_SetString(PyExc_TypeError, "Number of chips must be greater thatn 0"); return NULL; } chip_sizes = PyMem_RawCalloc(num_chips, sizeof(unsigned int)); if (!chip_sizes) return NULL; iter = PyObject_GetIter(chip_sizes_obj); if (!iter) { PyMem_RawFree(chip_sizes); return NULL; } for (i = 0;; i++) { next = PyIter_Next(iter); if (!next) { Py_DECREF(iter); break; } chip_sizes[i] = PyLong_AsUnsignedLong(next); Py_DECREF(next); if (PyErr_Occurred()) { Py_DECREF(iter); PyMem_RawFree(chip_sizes); return NULL; } } if (flags & gpiomockup_FLAG_NAMED_LINES) flags |= GPIO_MOCKUP_FLAG_NAMED_LINES; Py_BEGIN_ALLOW_THREADS; ret = gpio_mockup_probe(self->mockup, num_chips, chip_sizes, flags); Py_END_ALLOW_THREADS; PyMem_RawFree(chip_sizes); if (ret) return NULL; Py_RETURN_NONE; } static PyObject *gpiomockup_Mockup_remove(gpiomockup_MockupObject *self, PyObject *Py_UNUSED(ignored)) { int ret; Py_BEGIN_ALLOW_THREADS; ret = gpio_mockup_remove(self->mockup); Py_END_ALLOW_THREADS; if (ret) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; } static PyObject *gpiomockup_Mockup_chip_name(gpiomockup_MockupObject *self, PyObject *args) { unsigned int idx; const char *name; int ret; ret = PyArg_ParseTuple(args, "I", &idx); if (!ret) return NULL; name = gpio_mockup_chip_name(self->mockup, idx); if (!name) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return PyUnicode_FromString(name); } static PyObject *gpiomockup_Mockup_chip_path(gpiomockup_MockupObject *self, PyObject *args) { unsigned int idx; const char *path; int ret; ret = PyArg_ParseTuple(args, "I", &idx); if (!ret) return NULL; path = gpio_mockup_chip_path(self->mockup, idx); if (!path) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return PyUnicode_FromString(path); } static PyObject *gpiomockup_Mockup_chip_num(gpiomockup_MockupObject *self, PyObject *args) { unsigned int idx; int ret, num; ret = PyArg_ParseTuple(args, "I", &idx); if (!ret) return NULL; num = gpio_mockup_chip_num(self->mockup, idx); if (num < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return PyLong_FromLong(num); } static PyObject *gpiomockup_Mockup_chip_get_value(gpiomockup_MockupObject *self, PyObject *args) { unsigned int chip_idx, line_offset; int ret, val; ret = PyArg_ParseTuple(args, "II", &chip_idx, &line_offset); if (!ret) return NULL; Py_BEGIN_ALLOW_THREADS; val = gpio_mockup_get_value(self->mockup, chip_idx, line_offset); Py_END_ALLOW_THREADS; if (val < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return PyLong_FromUnsignedLong(val); } static PyObject *gpiomockup_Mockup_chip_set_pull(gpiomockup_MockupObject *self, PyObject *args) { unsigned int chip_idx, line_offset; int ret, pull; ret = PyArg_ParseTuple(args, "IIi", &chip_idx, &line_offset, &pull); if (!ret) return NULL; Py_BEGIN_ALLOW_THREADS; ret = gpio_mockup_set_pull(self->mockup, chip_idx, line_offset, pull); Py_END_ALLOW_THREADS; if (ret) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; } static PyMethodDef gpiomockup_Mockup_methods[] = { { .ml_name = "probe", .ml_meth = (PyCFunction)(void (*)(void))gpiomockup_Mockup_probe, .ml_flags = METH_VARARGS | METH_KEYWORDS, }, { .ml_name = "remove", .ml_meth = (PyCFunction)gpiomockup_Mockup_remove, .ml_flags = METH_NOARGS, }, { .ml_name = "chip_name", .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_name, .ml_flags = METH_VARARGS, }, { .ml_name = "chip_path", .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_path, .ml_flags = METH_VARARGS, }, { .ml_name = "chip_num", .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_num, .ml_flags = METH_VARARGS, }, { .ml_name = "chip_get_value", .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_get_value, .ml_flags = METH_VARARGS, }, { .ml_name = "chip_set_pull", .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_set_pull, .ml_flags = METH_VARARGS, }, { } }; static PyTypeObject gpiomockup_MockupType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "gpiomockup.Mockup", .tp_basicsize = sizeof(gpiomockup_MockupObject), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = PyType_GenericNew, .tp_init = (initproc)gpiomockup_Mockup_init, .tp_dealloc = (destructor)gpiomockup_Mockup_dealloc, .tp_methods = gpiomockup_Mockup_methods, }; static PyModuleDef gpiomockup_Module = { PyModuleDef_HEAD_INIT, .m_name = "gpiomockup", .m_size = -1, }; PyMODINIT_FUNC PyInit_gpiomockup(void) { PyObject *module, *val; int ret; module = PyModule_Create(&gpiomockup_Module); if (!module) return NULL; ret = PyType_Ready(&gpiomockup_MockupType); if (ret) return NULL; Py_INCREF(&gpiomockup_MockupType); ret = PyModule_AddObject(module, "Mockup", (PyObject *)&gpiomockup_MockupType); if (ret) return NULL; val = PyLong_FromLong(gpiomockup_FLAG_NAMED_LINES); if (!val) return NULL; ret = PyDict_SetItemString(gpiomockup_MockupType.tp_dict, "FLAG_NAMED_LINES", val); if (ret) return NULL; return module; }