2012-05-24 21:31:02 +02:00
|
|
|
/*
|
|
|
|
* \brief Emulation of Linux kernel interfaces
|
|
|
|
* \author Norman Feske
|
|
|
|
* \author Sebastian Sumpf
|
|
|
|
* \date 2012-01-29
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-11 17:35:30 +01:00
|
|
|
* Copyright (C) 2012-2017 Genode Labs GmbH
|
2012-05-24 21:31:02 +02:00
|
|
|
*
|
2017-02-20 13:23:52 +01:00
|
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
|
|
* version 2.
|
2012-05-24 21:31:02 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/allocator_avl.h>
|
|
|
|
#include <dataspace/client.h>
|
2016-04-15 15:19:22 +02:00
|
|
|
#include <region_map/client.h>
|
2012-05-24 21:31:02 +02:00
|
|
|
#include <timer_session/connection.h>
|
|
|
|
#include <util/string.h>
|
|
|
|
|
|
|
|
/* Local includes */
|
|
|
|
#include "signal.h"
|
2014-11-13 15:44:15 +01:00
|
|
|
#include "lx_emul.h"
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
#include <lx_kit/backend_alloc.h>
|
|
|
|
#include <lx_kit/irq.h>
|
|
|
|
#include <lx_kit/scheduler.h>
|
|
|
|
#include <lx_kit/work.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <lx_emul/impl/slab.h>
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2012-08-03 18:32:51 +02:00
|
|
|
namespace Genode {
|
2013-03-04 11:20:42 +01:00
|
|
|
class Slab_backend_alloc;
|
|
|
|
class Slab_alloc;
|
|
|
|
}
|
2012-08-03 18:32:51 +02:00
|
|
|
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
unsigned long jiffies;
|
|
|
|
void backtrace() { }
|
2015-05-12 15:16:19 +02:00
|
|
|
|
|
|
|
|
2016-11-24 14:31:42 +01:00
|
|
|
void pci_dev_put(struct pci_dev *pci_dev)
|
|
|
|
{
|
2017-02-11 17:35:30 +01:00
|
|
|
Genode::destroy(&Lx_kit::env().heap(), pci_dev);
|
2016-11-24 14:31:42 +01:00
|
|
|
}
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
/***********************
|
|
|
|
** Atomic operations **
|
|
|
|
***********************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Actually not atomic, for now
|
|
|
|
*/
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
unsigned int atomic_read(atomic_t *p) { return p->v; }
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
void atomic_inc(atomic_t *v) { v->v++; }
|
|
|
|
void atomic_dec(atomic_t *v) { v->v--; }
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
void atomic_add(int i, atomic_t *v) { v->v += i; }
|
|
|
|
void atomic_sub(int i, atomic_t *v) { v->v -= i; }
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
void atomic_set(atomic_t *p, unsigned int v) { p->v = v; }
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*************************************
|
|
|
|
** Memory allocation, linux/slab.h **
|
|
|
|
*************************************/
|
|
|
|
|
2016-01-06 14:43:21 +01:00
|
|
|
void *dma_malloc(size_t size)
|
|
|
|
{
|
2016-05-18 18:51:11 +02:00
|
|
|
return Lx::Malloc::dma().alloc_large(size);
|
2016-01-06 14:43:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dma_free(void *ptr)
|
|
|
|
{
|
2016-05-18 18:51:11 +02:00
|
|
|
Lx::Malloc::dma().free_large(ptr);
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
** linux/vmalloc.h **
|
|
|
|
*********************/
|
|
|
|
|
2015-07-02 14:20:20 +02:00
|
|
|
void *vzalloc(unsigned long size)
|
2012-05-24 21:31:02 +02:00
|
|
|
{
|
2015-07-02 14:20:20 +02:00
|
|
|
size_t *addr;
|
2016-06-21 12:59:11 +02:00
|
|
|
try { addr = (size_t *)Lx::Malloc::mem().alloc_large(size); }
|
2015-07-02 14:20:20 +02:00
|
|
|
catch (...) { return 0; }
|
|
|
|
|
2016-06-21 12:59:11 +02:00
|
|
|
memset(addr, 0, size);
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2016-06-21 12:59:11 +02:00
|
|
|
return addr;
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
2015-07-02 14:20:20 +02:00
|
|
|
|
|
|
|
void vfree(void *addr)
|
|
|
|
{
|
|
|
|
if (!addr) return;
|
2016-06-21 12:59:11 +02:00
|
|
|
Lx::Malloc::mem().free_large(addr);
|
2015-07-02 14:20:20 +02:00
|
|
|
}
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
** linux/kref.h **
|
|
|
|
******************/
|
|
|
|
|
|
|
|
void kref_init(struct kref *kref)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_KREF,"%s ref: %p", __func__, kref);
|
2012-05-24 21:31:02 +02:00
|
|
|
kref->refcount.v = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void kref_get(struct kref *kref)
|
|
|
|
{
|
|
|
|
kref->refcount.v++;
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_KREF, "%s ref: %p c: %d", __func__, kref, kref->refcount.v);
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int kref_put(struct kref *kref, void (*release) (struct kref *kref))
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_KREF, "%s: ref: %p c: %d", __func__, kref, kref->refcount.v);
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
if (!--kref->refcount.v) {
|
|
|
|
release(kref);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
** linux/uaccess.h **
|
|
|
|
*********************/
|
|
|
|
|
|
|
|
size_t copy_to_user(void *dst, void const *src, size_t len)
|
|
|
|
{
|
|
|
|
if (dst && src && len)
|
2012-08-03 18:32:51 +02:00
|
|
|
memcpy(dst, src, len);
|
2012-05-24 21:31:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t copy_from_user(void *dst, void const *src, size_t len)
|
|
|
|
{
|
|
|
|
if (dst && src && len)
|
2012-08-03 18:32:51 +02:00
|
|
|
memcpy(dst, src, len);
|
2012-05-24 21:31:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool access_ok(int access, void *addr, size_t size) { return 1; }
|
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
** linux/string.h **
|
|
|
|
********************/
|
|
|
|
|
2012-08-03 18:32:51 +02:00
|
|
|
void *_memcpy(void *d, const void *s, size_t n)
|
|
|
|
{
|
|
|
|
return Genode::memcpy(d, s, n);
|
|
|
|
}
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
|
2012-08-03 18:32:51 +02:00
|
|
|
inline void *memset(void *s, int c, size_t n)
|
|
|
|
{
|
|
|
|
return Genode::memset(s, c, n);
|
|
|
|
}
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
|
2013-09-12 21:34:02 +02:00
|
|
|
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
Genode::String_console sc(buf, size);
|
|
|
|
sc.vprintf(fmt, args);
|
|
|
|
|
|
|
|
return sc.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
int snprintf(char *buf, size_t size, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
Genode::String_console sc(buf, size);
|
|
|
|
sc.vprintf(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return sc.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-20 08:42:16 +02:00
|
|
|
int scnprintf(char *buf, size_t size, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
Genode::String_console sc(buf, size);
|
|
|
|
sc.vprintf(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return sc.len();
|
|
|
|
}
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
int strcmp(const char *s1, const char *s2)
|
|
|
|
{
|
|
|
|
printk("%s:%d from %p\n", __func__, __LINE__, __builtin_return_address(0));
|
|
|
|
return Genode::strcmp(s1, s2);
|
|
|
|
}
|
2012-05-24 21:31:02 +02:00
|
|
|
size_t strlen(const char *s) { return Genode::strlen(s); }
|
|
|
|
|
|
|
|
|
2018-08-20 14:03:25 +02:00
|
|
|
size_t strlcat(char *dest, const char *src, size_t count)
|
|
|
|
{
|
|
|
|
size_t dsize = strlen(dest);
|
|
|
|
size_t len = strlen(src);
|
|
|
|
size_t res = dsize + len;
|
|
|
|
|
|
|
|
/* This would be a bug */
|
|
|
|
BUG_ON(dsize >= count);
|
|
|
|
|
|
|
|
dest += dsize;
|
|
|
|
count -= dsize;
|
|
|
|
if (len >= count)
|
|
|
|
len = count-1;
|
|
|
|
memcpy(dest, src, len);
|
|
|
|
dest[len] = 0;
|
|
|
|
return res;
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 16:04:47 +01:00
|
|
|
size_t strlcpy(char *dest, const char *src, size_t size)
|
|
|
|
{
|
|
|
|
size_t ret = strlen(src);
|
|
|
|
|
|
|
|
if (size) {
|
|
|
|
size_t len = (ret >= size) ? size - 1 : ret;
|
|
|
|
Genode::memcpy(dest, src, len);
|
|
|
|
dest[len] = '\0';
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
void *memscan(void *addr, int c, size_t size)
|
|
|
|
{
|
|
|
|
unsigned char* p = (unsigned char *)addr;
|
|
|
|
|
|
|
|
for (size_t s = 0; s < size; s++, p++)
|
|
|
|
if (*p == c)
|
|
|
|
break;
|
|
|
|
|
|
|
|
return (void *)p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-30 22:29:19 +02:00
|
|
|
/*****************
|
|
|
|
** linux/gfp.h **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
unsigned long get_zeroed_page(gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
return (unsigned long)kzalloc(PAGE_SIZE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
/******************
|
|
|
|
** linux/log2.h **
|
|
|
|
******************/
|
|
|
|
|
|
|
|
int ilog2(u32 n) { return Genode::log2(n); }
|
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
** linux/slab.h **
|
|
|
|
********************/
|
|
|
|
|
|
|
|
|
|
|
|
void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags)
|
|
|
|
{
|
|
|
|
void *ret;
|
2016-05-18 18:51:11 +02:00
|
|
|
ret = kmem_cache_alloc(cache, flags);
|
|
|
|
memset(ret, 0, cache->size());
|
2016-06-21 12:59:11 +02:00
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************
|
|
|
|
** asm-generic/io.h **
|
|
|
|
**********************/
|
|
|
|
|
2013-09-12 21:34:02 +02:00
|
|
|
void *phys_to_virt(unsigned long address)
|
|
|
|
{
|
2016-05-18 18:51:11 +02:00
|
|
|
return (void *)Lx::Malloc::dma().virt_addr(address);
|
2013-09-12 21:34:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
/********************
|
|
|
|
** linux/device.h **
|
|
|
|
********************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Simple driver management class
|
|
|
|
*/
|
|
|
|
class Driver : public Genode::List<Driver>::Element
|
|
|
|
{
|
2013-05-16 12:17:03 +02:00
|
|
|
private:
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
struct device_driver *_drv; /* Linux driver */
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Driver(struct device_driver *drv) : _drv(drv)
|
|
|
|
{
|
|
|
|
list()->insert(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List of all currently registered drivers
|
|
|
|
*/
|
|
|
|
static Genode::List<Driver> *list()
|
|
|
|
{
|
|
|
|
static Genode::List<Driver> _list;
|
|
|
|
return &_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Match device and drivers
|
|
|
|
*/
|
|
|
|
bool match(struct device *dev)
|
|
|
|
{
|
2012-06-25 16:31:04 +02:00
|
|
|
/*
|
|
|
|
* Don't try if buses don't match, since drivers often use 'container_of'
|
|
|
|
* which might cast the device to non-matching type
|
|
|
|
*/
|
|
|
|
if (_drv->bus != dev->bus)
|
|
|
|
return false;
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true;
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p %p",
|
2014-11-13 15:44:15 +01:00
|
|
|
_drv->name, ret, _drv->bus->match, _drv->probe);
|
2012-05-24 21:31:02 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Probe device with driver
|
|
|
|
*/
|
|
|
|
int probe(struct device *dev)
|
|
|
|
{
|
|
|
|
dev->driver = _drv;
|
|
|
|
|
2018-03-23 14:15:25 +01:00
|
|
|
if (dev->bus->probe)
|
2012-05-24 21:31:02 +02:00
|
|
|
return dev->bus->probe(dev);
|
2018-03-23 14:15:25 +01:00
|
|
|
else if (_drv->probe)
|
2012-05-24 21:31:02 +02:00
|
|
|
return _drv->probe(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int driver_register(struct device_driver *drv)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DRIVER, "%s at %p", drv->name, drv);
|
2016-06-21 12:59:11 +02:00
|
|
|
new (Lx::Malloc::mem()) Driver(drv);
|
2012-05-24 21:31:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int device_add(struct device *dev)
|
|
|
|
{
|
|
|
|
if (dev->driver)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* foreach driver match and probe device */
|
|
|
|
for (Driver *driver = Driver::list()->first(); driver; driver = driver->next())
|
|
|
|
if (driver->match(dev)) {
|
|
|
|
int ret = driver->probe(dev);
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DRIVER, "Probe return %d", ret);
|
2013-04-17 17:58:46 +02:00
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
if (!ret)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-13 15:44:15 +01:00
|
|
|
void device_del(struct device *dev)
|
|
|
|
{
|
|
|
|
if (dev->driver && dev->driver->remove)
|
|
|
|
dev->driver->remove(dev);
|
2018-03-23 14:15:25 +01:00
|
|
|
|
|
|
|
if (dev->bus && dev->bus->remove)
|
|
|
|
dev->bus->remove(dev);
|
2014-11-13 15:44:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
int device_register(struct device *dev)
|
|
|
|
{
|
|
|
|
return device_add(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-23 14:15:25 +01:00
|
|
|
void device_unregister(struct device *dev)
|
|
|
|
{
|
|
|
|
device_del(dev);
|
|
|
|
put_device(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int device_is_registered(struct device *dev)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void device_release_driver(struct device *dev)
|
|
|
|
{
|
|
|
|
/* is usb_unbind_interface(dev); */
|
|
|
|
if (dev->driver->remove)
|
|
|
|
dev->driver->remove(dev);
|
|
|
|
|
|
|
|
dev->driver = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void put_device(struct device *dev)
|
|
|
|
{
|
|
|
|
if (dev->ref) {
|
|
|
|
dev->ref--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->release)
|
|
|
|
dev->release(dev);
|
|
|
|
else if (dev->type && dev->type->release)
|
|
|
|
dev->type->release(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct device *get_device(struct device *dev)
|
|
|
|
{
|
|
|
|
dev->ref++;
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
void *dev_get_drvdata(const struct device *dev)
|
|
|
|
{
|
|
|
|
return dev->driver_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int dev_set_drvdata(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
dev->driver_data = data; return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-20 08:42:16 +02:00
|
|
|
const char *dev_name(const struct device *dev) { return dev->name; }
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2018-03-23 14:15:25 +01:00
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
/*******************************
|
|
|
|
** asm-generic/bitops/find.h **
|
|
|
|
*******************************/
|
|
|
|
|
|
|
|
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
|
|
|
|
unsigned long offset)
|
|
|
|
{
|
|
|
|
unsigned long i = offset / BITS_PER_LONG;
|
|
|
|
offset -= (i * BITS_PER_LONG);
|
|
|
|
|
|
|
|
for (; offset < size; offset++)
|
|
|
|
if (addr[i] & (1UL << offset))
|
2016-06-16 16:13:25 +02:00
|
|
|
return offset + (i * BITS_PER_LONG);
|
2016-05-18 18:51:11 +02:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2016-06-16 16:13:25 +02:00
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
long find_next_zero_bit_le(const void *addr,
|
|
|
|
unsigned long size, unsigned long offset)
|
|
|
|
{
|
2016-06-16 16:13:25 +02:00
|
|
|
static unsigned cnt = 0;
|
2012-05-24 21:31:02 +02:00
|
|
|
unsigned long max_size = sizeof(long) * 8;
|
|
|
|
if (offset >= max_size) {
|
2016-06-21 12:59:11 +02:00
|
|
|
Genode::warning("Offset greater max size");
|
2012-05-24 21:31:02 +02:00
|
|
|
return offset + size;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; offset < max_size; offset++)
|
2014-11-17 16:18:29 +01:00
|
|
|
if (!(*(unsigned long*)addr & (1L << offset)))
|
2012-05-24 21:31:02 +02:00
|
|
|
return offset;
|
|
|
|
|
|
|
|
return offset + size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-17 17:58:46 +02:00
|
|
|
void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
|
|
|
|
{
|
|
|
|
return kzalloc(size, gfp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-02 13:50:17 +02:00
|
|
|
void *dev_get_platdata(const struct device *dev)
|
2013-09-12 21:34:02 +02:00
|
|
|
{
|
2014-06-02 13:50:17 +02:00
|
|
|
return (void *)dev->platform_data;
|
2013-09-12 21:34:02 +02:00
|
|
|
}
|
|
|
|
|
2013-04-17 17:58:46 +02:00
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
/*******************************
|
|
|
|
** linux/byteorder/generic.h **
|
|
|
|
*******************************/
|
|
|
|
|
2013-03-25 17:56:00 +01:00
|
|
|
u16 get_unaligned_le16(const void *p)
|
|
|
|
{
|
|
|
|
const struct __una_u16 *ptr = (const struct __una_u16 *)p;
|
|
|
|
return ptr->x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-16 12:17:03 +02:00
|
|
|
void put_unaligned_le16(u16 val, void *p)
|
|
|
|
{
|
|
|
|
struct __una_u16 *ptr = (struct __una_u16 *)p;
|
|
|
|
ptr->x = val;
|
|
|
|
}
|
|
|
|
|
2013-03-25 17:56:00 +01:00
|
|
|
u32 get_unaligned_le32(const void *p)
|
|
|
|
{
|
|
|
|
const struct __una_u32 *ptr = (const struct __una_u32 *)p;
|
|
|
|
return ptr->x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
void put_unaligned_le32(u32 val, void *p)
|
|
|
|
{
|
|
|
|
struct __una_u32 *ptr = (struct __una_u32 *)p;
|
|
|
|
ptr->x = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u64 get_unaligned_le64(const void *p)
|
|
|
|
{
|
2013-03-25 17:56:00 +01:00
|
|
|
const struct __una_u64 *ptr = (const struct __una_u64 *)p;
|
2012-05-24 21:31:02 +02:00
|
|
|
return ptr->x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void put_unaligned_le64(u64 val, void *p)
|
|
|
|
{
|
|
|
|
struct __una_u64 *ptr = (struct __una_u64 *)p;
|
|
|
|
ptr->x = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************
|
|
|
|
** linux/bitops.h, asm/bitops.h **
|
|
|
|
**********************************/
|
|
|
|
|
|
|
|
int fls(int x)
|
|
|
|
{
|
|
|
|
if (!x)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (int i = 31; i >= 0; i--)
|
|
|
|
if (x & (1 << i))
|
2014-02-14 13:36:21 +01:00
|
|
|
return i + 1;
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************
|
|
|
|
** linux/delay.h **
|
|
|
|
*******************/
|
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
#include <lx_emul/impl/delay.h>
|
2012-05-24 21:31:02 +02:00
|
|
|
|
2014-06-12 14:14:12 +02:00
|
|
|
|
|
|
|
/*********
|
|
|
|
** DMA **
|
|
|
|
*********/
|
|
|
|
|
2012-05-24 21:31:02 +02:00
|
|
|
struct dma_pool
|
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
int align;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct dma_pool *dma_pool_create(const char *name, struct device *d, size_t size,
|
|
|
|
size_t align, size_t alloc)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "size: %zx align:%zx %p", size, align, __builtin_return_address((0)));
|
2012-05-24 21:31:02 +02:00
|
|
|
|
|
|
|
if (align & (align - 1))
|
|
|
|
return 0;
|
|
|
|
|
2016-06-21 12:59:11 +02:00
|
|
|
dma_pool *pool = new(Lx::Malloc::mem()) dma_pool;
|
2012-05-24 21:31:02 +02:00
|
|
|
pool->align = Genode::log2((int)align);
|
|
|
|
pool->size = size;
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dma_pool_destroy(struct dma_pool *d)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "close");
|
2016-06-21 12:59:11 +02:00
|
|
|
destroy(Lx::Malloc::mem(), d);
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *dma_pool_alloc(struct dma_pool *d, gfp_t f, dma_addr_t *dma)
|
|
|
|
{
|
2013-05-16 12:17:03 +02:00
|
|
|
void *addr;
|
|
|
|
addr = dma_alloc_coherent(0, d->size, dma, 0);
|
|
|
|
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "addr: %p size %zx align %x phys: %lx pool %p",
|
2013-05-16 12:17:03 +02:00
|
|
|
addr, d->size, d->align, *dma, d);
|
|
|
|
return addr;
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dma_pool_free(struct dma_pool *d, void *vaddr, dma_addr_t a)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, d->size);
|
2016-05-18 18:51:11 +02:00
|
|
|
Lx::Malloc::dma().free(vaddr);
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *dma_alloc_coherent(struct device *, size_t size, dma_addr_t *dma, gfp_t)
|
|
|
|
{
|
2016-05-18 18:51:11 +02:00
|
|
|
void *addr = Lx::Malloc::dma().alloc(size, PAGE_SHIFT, dma);
|
2012-08-03 18:32:51 +02:00
|
|
|
|
|
|
|
if (!addr)
|
|
|
|
return 0;
|
|
|
|
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "DMA pool alloc addr: %p size %zx align: %d, phys: %lx",
|
2012-08-03 18:32:51 +02:00
|
|
|
addr, size, PAGE_SHIFT, *dma);
|
|
|
|
return addr;
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dma_free_coherent(struct device *, size_t size, void *vaddr, dma_addr_t)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, size);
|
2016-05-18 18:51:11 +02:00
|
|
|
Lx::Malloc::dma().free(vaddr);
|
2012-05-24 21:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
** linux/dma-mapping.h **
|
|
|
|
*************************/
|
|
|
|
|
|
|
|
dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
|
|
|
|
size_t size,
|
|
|
|
enum dma_data_direction dir,
|
|
|
|
struct dma_attrs *attrs)
|
|
|
|
{
|
2016-05-18 18:51:11 +02:00
|
|
|
dma_addr_t phys = (dma_addr_t)Lx::Malloc::dma().phys_addr(ptr);
|
2012-08-03 18:32:51 +02:00
|
|
|
|
2013-03-04 11:20:42 +01:00
|
|
|
if (phys == ~0UL)
|
2016-06-21 12:59:11 +02:00
|
|
|
Genode::error("translation virt->phys ", ptr, "->", Genode::Hex(phys), "failed, return ip ",
|
2013-03-04 11:20:42 +01:00
|
|
|
__builtin_return_address(0));
|
|
|
|
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "virt: %p phys: %lx", ptr, phys);
|
2012-05-24 21:31:02 +02:00
|
|
|
return phys;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dma_addr_t dma_map_page(struct device *dev, struct page *page,
|
|
|
|
size_t offset, size_t size,
|
|
|
|
enum dma_data_direction dir)
|
|
|
|
{
|
2015-05-12 15:16:19 +02:00
|
|
|
lx_log(DEBUG_DMA, "virt: %p phys: %lx offs: %zx", page->virt, page->phys, offset);
|
2012-05-24 21:31:02 +02:00
|
|
|
return page->phys + offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
|
|
|
|
int nents, enum dma_data_direction dir,
|
|
|
|
struct dma_attrs *attrs) { return nents; }
|
|
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
** linux/kthread.h **
|
|
|
|
*********************/
|
|
|
|
|
|
|
|
struct task_struct *kthread_run(int (*fn)(void *), void *arg, const char *n, ...)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is just called for delayed device scanning (see
|
|
|
|
* 'drivers/usb/storage/usb.c')
|
|
|
|
*/
|
2016-05-18 18:51:11 +02:00
|
|
|
lx_log(DEBUG_THREAD, "Run %s", n);
|
|
|
|
|
2016-06-21 12:59:11 +02:00
|
|
|
new (Lx::Malloc::mem()) Lx::Task((void (*)(void *))fn, arg, n,
|
|
|
|
Lx::Task::PRIORITY_2,
|
|
|
|
Lx::scheduler());
|
2012-05-24 21:31:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
** linux/scatterlist.h **
|
|
|
|
*************************/
|
|
|
|
|
|
|
|
struct scatterlist *sg_next(struct scatterlist *sg)
|
|
|
|
{
|
|
|
|
if (sg->last)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return sg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct page *sg_page(struct scatterlist *sg)
|
|
|
|
{
|
|
|
|
if (!sg)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (page *)sg->page_link;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *sg_virt(struct scatterlist *sg)
|
|
|
|
{
|
|
|
|
if (!sg || !sg->page_link)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
struct page *page = (struct page *)sg->page_link;
|
|
|
|
return (void *)((unsigned long)page->virt + sg->offset);
|
|
|
|
}
|
2012-06-20 08:42:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
** linux/ioport.h **
|
|
|
|
********************/
|
|
|
|
|
2013-05-16 12:17:03 +02:00
|
|
|
struct resource * devm_request_mem_region(struct device *dev, resource_size_t start,
|
|
|
|
resource_size_t n, const char *name)
|
|
|
|
{
|
|
|
|
struct resource *r = (struct resource *)kzalloc(sizeof(struct resource), GFP_KERNEL);
|
|
|
|
r->start = start;
|
|
|
|
r->end = start + n - 1;
|
|
|
|
r->name = name;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2012-06-25 16:31:04 +02:00
|
|
|
|
2016-05-18 18:51:11 +02:00
|
|
|
|
|
|
|
/*****************
|
|
|
|
** linux/smp.h **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
|
|
|
|
int wait) { func(info); return 0; }
|
|
|
|
|
|
|
|
|
2012-06-25 16:31:04 +02:00
|
|
|
/****************
|
|
|
|
** Networking **
|
|
|
|
****************/
|
|
|
|
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
** linux/etherdevice.h **
|
|
|
|
*************************/
|
|
|
|
|
|
|
|
struct net_device *alloc_etherdev(int sizeof_priv)
|
|
|
|
{
|
2016-06-21 12:59:11 +02:00
|
|
|
net_device *dev = new (Lx::Malloc::mem()) net_device();
|
2012-06-25 16:31:04 +02:00
|
|
|
|
|
|
|
dev->mtu = 1500;
|
|
|
|
dev->hard_header_len = 0;
|
|
|
|
dev->priv = kzalloc(sizeof_priv, 0);
|
|
|
|
dev->dev_addr = dev->_dev_addr;
|
|
|
|
memset(dev->_dev_addr, 0, sizeof(dev->_dev_addr));
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int is_valid_ether_addr(const u8 *addr)
|
|
|
|
{
|
|
|
|
/* is multicast */
|
2013-09-15 17:39:59 +02:00
|
|
|
if ((addr[0] & 0x1))
|
2012-06-25 16:31:04 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* zero */
|
|
|
|
if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]))
|
|
|
|
return 0;
|
2013-09-15 17:39:59 +02:00
|
|
|
|
2012-06-25 16:31:04 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
** linux/mii.h **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Restart NWay (autonegotiation) for this interface
|
|
|
|
*/
|
|
|
|
int mii_nway_restart (struct mii_if_info *mii)
|
|
|
|
{
|
|
|
|
int bmcr;
|
|
|
|
int r = -EINVAL;
|
|
|
|
enum {
|
|
|
|
BMCR_ANENABLE = 0x1000, /* enable auto negotiation */
|
|
|
|
BMCR_ANRESTART = 0x200, /* auto negotation restart */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* if autoneg is off, it's an error */
|
|
|
|
bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
|
|
|
|
|
|
|
|
if (bmcr & BMCR_ANENABLE) {
|
|
|
|
printk("Reanable\n");
|
|
|
|
bmcr |= BMCR_ANRESTART;
|
|
|
|
mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
|
|
|
|
{
|
|
|
|
ecmd->duplex = DUPLEX_FULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
|
|
|
|
{
|
|
|
|
u8 cap = 0;
|
|
|
|
|
|
|
|
if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) {
|
|
|
|
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
|
|
|
|
} else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) {
|
|
|
|
if (lcladv & ADVERTISE_PAUSE_CAP)
|
|
|
|
cap = FLOW_CTRL_RX;
|
|
|
|
else if (rmtadv & ADVERTISE_PAUSE_CAP)
|
|
|
|
cap = FLOW_CTRL_TX;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cap;
|
|
|
|
}
|
|
|
|
|
2014-06-02 13:50:17 +02:00
|
|
|
int mii_link_ok (struct mii_if_info *mii)
|
|
|
|
{
|
|
|
|
/* first, a dummy read, needed to latch some MII phys */
|
|
|
|
mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
|
|
|
|
if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-25 16:31:04 +02:00
|
|
|
|
2014-06-02 13:50:17 +02:00
|
|
|
unsigned int mii_check_media (struct mii_if_info *mii,
|
|
|
|
unsigned int ok_to_print,
|
|
|
|
unsigned int init_media)
|
|
|
|
{
|
|
|
|
if (mii_link_ok(mii))
|
|
|
|
netif_carrier_on(mii->dev);
|
|
|
|
else
|
|
|
|
netif_carrier_off(mii->dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
** linux/log2.h **
|
|
|
|
******************/
|
|
|
|
|
|
|
|
|
|
|
|
int rounddown_pow_of_two(u32 n)
|
|
|
|
{
|
|
|
|
return 1U << Genode::log2(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-13 15:44:15 +01:00
|
|
|
/*****************
|
|
|
|
** linux/nls.h **
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
int utf16s_to_utf8s(const wchar_t *pwcs, int len,
|
|
|
|
enum utf16_endian endian, u8 *s, int maxlen)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We do not convert to char, we simply copy the UTF16 plane 0 values
|
|
|
|
*/
|
|
|
|
u16 *out = (u16 *)s;
|
|
|
|
u16 *in = (u16 *)pwcs;
|
2018-09-05 12:45:21 +02:00
|
|
|
int length = min(len, maxlen / 2);
|
2014-11-13 15:44:15 +01:00
|
|
|
for (int i = 0; i < length; i++)
|
|
|
|
out[i] = in[i];
|
|
|
|
|
|
|
|
return 2 * length;
|
|
|
|
}
|
2015-05-08 18:00:35 +02:00
|
|
|
|
|
|
|
/**********************
|
|
|
|
** linux/notifier.h **
|
|
|
|
**********************/
|
|
|
|
|
|
|
|
int raw_notifier_chain_register(struct raw_notifier_head *nh,
|
|
|
|
struct notifier_block *n)
|
|
|
|
{
|
|
|
|
struct notifier_block *nl = nh->head;
|
|
|
|
struct notifier_block *pr = 0;
|
|
|
|
while (nl) {
|
|
|
|
if (n->priority > nl->priority)
|
|
|
|
break;
|
|
|
|
pr = nl;
|
|
|
|
nl = nl->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
n->next = nl;
|
|
|
|
if (pr)
|
|
|
|
pr->next = n;
|
|
|
|
else
|
|
|
|
nh->head = n;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int raw_notifier_call_chain(struct raw_notifier_head *nh,
|
|
|
|
unsigned long val, void *v)
|
|
|
|
{
|
|
|
|
int ret = NOTIFY_DONE;
|
|
|
|
struct notifier_block *nb = nh->head;
|
|
|
|
|
|
|
|
while (nb) {
|
|
|
|
|
|
|
|
ret = nb->notifier_call(nb, val, v);
|
|
|
|
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
|
|
|
|
break;
|
|
|
|
|
|
|
|
nb = nb->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
|
|
|
|
struct notifier_block *n)
|
|
|
|
{
|
|
|
|
return raw_notifier_chain_register((struct raw_notifier_head *)nh, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
|
|
|
unsigned long val, void *v)
|
|
|
|
{
|
|
|
|
return raw_notifier_call_chain((struct raw_notifier_head *)nh, val, v);
|
|
|
|
}
|
2016-05-18 18:51:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*******************
|
|
|
|
** linux/timer.h **
|
|
|
|
*******************/
|
|
|
|
|
|
|
|
#include <lx_emul/impl/timer.h>
|
|
|
|
#include <lx_emul/impl/sched.h>
|
|
|
|
|
|
|
|
signed long schedule_timeout_uninterruptible(signed long timeout)
|
|
|
|
{
|
|
|
|
lx_log(DEBUG_COMPLETION, "%ld\n", timeout);
|
|
|
|
schedule_timeout(timeout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************
|
|
|
|
** linux/completion.h **
|
|
|
|
************************/
|
|
|
|
|
|
|
|
#include <lx_emul/impl/completion.h>
|
|
|
|
|
|
|
|
|
2018-06-28 15:05:38 +02:00
|
|
|
static void _completion_timeout(struct timer_list *t)
|
2016-05-18 18:51:11 +02:00
|
|
|
{
|
2018-06-28 15:05:38 +02:00
|
|
|
Lx::Task *task = (Lx::Task *)t->data;
|
2016-05-18 18:51:11 +02:00
|
|
|
task->unblock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long __wait_completion(struct completion *work, unsigned long timeout)
|
|
|
|
{
|
|
|
|
timer_list t;
|
|
|
|
unsigned long j = timeout ? jiffies + timeout : 0;
|
|
|
|
|
|
|
|
if (timeout) {
|
2018-06-28 15:05:38 +02:00
|
|
|
timer_setup(&t, _completion_timeout, 0u);
|
|
|
|
t.data = (unsigned long)Lx::scheduler().current();
|
2016-05-18 18:51:11 +02:00
|
|
|
mod_timer(&t, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!work->done) {
|
|
|
|
|
2018-03-23 14:15:25 +01:00
|
|
|
if (j && j <= jiffies)
|
2016-05-18 18:51:11 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
Lx::Task *task = Lx::scheduler().current();
|
|
|
|
work->task = (void *)task;
|
|
|
|
task->block_and_schedule();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout)
|
|
|
|
del_timer(&t);
|
|
|
|
|
|
|
|
work->done = 0;
|
|
|
|
|
|
|
|
return j ? j - jiffies : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************
|
|
|
|
** linux/workqueue.h **
|
|
|
|
***********************/
|
|
|
|
|
|
|
|
#include <lx_emul/impl/work.h>
|
|
|
|
|
|
|
|
|
|
|
|
void tasklet_init(struct tasklet_struct *t, void (*f)(unsigned long), unsigned long d)
|
|
|
|
{
|
|
|
|
t->func = f;
|
|
|
|
t->data = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tasklet_schedule(struct tasklet_struct *tasklet)
|
|
|
|
{
|
|
|
|
Lx::Work *lx_work = (Lx::Work *)tasklet_wq->task;
|
|
|
|
lx_work->schedule_tasklet(tasklet);
|
|
|
|
lx_work->unblock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tasklet_hi_schedule(struct tasklet_struct *tasklet)
|
|
|
|
{
|
|
|
|
tasklet_schedule(tasklet);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct workqueue_struct *create_singlethread_workqueue(char const *name)
|
|
|
|
{
|
|
|
|
workqueue_struct *wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0);
|
2016-06-21 12:59:11 +02:00
|
|
|
Lx::Work *work = Lx::Work::alloc_work_queue(&Lx::Malloc::mem(), name);
|
2016-05-18 18:51:11 +02:00
|
|
|
wq->task = (void *)work;
|
|
|
|
|
|
|
|
return wq;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags,
|
|
|
|
int max_active, ...)
|
|
|
|
{
|
|
|
|
return create_singlethread_workqueue(fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
** linux/wait.h **
|
|
|
|
******************/
|
|
|
|
|
|
|
|
#include <lx_emul/impl/wait.h>
|
|
|
|
|
2017-10-16 21:47:40 +02:00
|
|
|
/*******************
|
|
|
|
** lib/hexdump.c **
|
|
|
|
*******************/
|
|
|
|
|
|
|
|
#include <linux/ctype.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* hex_to_bin - convert a hex digit to its real value
|
|
|
|
* @ch: ascii character represents hex digit
|
|
|
|
*
|
|
|
|
* hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
|
|
|
|
* input.
|
|
|
|
*/
|
|
|
|
int hex_to_bin(char ch)
|
|
|
|
{
|
|
|
|
if ((ch >= '0') && (ch <= '9'))
|
|
|
|
return ch - '0';
|
|
|
|
ch = tolower(ch);
|
|
|
|
if ((ch >= 'a') && (ch <= 'f'))
|
|
|
|
return ch - 'a' + 10;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* hex2bin - convert an ascii hexadecimal string to its binary representation
|
|
|
|
* @dst: binary result
|
|
|
|
* @src: ascii hexadecimal string
|
|
|
|
* @count: result length
|
|
|
|
*
|
|
|
|
* Return 0 on success, -1 in case of bad input.
|
|
|
|
*/
|
|
|
|
int hex2bin(u8 *dst, const char *src, size_t count)
|
|
|
|
{
|
|
|
|
while (count--) {
|
|
|
|
int hi = hex_to_bin(*src++);
|
|
|
|
int lo = hex_to_bin(*src++);
|
|
|
|
|
|
|
|
if ((hi < 0) || (lo < 0))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*dst++ = (hi << 4) | lo;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-28 15:05:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*******************
|
|
|
|
** linux/timer.h **
|
|
|
|
*******************/
|
|
|
|
|
|
|
|
extern "C" void init_timer(struct timer_list *) { }
|
|
|
|
|
2018-09-05 09:20:55 +02:00
|
|
|
struct callback_timer {
|
|
|
|
void (*function)(unsigned long);
|
|
|
|
unsigned long data;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void timer_callback(struct timer_list *t)
|
|
|
|
{
|
|
|
|
struct callback_timer * tc = (struct callback_timer *)t->data;
|
|
|
|
tc->function(tc->data);
|
|
|
|
}
|
2018-06-28 15:05:38 +02:00
|
|
|
|
|
|
|
extern "C" void setup_timer(struct timer_list *timer, void (*function)(unsigned long),
|
|
|
|
unsigned long data)
|
|
|
|
{
|
2018-09-05 09:20:55 +02:00
|
|
|
callback_timer * tc = new (Lx::Malloc::mem()) callback_timer;
|
|
|
|
tc->function = function;
|
|
|
|
tc->data = data;
|
|
|
|
|
|
|
|
timer_setup(timer, timer_callback, 0u);
|
|
|
|
timer->data = (unsigned long)tc;
|
2018-06-28 15:05:38 +02:00
|
|
|
}
|