1303233Sdim/*-
2303233Sdim * Copyright (c) 2014, 2015 Marcel Moolenaar
3303233Sdim * All rights reserved.
4353358Sdim *
5353358Sdim * Redistribution and use in source and binary forms, with or without
6353358Sdim * modification, are permitted provided that the following conditions
7303233Sdim * are met:
8303233Sdim *
9303233Sdim * 1. Redistributions of source code must retain the above copyright
10303233Sdim *    notice, this list of conditions and the following disclaimer.
11303233Sdim * 2. Redistributions in binary form must reproduce the above copyright
12303233Sdim *    notice, this list of conditions and the following disclaimer in the
13303233Sdim *    documentation and/or other materials provided with the distribution.
14303233Sdim *
15303233Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16303233Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17303233Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18341825Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19341825Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20303233Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21303233Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22341825Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23341825Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24303233Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25341825Sdim */
26341825Sdim
27341825Sdim#include <sys/cdefs.h>
28303233Sdim__FBSDID("$FreeBSD$");
29303233Sdim
30341825Sdim#include <Python.h>
31341825Sdim
32341825Sdim#include "bus.h"
33303233Sdim#include "busdma.h"
34341825Sdim
35341825Sdimstatic PyObject *
36341825Sdimbus_read_1(PyObject *self, PyObject *args)
37303233Sdim{
38303233Sdim	long ofs;
39341825Sdim	int rid;
40341825Sdim	uint8_t val;
41341825Sdim
42303233Sdim	if (!PyArg_ParseTuple(args, "il", &rid, &ofs))
43341825Sdim		return (NULL);
44341825Sdim	if (!bs_read(rid, ofs, &val, sizeof(val))) {
45341825Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
46303233Sdim		return (NULL);
47303233Sdim	}
48341825Sdim	return (Py_BuildValue("B", val));
49341825Sdim}
50341825Sdim
51303233Sdimstatic PyObject *
52341825Sdimbus_read_2(PyObject *self, PyObject *args)
53341825Sdim{
54341825Sdim	long ofs;
55303233Sdim	int rid;
56303233Sdim	uint16_t val;
57341825Sdim
58341825Sdim	if (!PyArg_ParseTuple(args, "il", &rid, &ofs))
59303233Sdim		return (NULL);
60341825Sdim	if (!bs_read(rid, ofs, &val, sizeof(val))) {
61341825Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
62303233Sdim		return (NULL);
63303233Sdim	}
64341825Sdim	return (Py_BuildValue("H", val));
65341825Sdim}
66341825Sdim
67303233Sdimstatic PyObject *
68341825Sdimbus_read_4(PyObject *self, PyObject *args)
69341825Sdim{
70341825Sdim	long ofs;
71303233Sdim	int rid;
72303233Sdim	uint32_t val;
73341825Sdim
74341825Sdim	if (!PyArg_ParseTuple(args, "il", &rid, &ofs))
75341825Sdim		return (NULL);
76303233Sdim	if (!bs_read(rid, ofs, &val, sizeof(val))) {
77341825Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
78341825Sdim		return (NULL);
79341825Sdim	}
80303233Sdim	return (Py_BuildValue("I", val));
81303233Sdim}
82341825Sdim
83341825Sdimstatic PyObject *
84341825Sdimbus_write_1(PyObject *self, PyObject *args)
85303233Sdim{
86341825Sdim	long ofs;
87341825Sdim	int rid;
88341825Sdim	uint8_t val;
89303233Sdim
90303233Sdim	if (!PyArg_ParseTuple(args, "ilB", &rid, &ofs, &val))
91341825Sdim		return (NULL);
92303233Sdim	if (!bs_write(rid, ofs, &val, sizeof(val))) {
93303233Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
94341825Sdim		return (NULL);
95303233Sdim	}
96303233Sdim	Py_RETURN_NONE;
97341825Sdim}
98303233Sdim
99303233Sdimstatic PyObject *
100341825Sdimbus_write_2(PyObject *self, PyObject *args)
101341825Sdim{
102341825Sdim	long ofs;
103303233Sdim	int rid;
104303233Sdim	uint16_t val;
105341825Sdim
106303233Sdim	if (!PyArg_ParseTuple(args, "ilH", &rid, &ofs, &val))
107303233Sdim		return (NULL);
108303233Sdim	if (!bs_write(rid, ofs, &val, sizeof(val))) {
109341825Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
110341825Sdim		return (NULL);
111341825Sdim	}
112303233Sdim	Py_RETURN_NONE;
113303233Sdim}
114341825Sdim
115303233Sdimstatic PyObject *
116303233Sdimbus_write_4(PyObject *self, PyObject *args)
117341825Sdim{
118303233Sdim	long ofs;
119303233Sdim	int rid;
120341825Sdim	uint32_t val;
121303233Sdim
122303233Sdim	if (!PyArg_ParseTuple(args, "ilI", &rid, &ofs, &val))
123303233Sdim		return (NULL);
124341825Sdim	if (!bs_write(rid, ofs, &val, sizeof(val))) {
125341825Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
126341825Sdim		return (NULL);
127303233Sdim	}
128303233Sdim	Py_RETURN_NONE;
129341825Sdim}
130303233Sdim
131303233Sdimstatic PyObject *
132303233Sdimbus_map(PyObject *self, PyObject *args)
133341825Sdim{
134341825Sdim	char *dev, *resource;
135341825Sdim	int rid;
136303233Sdim
137303233Sdim	if (!PyArg_ParseTuple(args, "ss", &dev, &resource))
138341825Sdim		return (NULL);
139344779Sdim	rid = bs_map(dev, resource);
140303233Sdim	if (rid == -1) {
141344779Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
142303233Sdim		return (NULL);
143303233Sdim	}
144341825Sdim	return (Py_BuildValue("i", rid));
145344779Sdim}
146344779Sdim
147303233Sdimstatic PyObject *
148344779Sdimbus_unmap(PyObject *self, PyObject *args)
149344779Sdim{
150344779Sdim	int rid;
151303233Sdim
152303233Sdim	if (!PyArg_ParseTuple(args, "i", &rid))
153341825Sdim		return (NULL);
154344779Sdim	if (!bs_unmap(rid)) {
155303233Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
156344779Sdim		return (NULL);
157344779Sdim	}
158344779Sdim	Py_RETURN_NONE;
159303233Sdim}
160303233Sdim
161341825Sdimstatic PyObject *
162344779Sdimbus_subregion(PyObject *self, PyObject *args)
163303233Sdim{
164344779Sdim	long ofs, sz;
165303233Sdim	int rid0, rid;
166303233Sdim
167341825Sdim	if (!PyArg_ParseTuple(args, "ill", &rid0, &ofs, &sz))
168344779Sdim		return (NULL);
169344779Sdim	rid = bs_subregion(rid0, ofs, sz);
170303233Sdim	if (rid == -1) {
171344779Sdim		PyErr_SetString(PyExc_IOError, strerror(errno));
172344779Sdim		return (NULL);
173344779Sdim	}
174303233Sdim	return (Py_BuildValue("i", rid));
175303233Sdim}
176341825Sdim
177344779Sdimstatic PyObject *
178303233Sdimbusdma_tag_create(PyObject *self, PyObject *args)
179344779Sdim{
180344779Sdim	char *dev;
181344779Sdim	u_long align, bndry, maxaddr, maxsz, maxsegsz;
182303233Sdim	u_int nsegs, datarate, flags;
183303233Sdim	int tid;
184303233Sdim
185341825Sdim	if (!PyArg_ParseTuple(args, "skkkkIkII", &dev, &align, &bndry,
186341825Sdim	    &maxaddr, &maxsz, &nsegs, &maxsegsz, &datarate, &flags))
187303233Sdim		return (NULL);
188303233Sdim	tid = bd_tag_create(dev, align, bndry, maxaddr, maxsz, nsegs,
189	    maxsegsz, datarate, flags);
190	if (tid == -1) {
191		PyErr_SetString(PyExc_IOError, strerror(errno));
192		return (NULL);
193	}
194	return (Py_BuildValue("i", tid));
195}
196
197static PyObject *
198busdma_tag_derive(PyObject *self, PyObject *args)
199{
200	u_long align, bndry, maxaddr, maxsz, maxsegsz;
201	u_int nsegs, datarate, flags;
202	int ptid, tid;
203
204	if (!PyArg_ParseTuple(args, "ikkkkIkII", &ptid, &align, &bndry,
205	    &maxaddr, &maxsz, &nsegs, &maxsegsz, &datarate, &flags))
206		return (NULL);
207	tid = bd_tag_derive(ptid, align, bndry, maxaddr, maxsz, nsegs,
208	    maxsegsz, datarate, flags);
209	if (tid == -1) {
210		PyErr_SetString(PyExc_IOError, strerror(errno));
211		return (NULL);
212	}
213	return (Py_BuildValue("i", tid));
214}
215
216static PyObject *
217busdma_tag_destroy(PyObject *self, PyObject *args)
218{
219	int error, tid;
220
221	if (!PyArg_ParseTuple(args, "i", &tid))
222		return (NULL);
223	error = bd_tag_destroy(tid);
224	if (error) {
225		PyErr_SetString(PyExc_IOError, strerror(error));
226		return (NULL);
227	}
228	Py_RETURN_NONE;
229}
230
231static PyObject *
232busdma_md_create(PyObject *self, PyObject *args)
233{
234	u_int flags;
235	int error, mdid, tid;
236
237	if (!PyArg_ParseTuple(args, "iI", &tid, &flags))
238		return (NULL);
239	mdid = bd_md_create(tid, flags);
240	if (mdid == -1) {
241		PyErr_SetString(PyExc_IOError, strerror(errno));
242		return (NULL);
243	}
244	return (Py_BuildValue("i", mdid));
245}
246
247static PyObject *
248busdma_md_destroy(PyObject *self, PyObject *args)
249{
250	int error, mdid;
251
252	if (!PyArg_ParseTuple(args, "i", &mdid))
253		return (NULL);
254	error = bd_md_destroy(mdid);
255	if (error) {
256		PyErr_SetString(PyExc_IOError, strerror(error));
257		return (NULL);
258	}
259	Py_RETURN_NONE;
260}
261
262static PyObject *
263busdma_md_load(PyObject *self, PyObject *args)
264{
265	void *buf;
266	u_long len;
267	u_int flags;
268	int error, mdid;
269
270	if (!PyArg_ParseTuple(args, "iwkI", &mdid, &buf, &len, &flags))
271		return (NULL);
272	error = bd_md_load(mdid, buf, len, flags);
273	if (error) {
274		PyErr_SetString(PyExc_IOError, strerror(error));
275		return (NULL);
276	}
277	Py_RETURN_NONE;
278}
279
280static PyObject *
281busdma_md_unload(PyObject *self, PyObject *args)
282{
283	int error, mdid;
284
285	if (!PyArg_ParseTuple(args, "i", &mdid))
286		return (NULL);
287	error = bd_md_unload(mdid);
288	if (error) {
289		PyErr_SetString(PyExc_IOError, strerror(error));
290		return (NULL);
291	}
292	Py_RETURN_NONE;
293}
294
295static PyObject *
296busdma_mem_alloc(PyObject *self, PyObject *args)
297{
298	u_int flags;
299	int mdid, tid;
300
301	if (!PyArg_ParseTuple(args, "iI", &tid, &flags))
302		return (NULL);
303	mdid = bd_mem_alloc(tid, flags);
304	if (mdid == -1) {
305		PyErr_SetString(PyExc_IOError, strerror(errno));
306		return (NULL);
307	}
308	return (Py_BuildValue("i", mdid));
309}
310
311static PyObject *
312busdma_mem_free(PyObject *self, PyObject *args)
313{
314	int error, mdid;
315
316	if (!PyArg_ParseTuple(args, "i", &mdid))
317		return (NULL);
318	error = bd_mem_free(mdid);
319	if (error) {
320		PyErr_SetString(PyExc_IOError, strerror(error));
321		return (NULL);
322	}
323	Py_RETURN_NONE;
324}
325
326static PyObject *
327busdma_md_first_seg(PyObject *self, PyObject *args)
328{
329	int error, mdid, sid, what;
330
331	if (!PyArg_ParseTuple(args, "ii", &mdid, &what))
332		return (NULL);
333	sid = bd_md_first_seg(mdid, what);
334	if (sid == -1)
335		Py_RETURN_NONE;
336	return (Py_BuildValue("i", sid));
337}
338
339static PyObject *
340busdma_md_next_seg(PyObject *self, PyObject *args)
341{
342	int error, mdid, sid;
343
344	if (!PyArg_ParseTuple(args, "ii", &mdid, &sid))
345		return (NULL);
346	sid = bd_md_next_seg(mdid, sid);
347	if (sid == -1)
348		Py_RETURN_NONE;
349	return (Py_BuildValue("i", sid));
350}
351
352static PyObject *
353busdma_seg_get_addr(PyObject *self, PyObject *args)
354{
355	u_long addr;
356	int error, sid;
357
358	if (!PyArg_ParseTuple(args, "i", &sid))
359		return (NULL);
360	error = bd_seg_get_addr(sid, &addr);
361	if (error) {
362		PyErr_SetString(PyExc_IOError, strerror(error));
363		return (NULL);
364	}
365	return (Py_BuildValue("k", addr));
366}
367
368static PyObject *
369busdma_seg_get_size(PyObject *self, PyObject *args)
370{
371	u_long size;
372	int error, sid;
373
374	if (!PyArg_ParseTuple(args, "i", &sid))
375		return (NULL);
376	error = bd_seg_get_size(sid, &size);
377	if (error) {
378		PyErr_SetString(PyExc_IOError, strerror(error));
379		return (NULL);
380	}
381	return (Py_BuildValue("k", size));
382}
383
384static PyObject *
385busdma_sync(PyObject *self, PyObject *args)
386{
387	int error, mdid, op;
388
389	if (!PyArg_ParseTuple(args, "ii", &mdid, &op))
390		return (NULL);
391	error = bd_sync(mdid, op, 0UL, ~0UL);
392	if (error) {
393		PyErr_SetString(PyExc_IOError, strerror(error));
394		return (NULL);
395	}
396	Py_RETURN_NONE;
397}
398
399static PyObject *
400busdma_sync_range(PyObject *self, PyObject *args)
401{
402	u_long ofs, len;
403	int error, mdid, op;
404
405	if (!PyArg_ParseTuple(args, "iikk", &mdid, &op, &ofs, &len))
406		return (NULL);
407	error = bd_sync(mdid, op, ofs, len);
408	if (error) {
409		PyErr_SetString(PyExc_IOError, strerror(error));
410		return (NULL);
411	}
412	Py_RETURN_NONE;
413}
414
415static PyMethodDef bus_methods[] = {
416    { "read_1", bus_read_1, METH_VARARGS, "Read a 1-byte data item." },
417    { "read_2", bus_read_2, METH_VARARGS, "Read a 2-byte data item." },
418    { "read_4", bus_read_4, METH_VARARGS, "Read a 4-byte data item." },
419
420    { "write_1", bus_write_1, METH_VARARGS, "Write a 1-byte data item." },
421    { "write_2", bus_write_2, METH_VARARGS, "Write a 2-byte data item." },
422    { "write_4", bus_write_4, METH_VARARGS, "Write a 4-byte data item." },
423
424    { "map", bus_map, METH_VARARGS,
425	"Return a resource ID for a device file created by proto(4)" },
426    { "unmap", bus_unmap, METH_VARARGS,
427	"Free a resource ID" },
428    { "subregion", bus_subregion, METH_VARARGS,
429	"Return a resource ID for a subregion of another resource ID" },
430
431    { NULL, NULL, 0, NULL }
432};
433
434static PyMethodDef busdma_methods[] = {
435    { "tag_create", busdma_tag_create, METH_VARARGS,
436	"Create a root tag." },
437    { "tag_derive", busdma_tag_derive, METH_VARARGS,
438	"Derive a child tag." },
439    { "tag_destroy", busdma_tag_destroy, METH_VARARGS,
440	"Destroy a tag." },
441
442    { "md_create", busdma_md_create, METH_VARARGS,
443	"Create a new and empty memory descriptor." },
444    { "md_destroy", busdma_md_destroy, METH_VARARGS,
445	"Destroy a previously created memory descriptor." },
446    { "md_load", busdma_md_load, METH_VARARGS,
447	"Load a buffer into a memory descriptor." },
448    { "md_unload", busdma_md_unload, METH_VARARGS,
449	"Unload a memory descriptor." },
450
451    { "mem_alloc", busdma_mem_alloc, METH_VARARGS,
452	"Allocate memory according to the DMA constraints." },
453    { "mem_free", busdma_mem_free, METH_VARARGS,
454	"Free allocated memory." },
455
456    { "md_first_seg", busdma_md_first_seg, METH_VARARGS,
457	"Return first segment in one of the segment lists." },
458    { "md_next_seg", busdma_md_next_seg, METH_VARARGS,
459	"Return next segment in the segment list." },
460    { "seg_get_addr", busdma_seg_get_addr, METH_VARARGS,
461	"Return the address of the segment." },
462    { "seg_get_size", busdma_seg_get_size, METH_VARARGS,
463	"Return the size of the segment." },
464
465    { "sync", busdma_sync, METH_VARARGS,
466	"Make the entire memory descriptor coherent WRT to DMA." },
467    { "sync_range", busdma_sync_range, METH_VARARGS,
468	"Make part of the memory descriptor coherent WRT to DMA." },
469
470    { NULL, NULL, 0, NULL }
471};
472
473PyMODINIT_FUNC
474initbus(void)
475{
476	PyObject *bus, *busdma;
477
478	bus = Py_InitModule("bus", bus_methods);
479	if (bus == NULL)
480		return;
481	busdma = Py_InitModule("busdma", busdma_methods);
482	if (busdma == NULL)
483		return;
484	PyModule_AddObject(bus, "dma", busdma);
485
486	PyModule_AddObject(busdma, "MD_BUS_SPACE", Py_BuildValue("i", 0));
487	PyModule_AddObject(busdma, "MD_PHYS_SPACE", Py_BuildValue("i", 1));
488	PyModule_AddObject(busdma, "MD_VIRT_SPACE", Py_BuildValue("i", 2));
489
490	PyModule_AddObject(busdma, "SYNC_PREREAD", Py_BuildValue("i", 1));
491	PyModule_AddObject(busdma, "SYNC_POSTREAD", Py_BuildValue("i", 2));
492	PyModule_AddObject(busdma, "SYNC_PREWRITE", Py_BuildValue("i", 4));
493	PyModule_AddObject(busdma, "SYNC_POSTWRITE", Py_BuildValue("i", 8));
494}
495