771 lines
15 KiB
C++
771 lines
15 KiB
C++
|
/*
|
||
|
* \brief Emulation of Linux kernel interfaces
|
||
|
* \author Norman Feske
|
||
|
* \author Sebastian Sumpf
|
||
|
* \date 2012-01-29
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Copyright (C) 2012 Genode Labs GmbH
|
||
|
*
|
||
|
* This file is part of the Genode OS framework, which is distributed
|
||
|
* under the terms of the GNU General Public License version 2.
|
||
|
*/
|
||
|
|
||
|
/* Genode includes */
|
||
|
#include <base/allocator_avl.h>
|
||
|
#include <dataspace/client.h>
|
||
|
#include <rm_session/connection.h>
|
||
|
#include <timer_session/connection.h>
|
||
|
#include <util/string.h>
|
||
|
|
||
|
/* Local includes */
|
||
|
#include "routine.h"
|
||
|
#include "signal.h"
|
||
|
#include "lx_emul.h"
|
||
|
|
||
|
/* DDE kit includes */
|
||
|
extern "C" {
|
||
|
#include <dde_kit/semaphore.h>
|
||
|
#include <dde_kit/memory.h>
|
||
|
#include <dde_kit/pgtab.h>
|
||
|
#include <dde_kit/resources.h>
|
||
|
#include <dde_kit/interrupt.h>
|
||
|
#include <dde_kit/thread.h>
|
||
|
}
|
||
|
|
||
|
|
||
|
#if VERBOSE_LX_EMUL
|
||
|
#define TRACE dde_kit_printf("\033[35m%s\033[0m called\n", __PRETTY_FUNCTION__)
|
||
|
#define UNSUPPORTED dde_kit_printf("\033[31m%s\033[0m unsupported arguments\n", __PRETTY_FUNCTION__)
|
||
|
#else
|
||
|
#define TRACE
|
||
|
#define UNSUPPORTED
|
||
|
#endif
|
||
|
|
||
|
/***********************
|
||
|
** Atomic operations **
|
||
|
***********************/
|
||
|
|
||
|
/*
|
||
|
* Actually not atomic, for now
|
||
|
*/
|
||
|
|
||
|
unsigned int atomic_read(atomic_t *p) { return *(volatile int *)p; }
|
||
|
|
||
|
void atomic_inc(atomic_t *v) { (*(volatile int *)v)++; }
|
||
|
void atomic_dec(atomic_t *v) { (*(volatile int *)v)--; }
|
||
|
|
||
|
void atomic_add(int i, atomic_t *v) { (*(volatile int *)v) += i; }
|
||
|
void atomic_sub(int i, atomic_t *v) { (*(volatile int *)v) -= i; }
|
||
|
|
||
|
void atomic_set(atomic_t *p, unsigned int v) { (*(volatile int *)p) = v; }
|
||
|
|
||
|
/*******************
|
||
|
** linux/mutex.h **
|
||
|
*******************/
|
||
|
|
||
|
void mutex_init (struct mutex *m) { if (m->lock) dde_kit_lock_init (&m->lock); }
|
||
|
void mutex_lock (struct mutex *m) { if (m->lock) dde_kit_lock_lock ( m->lock); }
|
||
|
void mutex_unlock(struct mutex *m) { if (m->lock) dde_kit_lock_unlock( m->lock); }
|
||
|
|
||
|
|
||
|
/*************************************
|
||
|
** Memory allocation, linux/slab.h **
|
||
|
*************************************/
|
||
|
|
||
|
void *kmalloc(size_t size, gfp_t flags)
|
||
|
{
|
||
|
return dde_kit_large_malloc(size);
|
||
|
}
|
||
|
|
||
|
|
||
|
void *kzalloc(size_t size, gfp_t flags)
|
||
|
{
|
||
|
void *addr = dde_kit_large_malloc(size);
|
||
|
if (addr)
|
||
|
Genode::memset(addr, 0, size);
|
||
|
return addr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void *kcalloc(size_t n, size_t size, gfp_t flags)
|
||
|
{
|
||
|
if (size != 0 && n > ~0UL / size)
|
||
|
return 0;
|
||
|
|
||
|
return kzalloc(n * size, flags);
|
||
|
}
|
||
|
|
||
|
void kfree(const void *p)
|
||
|
{
|
||
|
dde_kit_large_free((void *)p);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*********************
|
||
|
** linux/vmalloc.h **
|
||
|
*********************/
|
||
|
|
||
|
void *vzalloc(unsigned long size)
|
||
|
{
|
||
|
void *ptr = dde_kit_simple_malloc(size);
|
||
|
if (ptr)
|
||
|
Genode::memset(ptr, 0, size);
|
||
|
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void vfree(void *addr) { dde_kit_simple_free(addr); }
|
||
|
|
||
|
|
||
|
/******************
|
||
|
** linux/kref.h **
|
||
|
******************/
|
||
|
|
||
|
void kref_init(struct kref *kref)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_KREF,"%s ref: %p", __func__, kref);
|
||
|
kref->refcount.v = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void kref_get(struct kref *kref)
|
||
|
{
|
||
|
kref->refcount.v++;
|
||
|
dde_kit_log(DEBUG_KREF, "%s ref: %p c: %d", __func__, kref, kref->refcount.v);
|
||
|
}
|
||
|
|
||
|
|
||
|
int kref_put(struct kref *kref, void (*release) (struct kref *kref))
|
||
|
{
|
||
|
dde_kit_log(DEBUG_KREF, "%s: ref: %p c: %d", __func__, kref, kref->refcount.v);
|
||
|
|
||
|
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)
|
||
|
Genode::memcpy(dst, src, len);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t copy_from_user(void *dst, void const *src, size_t len)
|
||
|
{
|
||
|
if (dst && src && len)
|
||
|
Genode::memcpy(dst, src, len);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool access_ok(int access, void *addr, size_t size) { return 1; }
|
||
|
|
||
|
|
||
|
/********************
|
||
|
** linux/string.h **
|
||
|
********************/
|
||
|
|
||
|
void *memcpy(void *dest, const void *src, size_t n) {
|
||
|
return Genode::memcpy(dest, src, n); }
|
||
|
|
||
|
|
||
|
void *memset(void *s, int c, size_t n) {
|
||
|
return Genode::memset(s, c, n); }
|
||
|
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t strlen(const char *s) { return Genode::strlen(s); }
|
||
|
|
||
|
|
||
|
size_t strlcat(char *dest, const char *src, size_t n)
|
||
|
{
|
||
|
size_t len = strlen(dest);
|
||
|
Genode::strncpy(dest + len, src, n);
|
||
|
dest[len + n] = 0;
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
|
||
|
void *kmemdup(const void *src, size_t len, gfp_t gfp)
|
||
|
{
|
||
|
void *ptr = kmalloc(len, 0);
|
||
|
memcpy(ptr, src, len);
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************
|
||
|
** linux/log2.h **
|
||
|
******************/
|
||
|
|
||
|
int ilog2(u32 n) { return Genode::log2(n); }
|
||
|
|
||
|
|
||
|
/********************
|
||
|
** linux/slab.h **
|
||
|
********************/
|
||
|
|
||
|
struct kmem_cache
|
||
|
{
|
||
|
const char *name; /* cache name */
|
||
|
unsigned size; /* object size */
|
||
|
|
||
|
struct dde_kit_slab *dde_kit_slab_cache; /* backing DDE kit cache */
|
||
|
};
|
||
|
|
||
|
|
||
|
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
|
||
|
unsigned long falgs, void (*ctor)(void *))
|
||
|
{
|
||
|
dde_kit_log(DEBUG_SLAB, "\"%s\" obj_size=%d", name, size);
|
||
|
|
||
|
struct kmem_cache *cache;
|
||
|
|
||
|
if (!name) {
|
||
|
printk("kmem_cache name reqeuired\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
cache = (struct kmem_cache *)dde_kit_simple_malloc(sizeof(*cache));
|
||
|
if (!cache) {
|
||
|
printk("No memory for slab cache\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* initialize a physically contiguous cache for kmem */
|
||
|
if (!(cache->dde_kit_slab_cache = dde_kit_slab_init(size))) {
|
||
|
printk("DDE kit slab init failed\n");
|
||
|
dde_kit_simple_free(cache);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
cache->name = name;
|
||
|
cache->size = size;
|
||
|
|
||
|
return cache;
|
||
|
}
|
||
|
|
||
|
|
||
|
void kmem_cache_destroy(struct kmem_cache *cache)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_SLAB, "\"%s\"", cache->name);
|
||
|
|
||
|
dde_kit_slab_destroy(cache->dde_kit_slab_cache);
|
||
|
dde_kit_simple_free(cache);
|
||
|
}
|
||
|
|
||
|
|
||
|
void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags)
|
||
|
{
|
||
|
void *ret;
|
||
|
|
||
|
dde_kit_log(DEBUG_SLAB, "\"%s\" flags=%x", cache->name, flags);
|
||
|
|
||
|
ret = dde_kit_slab_alloc(cache->dde_kit_slab_cache);
|
||
|
|
||
|
/* return here in case of error */
|
||
|
if (!ret) return 0;
|
||
|
|
||
|
/* zero page */
|
||
|
memset(ret, 0, cache->size);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
void kmem_cache_free(struct kmem_cache *cache, void *objp)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_SLAB, "\"%s\" (%p)", cache->name, objp);
|
||
|
dde_kit_slab_free(cache->dde_kit_slab_cache, objp);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**********************
|
||
|
** asm-generic/io.h **
|
||
|
**********************/
|
||
|
|
||
|
void *ioremap_wc(resource_size_t phys_addr, unsigned long size)
|
||
|
{
|
||
|
dde_kit_addr_t map_addr;
|
||
|
if (dde_kit_request_mem(phys_addr, size, 1, &map_addr)) {
|
||
|
PERR("Failed to request I/O memory: [%x,%lx)", phys_addr, phys_addr + size);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return (void *)map_addr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************
|
||
|
** linux/device.h **
|
||
|
********************/
|
||
|
|
||
|
/**
|
||
|
* Simple driver management class
|
||
|
*/
|
||
|
class Driver : public Genode::List<Driver>::Element
|
||
|
{
|
||
|
private:
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true;
|
||
|
dde_kit_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p",
|
||
|
_drv->name, ret, _drv->bus->match);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Probe device with driver
|
||
|
*/
|
||
|
int probe(struct device *dev)
|
||
|
{
|
||
|
dev->driver = _drv;
|
||
|
|
||
|
if (dev->bus->probe) {
|
||
|
dde_kit_log(DEBUG_DRIVER, "Probing device bus");
|
||
|
return dev->bus->probe(dev);
|
||
|
} else if (_drv->probe) {
|
||
|
dde_kit_log(DEBUG_DRIVER, "Probing driver: %s", _drv->name);
|
||
|
return _drv->probe(dev);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
int driver_register(struct device_driver *drv)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_DRIVER, "%s at %p", drv->name, drv);
|
||
|
new (Genode::env()->heap()) Driver(drv);
|
||
|
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);
|
||
|
dde_kit_log(DEBUG_DRIVER, "Probe return %d", ret);
|
||
|
if (!ret)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int device_register(struct device *dev)
|
||
|
{
|
||
|
//XXX: initialize DMA pools (see device_initialize)
|
||
|
return device_add(dev);
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct device *get_device(struct device *dev) { TRACE; return dev; }
|
||
|
|
||
|
|
||
|
long find_next_zero_bit_le(const void *addr,
|
||
|
unsigned long size, unsigned long offset)
|
||
|
{
|
||
|
unsigned long max_size = sizeof(long) * 8;
|
||
|
if (offset >= max_size) {
|
||
|
PWRN("Offset greater max size");
|
||
|
return offset + size;
|
||
|
}
|
||
|
|
||
|
for (; offset < max_size; offset++)
|
||
|
if (!(*(unsigned long*)addr & (1 << offset)))
|
||
|
return offset;
|
||
|
|
||
|
PERR("No zero bit findable");
|
||
|
return offset + size;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************
|
||
|
** linux/byteorder/generic.h **
|
||
|
*******************************/
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
struct __una_u64 *ptr = (struct __una_u64 *)p;
|
||
|
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))
|
||
|
return i;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************
|
||
|
** linux/delay.h **
|
||
|
*******************/
|
||
|
|
||
|
static Timer::Connection _timer;
|
||
|
|
||
|
|
||
|
void udelay(unsigned long usecs)
|
||
|
{
|
||
|
_timer.msleep(usecs < 1000 ? 1 : usecs / 1000);
|
||
|
}
|
||
|
|
||
|
|
||
|
void msleep(unsigned int msecs) { _timer.msleep(msecs); }
|
||
|
|
||
|
|
||
|
/*********************
|
||
|
** linux/jiffies.h **
|
||
|
*********************/
|
||
|
|
||
|
/*
|
||
|
* We use DDE kit's jiffies in 100Hz granularity.
|
||
|
*/
|
||
|
enum { JIFFIES_TICK_MS = 1000 / DDE_KIT_HZ };
|
||
|
|
||
|
unsigned long msecs_to_jiffies(const unsigned int m) { return m / JIFFIES_TICK_MS; }
|
||
|
long time_after_eq(long a, long b) { return (a - b) >= 0; }
|
||
|
long time_after(long a, long b) { return (b - a) > 0; }
|
||
|
|
||
|
|
||
|
/*********************
|
||
|
** linux/dmapool.h **
|
||
|
*********************/
|
||
|
|
||
|
namespace Genode {
|
||
|
|
||
|
/**
|
||
|
* Dma-pool manager
|
||
|
*/
|
||
|
class Dma
|
||
|
{
|
||
|
private:
|
||
|
|
||
|
enum { SIZE = 1024 * 1024 };
|
||
|
|
||
|
addr_t _base; /* virt base of pool */
|
||
|
addr_t _base_phys; /* phys base of pool */
|
||
|
Allocator_avl _range; /* range allocator for pool */
|
||
|
|
||
|
Dma() : _range(env()->heap())
|
||
|
{
|
||
|
Ram_dataspace_capability cap = env()->ram_session()->alloc(SIZE);
|
||
|
_base_phys = Dataspace_client(cap).phys_addr();
|
||
|
_base = (addr_t)env()->rm_session()->attach(cap);
|
||
|
dde_kit_log(DEBUG_DMA, "New DMA range [%lx-%lx)", _base, _base + SIZE);
|
||
|
_range.add_range(_base, SIZE);
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
|
||
|
static Dma* pool()
|
||
|
{
|
||
|
static Dma _p;
|
||
|
return &_p;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Alloc 'size' bytes of DMA memory
|
||
|
*/
|
||
|
void *alloc(size_t size, int align = PAGE_SHIFT)
|
||
|
{
|
||
|
void *addr;
|
||
|
if (!_range.alloc_aligned(size, &addr, align)) {
|
||
|
PERR("DMA of %zu bytes allocation failed", size);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return addr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Free DMA memory
|
||
|
*/
|
||
|
void free(void *addr) { _range.free(addr); }
|
||
|
|
||
|
/**
|
||
|
* Get phys for virt address
|
||
|
*/
|
||
|
addr_t phys_addr(void *addr)
|
||
|
{
|
||
|
addr_t a = (addr_t)addr;
|
||
|
if (a < _base || a >= _base + SIZE) {
|
||
|
PERR("No DMA phys addr for %lx", a);
|
||
|
return 0;
|
||
|
}
|
||
|
return (a - _base) + _base_phys;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_DMA, "size: %zx align:%zx", size, align);
|
||
|
|
||
|
if (align & (align - 1))
|
||
|
return 0;
|
||
|
|
||
|
dma_pool *pool = new(Genode::env()->heap()) dma_pool;
|
||
|
pool->align = Genode::log2((int)align);
|
||
|
pool->size = size;
|
||
|
return pool;
|
||
|
}
|
||
|
|
||
|
|
||
|
void dma_pool_destroy(struct dma_pool *d)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_DMA, "close");
|
||
|
destroy(Genode::env()->heap(), d);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void* _alloc(size_t size, int align, dma_addr_t *dma)
|
||
|
{
|
||
|
void *addr = Genode::Dma::pool()->alloc(size, align);
|
||
|
dde_kit_log(DEBUG_DMA, "addr: %p size %zx align: %d", addr, size, align);
|
||
|
|
||
|
if (!addr)
|
||
|
return 0;
|
||
|
|
||
|
*dma = (dma_addr_t)Genode::Dma::pool()->phys_addr(addr);
|
||
|
return addr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void *dma_pool_alloc(struct dma_pool *d, gfp_t f, dma_addr_t *dma)
|
||
|
{
|
||
|
return _alloc(d->size, d->align, dma);
|
||
|
}
|
||
|
|
||
|
|
||
|
void dma_pool_free(struct dma_pool *d, void *vaddr, dma_addr_t a)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, d->size);
|
||
|
Genode::Dma::pool()->free(vaddr);
|
||
|
}
|
||
|
|
||
|
|
||
|
void *dma_alloc_coherent(struct device *, size_t size, dma_addr_t *dma, gfp_t)
|
||
|
{
|
||
|
return _alloc(size, PAGE_SHIFT, dma);
|
||
|
}
|
||
|
|
||
|
|
||
|
void dma_free_coherent(struct device *, size_t size, void *vaddr, dma_addr_t)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_DMA, "free: addr %p, size: %zx", vaddr, size);
|
||
|
Genode::Dma::pool()->free(vaddr);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************
|
||
|
** linux/dma-mapping.h **
|
||
|
*************************/
|
||
|
|
||
|
/**
|
||
|
* Translate virt to phys using DDE-kit
|
||
|
*/
|
||
|
dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
|
||
|
size_t size,
|
||
|
enum dma_data_direction dir,
|
||
|
struct dma_attrs *attrs)
|
||
|
{
|
||
|
dma_addr_t phys = (dma_addr_t)dde_kit_pgtab_get_physaddr(ptr);
|
||
|
dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx", ptr, phys);
|
||
|
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)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx offs: %zx", page->virt, page->phys, offset);
|
||
|
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/workquque.h **
|
||
|
***********************/
|
||
|
|
||
|
int schedule_delayed_work(struct delayed_work *work, unsigned long delay)
|
||
|
{
|
||
|
work->work.func(&(work)->work);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*********************
|
||
|
** linux/kthread.h **
|
||
|
*********************/
|
||
|
|
||
|
struct task_struct *kthread_run(int (*fn)(void *), void *arg, const char *n, ...)
|
||
|
{
|
||
|
dde_kit_log(DEBUG_THREAD, "Run %s", n);
|
||
|
Routine::add(fn, arg, n);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct task_struct *kthread_create(int (*threadfn)(void *data),
|
||
|
void *data,
|
||
|
const char namefmt[], ...)
|
||
|
{
|
||
|
/*
|
||
|
* This is just called for delayed device scanning (see
|
||
|
* 'drivers/usb/storage/usb.c')
|
||
|
*/
|
||
|
dde_kit_log(DEBUG_THREAD, "Create %s", namefmt);
|
||
|
Routine::add(threadfn, data, namefmt);
|
||
|
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);
|
||
|
}
|