diff --git a/.gitignore b/.gitignore index 399c80651..dadb3267b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ /base-okl4/download /base-pistachio/contrib /dde_ipxe/contrib +/dde_linux/contrib +/dde_linux/download /libports/contrib /libports/download /libports/include/EGL/egl.h diff --git a/README b/README index a0d913f21..c06b19b42 100644 --- a/README +++ b/README @@ -127,10 +127,17 @@ The Genode source tree is composed of the following subdirectories: For instructions about how to use this mechanism, please consult the README file at the top level of the repository. -:'linux_drivers': +:'dde_linux': This source-code repository contains the device driver environment for - executing Linux device drivers natively on Genode. + executing Linux device drivers natively on Genode. Currently, this + repository hosts the USB stack. + +:'linux_drivers': + + Deprecated version of the Linux device driver environment featuring audio + drivers and the Intel GEM driver. This repository is in a transitionary + phase. Its functionality will be incorporated into 'dde_linux'. :'dde_ipxe': diff --git a/dde_linux/Makefile b/dde_linux/Makefile new file mode 100644 index 000000000..5a5d58429 --- /dev/null +++ b/dde_linux/Makefile @@ -0,0 +1,98 @@ +# +# \brief Download integrate Linux kernel sources with Genode +# \author Norman Feske +# \date 2012-01-28 + +CONTRIB_DIR = contrib +DOWNLOAD_DIR = download +VERBOSE ?= @ +ECHO = @echo +PATCHES = $(shell find patches -name *.patch) + +LINUX = linux-3.2.2 +LINUX_TBZ2 = $(LINUX).tar.bz2 +LINUX_URL = http://www.kernel.org/pub/linux/kernel/v3.x/$(LINUX_TBZ2) + +# Linux utilities +CONTENT += include/linux/list.h +CONTENT += $(addprefix include/linux/,pci_ids.h pci_regs.h usb.h hid.h hiddev.h input.h mod_devicetable.h) +CONTENT += $(addprefix include/linux/byteorder/,generic.h little_endian.h) +CONTENT += include/linux/swab.h +CONTENT += $(addprefix include/asm-generic/bitops/,__ffs.h non-atomic.h) + +# USB core +CONTENT += drivers/usb/core +CONTENT += drivers/usb/usb-common.c +CONTENT_INCLUDE_USB := ch11.h ch9.h ehci_def.h hcd.h input.h otg.h quirks.h storage.h +CONTENT += $(addprefix include/linux/usb/,$(CONTENT_INCLUDE_USB)) + +# needed by usb/core/devio.c +CONTENT += include/linux/usbdevice_fs.h include/asm-generic/ioctl.h + +# USB host-controller driver +CONTENT_USB_HOST := ehci.h ehci-hcd.c ehci-hub.c ehci-dbg.c ehci-mem.c \ + ehci-q.c ehci-pci.c ehci-sched.c ehci-sysfs.c +CONTENT_USB_HOST += ohci.h ohci-hcd.c ohci-hub.c ohci-dbg.c ohci-mem.c \ + ohci-q.c ohci-pci.c ehci-lpm.c +CONTENT_USB_HOST += uhci-hcd.h uhci-hcd.c uhci-debug.c uhci-q.c uhci-hub.c \ + uhci-pci.c +CONTENT_USB_HOST += pci-quirks.h pci-quirks.c xhci-ext-caps.h +CONTENT += $(addprefix drivers/usb/host/,$(CONTENT_USB_HOST)) + +# USB storage driver +CONTENT += drivers/usb/storage/ +CONTENT += include/linux/usb_usual.h + +# SCSI support for storage +CONTENT += $(addprefix drivers/scsi/,scsi.h scsi.c constants.c scsi_priv.h scsi_logging.h) +CONTENT += $(addprefix include/scsi/,scsi.h scsi_host.h) + +# USB hid driver +CONTENT += drivers/hid/hid-input.c drivers/hid/hid-core.c drivers/hid/hid-ids.h +CONTENT += drivers/hid/usbhid + +# needed by USB hid +CONTENT_INPUT := input.c evdev.c input-compat.h +CONTENT += $(addprefix drivers/input/,$(CONTENT_INPUT)) +CONTENT += include/linux/input/mt.h + + +CONTRIB_CONTENT := $(addprefix $(CONTRIB_DIR)/,$(CONTENT)) + +# +# Print help information by default +# +help: + $(ECHO) + $(ECHO) "Download integrate Linux kernel sources with Genode" + $(ECHO) + $(ECHO) "--- available commands ---" + $(ECHO) "prepare - download and integrate Linux source code" + $(ECHO) "clean - remove contib sources except downloaded archives" + $(ECHO) "cleanall - remove contib sources and downloaded archives" + $(ECHO) + +prepare: $(CONTRIB_DIR)/.prepared + +$(CONTRIB_DIR)/.prepared: Makefile +$(CONTRIB_DIR)/.prepared: $(DOWNLOAD_DIR)/$(LINUX_TBZ2) + $(ECHO) "extracting source code to '$(CONTRIB_DIR)'" + $(VERBOSE)tar xfj $< --transform "s/$(LINUX)/$(CONTRIB_DIR)/" $(addprefix $(LINUX)/,$(CONTENT)) + $(VERBOSE)touch $@ + $(ECHO) "applying patches to '$(CONTRIB_DIR)/'" + $(VERBOSE)for i in $(PATCHES); do patch -d $(CONTRIB_DIR) -p1 < $$i; done + + +$(DOWNLOAD_DIR): + $(VERBOSE)mkdir -p $@ + +$(DOWNLOAD_DIR)/$(LINUX_TBZ2): $(DOWNLOAD_DIR) + $(ECHO) "downloading source code to '$@'" + $(VERBOSE)cd $(DOWNLOAD_DIR); wget -c $(LINUX_URL) + $(VERBOSE)touch $@ + +clean: + $(VERBOSE)rm -f $(CONTRIB_DIR) + +cleanall: clean + $(VERBOSE)rm -rf $(DOWNLOAD_DIR) diff --git a/dde_linux/README b/dde_linux/README new file mode 100644 index 000000000..c96d02d3c --- /dev/null +++ b/dde_linux/README @@ -0,0 +1,37 @@ +Device drivers ported from the Linux kernel + +USB +### + +HID +~~~ + +Supports keyboard and mouse. A run script can be found under 'run/usb_hid.run'. + +Configuration snippet: + +! +! +! +! +! +! +! + +Note: It has been observed that certain 1.0 versions of Qemu do not generate +mouse interrupts. The mouse driver should work correctly on Qemu 1.0.93 and +above. + +STORAGE +~~~~~~~ + +Currently supports one USB storage device. Hot plugging has not been tested. A +run script can be found under 'run/usb_storage.run'. + +Configuration snippet: + +! +! +! +! +! diff --git a/dde_linux/patches/evdev.patch b/dde_linux/patches/evdev.patch new file mode 100644 index 000000000..4618cb547 --- /dev/null +++ b/dde_linux/patches/evdev.patch @@ -0,0 +1,22 @@ +diff -r 1d04c9c5fa8a drivers/input/evdev.c +--- a/drivers/input/evdev.c Tue Apr 17 16:14:54 2012 +0200 ++++ b/drivers/input/evdev.c Wed Apr 18 11:25:37 2012 +0200 +@@ -957,6 +957,9 @@ + if (error) + goto err_cleanup_evdev; + ++ evdev_open_device(evdev); ++ dev_info(evdev, "%s\n", dev->name); ++ + return 0; + + err_cleanup_evdev: +@@ -986,7 +989,7 @@ + MODULE_DEVICE_TABLE(input, evdev_ids); + + static struct input_handler evdev_handler = { +- .event = evdev_event, ++ .event = genode_evdev_event, + .connect = evdev_connect, + .disconnect = evdev_disconnect, + .fops = &evdev_fops, diff --git a/dde_linux/run/usb_hid.run b/dde_linux/run/usb_hid.run new file mode 100644 index 000000000..30099e436 --- /dev/null +++ b/dde_linux/run/usb_hid.run @@ -0,0 +1,75 @@ +# +# Build +# + +set build_components { + core init + drivers/timer + drivers/pci + drivers/usb + test/input +} + +build $build_components + +create_boot_directory + +# +# Generate config +# + +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core init timer pci_drv usb_drv test-input +} + +build_boot_image $boot_modules + +append qemu_args " -m 256 -usb -usbdevice mouse -usbdevice keyboard" + + +run_genode_until forever diff --git a/dde_linux/run/usb_storage.run b/dde_linux/run/usb_storage.run new file mode 100644 index 000000000..adec08c04 --- /dev/null +++ b/dde_linux/run/usb_storage.run @@ -0,0 +1,107 @@ +# +# \brief Test for using the Block (Storage) service of usb_drv +# \author Christian Prochaska +# \date 2011-06-24 +# + +# +# Build +# + +build { + core init + drivers/pci + drivers/timer + drivers/usb + test/ahci +} + +create_boot_directory + +# +# Generate config +# + +set config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core init timer usb_drv pci_drv test-ahci +} + + +build_boot_image $boot_modules + +# +# Execute test case +# +set disk_image "bin/test.img" +set cmd "dd if=/dev/zero of=$disk_image bs=1024 count=65536" +puts "creating disk image:\n$cmd" +catch { exec sh -c $cmd } + +set cmd "mkfs.vfat -F32 $disk_image" +puts "formating disk image with vfat file system:\$cmd" +catch { exec sh -c $cmd } + +# +# Qemu opts for UHCI +# +#append qemu_args " -m 64 -nographic -usbdevice disk::$disk_image -boot order=d" + +# +# Qemu opts for EHCI +# +append qemu_args "-drive if=none,id=disk,file=$disk_image" +append qemu_args { \ +-m 64 -nographic -M pc \ +-device usb-ehci,id=ehci \ +-device usb-storage,bus=ehci.0,drive=disk \ +-boot order=d } + +run_genode_until {.*child exited with exit value 0.*} 40 + +puts "\ntest succeeded\n" + +# vi: set ft=tcl : diff --git a/dde_linux/src/drivers/usb/dummies.c b/dde_linux/src/drivers/usb/dummies.c new file mode 100644 index 000000000..0642876c5 --- /dev/null +++ b/dde_linux/src/drivers/usb/dummies.c @@ -0,0 +1,782 @@ +/* + * \brief Dummy functions + * \author Norman Feske + * \author Sebastian sumpf + * \date 2011-01-29 + */ + +/* + * Copyright (C) 2011-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. + */ + +/* Linux kernel API */ +#include + +/* DDE-Kit includes */ +#include + +/* Linux includes */ +#include + +#define SKIP_VERBOSE 0 + +#if VERBOSE_LX_EMUL +#define TRACE dde_kit_printf("\033[32m%s\033[0m called, not implemented\n", __PRETTY_FUNCTION__) +#else +#define TRACE +#endif +#if SKIP_VERBOSE +#define SKIP dde_kit_printf("\033[34m%s\033[0m: skipped\n", __PRETTY_FUNCTION__) +#else +#define SKIP +#endif + + +/****************** + ** asm/atomic.h ** + ******************/ + +int atomic_inc_return(atomic_t *v) { TRACE; return 0; } + + +/******************************* + ** linux/byteorder/generic.h ** + *******************************/ + +u16 get_unaligned_le16(const void *p) { TRACE; return 0; } +u32 get_unaligned_le32(const void *p) { TRACE; return 0; } + + +/******************************* + ** linux/errno.h and friends ** + *******************************/ + +long PTR_ERR(const void *ptr) { TRACE; return 0; } + + +/******************** + ** linux/kernel.h ** + ********************/ + +void might_sleep() { SKIP; } +char *kasprintf(gfp_t gfp, const char *fmt, ...) { TRACE; return NULL; } +int kstrtouint(const char *s, unsigned int base, unsigned int *res) { TRACE; return 0; } +int sprintf(char *buf, const char *fmt, ...) { TRACE; return 0; } +int sscanf(const char *b, const char *s, ...) { TRACE; return 0; } +int scnprintf(char *buf, size_t size, const char *fmt, ...) { TRACE; return 0; } +int strict_strtoul(const char *s, unsigned int base, unsigned long *res) { TRACE; return 0; } +long simple_strtoul(const char *cp, char **endp, unsigned int base) { TRACE; return 0; } + + +/****************** + ** linux/log2.h ** + ******************/ + +int roundup_pow_of_two(u32 n) { TRACE; return 0; } + + +/******************** + ** linux/printk.h ** + ********************/ + +void print_hex_dump(const char *level, const char *prefix_str, + int prefix_type, int rowsize, int groupsize, + const void *buf, size_t len, bool ascii) { TRACE; } + + +/********************************** + ** linux/bitops.h, asm/bitops.h ** + **********************************/ + +int ffs(int x) { TRACE; return 0; } + + +/******************** + ** linux/string.h ** + ********************/ + +int memcmp(const void *dst, const void *src, size_t s) { TRACE; return 0; } +char *strcat(char *dest, const char *src) { TRACE; return 0; } +int strcmp(const char *s1, const char *s2) { TRACE; return 0; } +int strncmp(const char *cs, const char *ct, size_t count) { TRACE; return 0; } +char *strncpy(char *dst, const char *src, size_t s) { TRACE; return NULL; } +char *strchr(const char *s, int n) { TRACE; return NULL; } +char *strrchr(const char *s, int n) { TRACE; return NULL; } +size_t strlcpy(char *dest, const char *src, size_t size) { TRACE; return 0; } +char *strsep(char **s,const char *d) { TRACE; return NULL; } +char *kstrdup(const char *s, gfp_t gfp) { TRACE; return 0; } +char *strstr(const char *h, const char *n) { TRACE; return 0; } + + +/***************** + ** linux/nls.h ** + *****************/ + +int utf16s_to_utf8s(const wchar_t *pwcs, int len, + enum utf16_endian endian, u8 *s, int maxlen) { TRACE; return 0; } + + +/******************* + ** linux/ctype.h ** + *******************/ + +int isprint(int v) { TRACE; return 0; } + + +/********************** + ** linux/spinlock.h ** + **********************/ + +void spin_lock(spinlock_t *lock) { SKIP; } +void spin_lock_nested(spinlock_t *lock, int subclass) { TRACE; } +void spin_unlock(spinlock_t *lock) { SKIP; } +void spin_lock_init(spinlock_t *lock) { SKIP; } +void spin_lock_irqsave(spinlock_t *lock, unsigned long flags) { SKIP; } +void spin_lock_irqrestore(spinlock_t *lock, unsigned long flags) { SKIP; } +void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { SKIP; } +void spin_lock_irq(spinlock_t *lock) { SKIP; } +void spin_unlock_irq(spinlock_t *lock) { SKIP; } +void assert_spin_locked(spinlock_t *lock) { TRACE;} + + + +/******************* + ** linux/mutex.h ** + *******************/ + +void mutex_lock_nested(struct mutex *lock, unsigned int subclass) { TRACE; } +int mutex_lock_interruptible(struct mutex *m) { TRACE; return 0; } + + +/******************* + ** linux/rwsem.h ** + *******************/ + +void down_read(struct rw_semaphore *sem) { TRACE; } +void up_read(struct rw_semaphore *sem) { TRACE; } +void down_write(struct rw_semaphore *sem) { TRACE; } +void up_write(struct rw_semaphore *sem) { TRACE; } + + +/******************* + ** linux/ktime.h ** + *******************/ + +ktime_t ktime_add_ns(const ktime_t kt, u64 nsec) { TRACE; ktime_t ret = { 0 }; return ret; } + +s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) { TRACE; return 0; }; + + +/******************* + ** linux/timer.h ** + *******************/ + +int del_timer_sync(struct timer_list *timer) { TRACE; return 0; } +unsigned long round_jiffies(unsigned long j) { TRACE; return 1; } + + +/********************* + ** linux/hrtimer.h ** + *********************/ + +ktime_t ktime_get_real(void) { TRACE; ktime_t ret; return ret; } + + +/******************* + ** linux/delay.h ** + *******************/ + +void mdelay(unsigned long msecs) { TRACE; } + + +/*********************** + ** linux/workquque.h ** + ***********************/ + +bool cancel_work_sync(struct work_struct *work) { TRACE; return 0; } +int cancel_delayed_work_sync(struct delayed_work *work) { TRACE; return 0; } +int schedule_work(struct work_struct *work) { TRACE; return 0; } +bool flush_work_sync(struct work_struct *work) { TRACE; return 0; } + + +/****************** + ** linux/wait.h ** + ******************/ + +void init_waitqueue_head(wait_queue_head_t *q) { TRACE; } +void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { TRACE; } +void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { TRACE; } + + +/****************** + ** linux/time.h ** + ******************/ + +struct timespec current_kernel_time(void) +{ + struct timespec t = { 0, 0 }; + return t; +} + +void do_gettimeofday(struct timeval *tv) { TRACE; } + + +/******************* + ** linux/sched.h ** + *******************/ + +int kill_pid_info_as_cred(int i, struct siginfo *s, struct pid *p, + const struct cred *c, u32 v) { TRACE; return 0; } +pid_t task_pid_nr(struct task_struct *tsk) { TRACE; return 0; } +struct pid *task_pid(struct task_struct *task) { TRACE; return NULL; } +void __set_current_state(int state) { TRACE; } +int signal_pending(struct task_struct *p) { TRACE; return 0; } +void schedule(void) { TRACE; } +void yield(void) { TRACE; } +void cpu_relax(void) { TRACE; } + +struct task_struct *current; + + +/********************* + ** linux/kthread.h ** + *********************/ + +int kthread_should_stop(void) { SKIP; return 0; } +int kthread_stop(struct task_struct *k) { TRACE; return 0; } + + +/********************** + ** linux/notifier.h ** + **********************/ + +int blocking_notifier_chain_register(struct blocking_notifier_head *nh, + struct notifier_block *nb) { TRACE; return 0; } +int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, + struct notifier_block *nb) { TRACE; return 0; } +int blocking_notifier_call_chain(struct blocking_notifier_head *nh, + unsigned long val, void *v) { TRACE; return 0; } +int atomic_notifier_chain_register(struct atomic_notifier_head *nh, + struct notifier_block *nb) { TRACE; return 0; } +int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, + struct notifier_block *nb) { TRACE; return 0; } + + + +/********************* + ** linux/kobject.h ** + *********************/ + +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { TRACE; return 0; } +char *kobject_name(const struct kobject *kobj) { TRACE; return 0; } +char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) { TRACE; return 0; } + + +/******************* + ** linux/sysfs.h ** + *******************/ + +int sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp) { TRACE; return 0; } +void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp) { TRACE; } + +int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) { TRACE; return 0; } + +ssize_t simple_read_from_buffer(void __user *to, size_t count, + loff_t *ppos, const void *from, size_t available) { TRACE; return 0; } + +/************************ + ** linux/pm_runtime.h ** + ************************/ + +int pm_runtime_set_active(struct device *dev) { TRACE; return 0; } +void pm_suspend_ignore_children(struct device *dev, bool enable) { TRACE; } +void pm_runtime_enable(struct device *dev) { TRACE; } +void pm_runtime_disable(struct device *dev) { TRACE; } +void pm_runtime_set_suspended(struct device *dev) { TRACE; } +void pm_runtime_get_noresume(struct device *dev) { TRACE; } +void pm_runtime_put_noidle(struct device *dev) { TRACE; } +void pm_runtime_use_autosuspend(struct device *dev) { TRACE; } +int pm_runtime_put_sync_autosuspend(struct device *dev) { TRACE; return 0; } +void pm_runtime_no_callbacks(struct device *dev) { TRACE; } + + +/*********************** + ** linux/pm_wakeup.h ** + ***********************/ + +int device_init_wakeup(struct device *dev, bool val) { TRACE; return 0; } +int device_wakeup_enable(struct device *dev) { TRACE; return 0; } +bool device_may_wakeup(struct device *dev) { TRACE; return 0; } +int device_set_wakeup_enable(struct device *dev, bool enable) { TRACE; return 0; } +bool device_can_wakeup(struct device *dev) { TRACE; return 0; } + + +/******************** + ** linux/device.h ** + ********************/ + +int dev_set_name(struct device *dev, const char *name, ...) { TRACE; return 0; } +const char *dev_name(const struct device *dev) { TRACE; return NULL; } +int dev_to_node(struct device *dev) { TRACE; return 0; } +void set_dev_node(struct device *dev, int node) { TRACE; } + +struct device *device_create(struct class *cls, struct device *parent, + dev_t devt, void *drvdata, + const char *fmt, ...) { TRACE; return NULL; } +void device_destroy(struct class *cls, dev_t devt) { TRACE; } +void device_unregister(struct device *dev) { TRACE; } +void device_lock(struct device *dev) { TRACE; } +int device_trylock(struct device *dev) { TRACE; return 0; } +void device_unlock(struct device *dev) { TRACE; } +void device_del(struct device *dev) { TRACE; } +void device_initialize(struct device *dev) { TRACE; } +int device_attach(struct device *dev) { TRACE; return 0; } +int device_is_registered(struct device *dev) { TRACE; return 0; } +int device_bind_driver(struct device *dev) { TRACE; return 0; } +void device_release_driver(struct device *dev) { TRACE; } +void device_enable_async_suspend(struct device *dev) { TRACE; } +void device_set_wakeup_capable(struct device *dev, bool capable) { TRACE; } +int device_create_bin_file(struct device *dev, + const struct bin_attribute *attr) { TRACE; return 0; } +void device_remove_bin_file(struct device *dev, + const struct bin_attribute *attr) { TRACE; } +int device_create_file(struct device *device, + const struct device_attribute *entry) { TRACE; return 0; } +void device_remove_file(struct device *dev, + const struct device_attribute *attr) { TRACE; } + +void put_device(struct device *dev) { TRACE; } + +void driver_unregister(struct device_driver *drv) { TRACE; } +int driver_attach(struct device_driver *drv) { TRACE; return 0; } +int driver_create_file(struct device_driver *driver, + const struct driver_attribute *attr) { TRACE; return 0; } +void driver_remove_file(struct device_driver *driver, + const struct driver_attribute *attr) { TRACE; } + +struct device_driver *get_driver(struct device_driver *drv) { TRACE; return NULL; } +void put_driver(struct device_driver *drv) { TRACE; } + +struct device *bus_find_device(struct bus_type *bus, struct device *start, + void *data, + int (*match)(struct device *dev, void *data)) { TRACE; return NULL; } +int bus_register(struct bus_type *bus) { TRACE; return 0; } +void bus_unregister(struct bus_type *bus) { TRACE; } +int bus_register_notifier(struct bus_type *bus, + struct notifier_block *nb) { TRACE; return 0; } +int bus_unregister_notifier(struct bus_type *bus, + struct notifier_block *nb) { TRACE; return 0; } + +struct class *__class_create(struct module *owner, + const char *name, + struct lock_class_key *key) { TRACE; return NULL; } +int class_register(struct class *cls) { TRACE; return 0; } +void class_unregister(struct class *cls) { TRACE; } +void class_destroy(struct class *cls) { TRACE; } + + +/***************************** + ** linux/platform_device.h ** + *****************************/ + +void *platform_get_drvdata(const struct platform_device *pdev) { TRACE; return NULL; } + + +/******************** + ** linux/dcache.h ** + ********************/ + +void d_instantiate(struct dentry *dentry, struct inode *i) { TRACE; } +int d_unhashed(struct dentry *dentry) { TRACE; return 0; } +void d_delete(struct dentry *d) { TRACE; } +struct dentry *d_alloc_root(struct inode *i) { TRACE; return NULL; } +struct dentry *dget(struct dentry *dentry) { TRACE; return NULL; } +void dput(struct dentry *dentry) { TRACE; } + +void dont_mount(struct dentry *dentry) { TRACE; } + + +/****************** + ** linux/poll.h ** + ******************/ + +void poll_wait(struct file *f, wait_queue_head_t *w, poll_table *p) { TRACE; } + + +/******************** + ** linux/statfs.h ** + ********************/ + +loff_t default_llseek(struct file *file, loff_t offset, int origin) { TRACE; return 0; } + + +/**************** + ** linux/fs.h ** + ****************/ + +unsigned iminor(const struct inode *inode) { TRACE; return 0; } +unsigned imajor(const struct inode *inode) { TRACE; return 0; } + +int register_chrdev_region(dev_t d, unsigned v, const char *s) { TRACE; return 0; } +void unregister_chrdev_region(dev_t d, unsigned v) { TRACE; } +void fops_put(struct file_operations const *fops) { TRACE; } +loff_t noop_llseek(struct file *file, loff_t offset, int origin) { TRACE; return 0; } +int register_chrdev(unsigned int major, const char *name, + const struct file_operations *fops) { TRACE; return 0; } +void unregister_chrdev(unsigned int major, const char *name) { TRACE; } +struct inode *new_inode(struct super_block *sb) { TRACE; return NULL; } +unsigned int get_next_ino(void) { TRACE; return 0; } +void init_special_inode(struct inode *i, umode_t m, dev_t d) { TRACE; } +int generic_delete_inode(struct inode *inode) { TRACE; return 0; } +void drop_nlink(struct inode *inode) { TRACE; } +void inc_nlink(struct inode *inode) { TRACE; } +void dentry_unhash(struct dentry *dentry) { TRACE; } +void iput(struct inode *i) { TRACE; } +struct dentry *mount_single(struct file_system_type *fs_type, + int flags, void *data, + int (*fill_super)(struct super_block *, + void *, int)) { TRACE; return NULL; } +int nonseekable_open(struct inode *inode, struct file *filp) { TRACE; return 0; } +int simple_statfs(struct dentry *d, struct kstatfs *k) { TRACE; return 0; } +int simple_pin_fs(struct file_system_type *t, struct vfsmount **mount, int *count) { TRACE; return 0; } +void simple_release_fs(struct vfsmount **mount, int *count) { TRACE; } +void kill_litter_super(struct super_block *sb) { TRACE; } +int register_filesystem(struct file_system_type *t) { TRACE; return 0; } +int unregister_filesystem(struct file_system_type *t) { TRACE; return 0; } + +void kill_fasync(struct fasync_struct **fp, int sig, int band) { TRACE; } +int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) { TRACE; return 0; } +const struct file_operations simple_dir_operations; +const struct inode_operations simple_dir_inode_operations; + + +/******************* + ** linux/namei.h ** + *******************/ + +struct dentry *lookup_one_len(const char *c, struct dentry *e, int v) { TRACE; return NULL; } + + +/********************** + ** linux/seq_file.h ** + **********************/ + +int seq_printf(struct seq_file *f, const char *fmt, ...) { TRACE; return 0; } + + +/***************** + ** linux/gfp.h ** + *****************/ + +unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) { TRACE; return 0; } +void __free_pages(struct page *p, unsigned int order) { TRACE; } +void free_pages(unsigned long addr, unsigned int order) { TRACE; } + + +/********************* + ** linux/proc_fs.h ** + *********************/ + +struct proc_dir_entry *proc_mkdir(const char *s,struct proc_dir_entry *e) { TRACE; return NULL; } +void remove_proc_entry(const char *name, struct proc_dir_entry *parent) { TRACE; } + + +/******************** + * linux/debugfs.h ** + ********************/ + +struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) { TRACE; return (struct dentry *)1; } +struct dentry *debugfs_create_file(const char *name, mode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops) { TRACE; return (struct dentry *)1; } +void debugfs_remove(struct dentry *dentry) { TRACE; } + + +/************************ + ** linux/page-flags.h ** + ************************/ + +bool is_highmem(void *ptr) { TRACE; return 0; } + + +/**************** + ** linux/mm.h ** + ****************/ + +struct zone *page_zone(const struct page *page) { TRACE; return NULL; } + + +/********************** + ** linux/highmem.h ** + **********************/ + +void *kmap(struct page *page) { TRACE; return 0; } +void kunmap(struct page *page) { TRACE; } + + +/********************** + ** asm-generic/io.h ** + **********************/ + +void *ioremap(resource_size_t offset, unsigned long size) { TRACE; return NULL; } +void iounmap(volatile void *addr) { TRACE; } +void native_io_delay(void) { TRACE; } + + +/******************** + ** linux/ioport.h ** + ********************/ + +void release_region(resource_size_t start, resource_size_t n) { TRACE; } +void release_mem_region(resource_size_t start, resource_size_t n) { TRACE; } + +/** + * SKIP + */ + +/* implemented in Pci_driver */ +struct resource *request_region(resource_size_t start, resource_size_t n, + const char *name) { SKIP; return (struct resource *)1; } +/* implemented in Pci_driver */ +struct resource *request_mem_region(resource_size_t start, resource_size_t n, + const char *name) { SKIP; return (struct resource *)1; } + +/*********************** + ** linux/interrupt.h ** + ***********************/ + +void local_irq_enable(void) { TRACE; } +void local_irq_disable(void) { TRACE; } +void free_irq(unsigned int i, void *p) { TRACE; } + + +/********************* + ** linux/hardirq.h ** + *********************/ + +void synchronize_irq(unsigned int irq) { TRACE; } + + +/***************** + ** linux/pci.h ** + *****************/ +int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 *val) { TRACE; return 0; } +int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) { TRACE; return 0; } + +void *pci_get_drvdata(struct pci_dev *pdev) { TRACE; return NULL; } +void pci_dev_put(struct pci_dev *dev) { TRACE; } +struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, + struct pci_dev *from) { TRACE; return NULL; } + + +void pci_disable_device(struct pci_dev *dev) { TRACE; } +int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) { TRACE; return 0; } + +void pci_unregister_driver(struct pci_driver *drv) { TRACE; } + +bool pci_dev_run_wake(struct pci_dev *dev) { TRACE; return 0; } +int pci_set_mwi(struct pci_dev *dev) { TRACE; return 0; } +int pci_find_capability(struct pci_dev *dev, int cap) { TRACE; return 0; } +struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn) { TRACE; return NULL; } +const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, + struct pci_dev *dev) { TRACE; return 0; } +void *pci_ioremap_bar(struct pci_dev *pdev, int bar); + +/** + * Omitted PCI functions + */ +/* scans resources, this is already implemented in 'pci_driver.cc' */ +int pci_enable_device(struct pci_dev *dev) { SKIP; return 0; } + +/* implemented in Pci_driver::_setup_pci_device */ +void pci_set_master(struct pci_dev *dev) { SKIP; } + +/********************** + ** linux/irqflags.h ** + **********************/ + +unsigned long local_irq_save(unsigned long flags) { SKIP; return 0; } +unsigned long local_irq_restore(unsigned long flags) { SKIP; return 0; } + + +/************************* + ** linux/dma-mapping.h ** + *************************/ + +void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, + size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) { SKIP; } + +void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) { SKIP; } + + +void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) { SKIP;; } + +int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { SKIP; return 0; } + +/***************** + ** linux/pid.h ** + *****************/ + +void put_pid(struct pid *pid) { TRACE; } +struct pid *get_pid(struct pid *pid) { TRACE; return NULL; } + + +/****************** + ** linux/cred.h ** + ******************/ + +void put_cred(struct cred const *c) { TRACE; } +const struct cred *get_cred(const struct cred *cred) { TRACE; return NULL; } + + +/********************** + ** linux/security.h ** + **********************/ + +void security_task_getsecid(struct task_struct *p, u32 *secid) { TRACE; } + + +/****************** + ** linux/cdev.h ** + ******************/ + +void cdev_init(struct cdev *c, const struct file_operations *fops) { TRACE; } +int cdev_add(struct cdev *c, dev_t d, unsigned v) { TRACE; return 0; } +void cdev_del(struct cdev *c) { TRACE; } + + +/********************* + ** linux/utsname.h ** + *********************/ + +struct new_utsname *init_utsname(void) +{ + static struct new_utsname uts = { .sysname = "Genode.UTS", .release = "1.0" }; + return &uts; +} +struct new_utsname *utsname(void) { TRACE; return NULL; } + + +/********************* + ** linux/freezer.h ** + *********************/ + +void set_freezable(void) { TRACE; } + + +/******************** + ** linux/parser.h ** + ********************/ + +int match_token(char *s, const match_table_t table, substring_t args[]) { TRACE; return 0; } +int match_int(substring_t *s, int *result) { TRACE; return 0; } +int match_octal(substring_t *s, int *result) { TRACE; return 0; } + + +/********************* + ** linux/semaphore ** + *********************/ +void sema_init(struct semaphore *sem, int val) { TRACE; } +int down_trylock(struct semaphore *sem) { TRACE; return 0; } +int down_interruptible(struct semaphore *sem) { TRACE; return 0; } +void up(struct semaphore *sem) { TRACE; } + + +/******************* + ** linux/input.h ** + *******************/ + +void input_ff_destroy(struct input_dev *dev) { TRACE; } +int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { TRACE; return 0; } +int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file) { TRACE; return 0; } +int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) { TRACE; return 0; } + +/********************* + ** input-compat.h" ** + *********************/ + +int input_event_from_user(const char __user *buffer, struct input_event *event) { TRACE; return 0; } +int input_event_to_user(char __user *buffer, const struct input_event *event) { TRACE; return 0; } +int input_ff_effect_from_user(const char __user *buffer, size_t size, struct ff_effect *effect) { TRACE; return 0;} + +/**************** + ** linux/mt.h ** + ****************/ + +void input_mt_destroy_slots(struct input_dev *dev) { TRACE; } + + +/********************* + ** linux/vmalloc.h ** + *********************/ + +void *vmalloc(unsigned long size) { TRACE; return 0; } + + +/******************** + ** linux/blkdev.h ** + ********************/ + +void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) { TRACE; } +void blk_queue_update_dma_alignment(struct request_queue *q, int mask) { TRACE; } +void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) { TRACE; } +unsigned int queue_max_hw_sectors(struct request_queue *q) { TRACE; return 0; } + + +/********************** + ** scsi/scsi_cmnd.h ** + **********************/ + +void scsi_set_resid(struct scsi_cmnd *cmd, int resid) { TRACE; } +int scsi_get_resid(struct scsi_cmnd *cmd) { TRACE; return 0; } + + +/******************** + ** scsi/scsi_eh.h ** + *******************/ + +void scsi_report_bus_reset(struct Scsi_Host *shost, int channel) { TRACE; } +void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target) { TRACE; } + +void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, + struct scsi_eh_save *ses, unsigned char *cmnd, + int cmnd_size, unsigned sense_bytes) { TRACE; } + +void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, + struct scsi_eh_save *ses) { TRACE; } + + +int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, + struct scsi_sense_hdr *sshdr) { TRACE; return 0; } + +const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type) { TRACE; return 0; } + + +/*********************** + ** drivers/scsi/sd.h ** + **********************/ + +struct scsi_disk *scsi_disk(struct gendisk *disk) { TRACE; return 0; } + + +/********************** + ** scsi/scsi_host.h ** + **********************/ +int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, + struct device *dma_dev) { TRACE; return 0; } +void scsi_remove_host(struct Scsi_Host *shost) { TRACE; } +void scsi_host_put(struct Scsi_Host *shost) { TRACE; } +struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) { TRACE; return 0; } + + diff --git a/dde_linux/src/drivers/usb/input/evdev.c b/dde_linux/src/drivers/usb/input/evdev.c new file mode 100644 index 000000000..a96cb2923 --- /dev/null +++ b/dde_linux/src/drivers/usb/input/evdev.c @@ -0,0 +1,136 @@ +/* + * \brief Input service and event handler + * \author Christian Helmuth + * \author Dirk Vogt + * \author Sebastian Sumpf + * \date 2009-04-20 + * + * The original implementation was in the L4Env from the TUD:OS group + * (l4/pkg/input/lib/src/l4evdev.c). This file was released under the terms of + * the GNU General Public License version 2. + */ + +/* Linux */ +#include + +/* Local */ +#include + +/* Callback function to Genode subsystem */ +static genode_input_event_cb handler;; + +void genode_evdev_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ +#if DEBUG_EVDEV + static unsigned long count = 0; +#endif + + /* filter sound events */ + if (test_bit(EV_SND, handle->dev->evbit)) return; + + /* filter input_repeat_key() */ + if ((type == EV_KEY) && (value == 2)) return; + + /* filter EV_SYN */ + if (type == EV_SYN) return; + + /* generate arguments and call back */ + enum input_event_type arg_type; + unsigned arg_keycode = KEY_UNKNOWN; + int arg_ax = 0, arg_ay = 0, arg_rx = 0, arg_ry = 0; + + switch (type) { + + case EV_KEY: + arg_keycode = code; + switch (value) { + + case 0: + arg_type = EVENT_TYPE_RELEASE; + break; + + case 1: + arg_type = EVENT_TYPE_PRESS; + break; + + default: + printk("Unknown key event value %d - not handled\n", value); + return; + } + break; + + case EV_ABS: + switch (code) { + + case ABS_X: + arg_type = EVENT_TYPE_MOTION; + arg_ax = value; + break; + + case ABS_Y: + arg_type = EVENT_TYPE_MOTION; + arg_ay = value; + break; + + case ABS_WHEEL: + /* + * XXX I do not know, how to handle this correctly. At least, this + * scheme works on Qemu. + */ + arg_type = EVENT_TYPE_WHEEL; + arg_ry = value; + break; + + default: + printk("Unknown absolute event code %d - not handled\n", code); + return; + } + break; + + case EV_REL: + switch (code) { + + case REL_X: + arg_type = EVENT_TYPE_MOTION; + arg_rx = value; + break; + + case REL_Y: + arg_type = EVENT_TYPE_MOTION; + arg_ry = value; + break; + + case REL_HWHEEL: + arg_type = EVENT_TYPE_WHEEL; + arg_rx = value; + break; + + case REL_WHEEL: + arg_type = EVENT_TYPE_WHEEL; + arg_ry = value; + break; + + default: + printk("Unknown relative event code %d - not handled\n", code); + return; + } + break; + + default: + printk("Unknown event type %d - not handled\n", type); + return; + } + + if (handler) + handler(arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry); + printk("EVENT: t: %x c: %x ax: %d ay %d rx: %d ry %d\n", + arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry); +#if DEBUG_EVDEV + printk("event[%ld]. dev: %s, type: %d, code: %d, value: %d\n", + count++, handle->dev->name, type, code, value); +#endif +} + +void genode_input_register(genode_input_event_cb h) { handler = h; } + diff --git a/dde_linux/src/drivers/usb/input/input_component.cc b/dde_linux/src/drivers/usb/input/input_component.cc new file mode 100644 index 000000000..2568ea1dc --- /dev/null +++ b/dde_linux/src/drivers/usb/input/input_component.cc @@ -0,0 +1,77 @@ +/* + * \brief Linux 2.6 Input driver for USB HID + * \author Christian Helmuth + * \author Christian Prochaska + * \author Sebastian Sumpf + * \date 2011-07-15 + */ + +/* + * Copyright (C) 2011-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. + */ + +#include +#include +#include +#include + +#include + +#undef RELEASE + +using namespace Genode; + + +/********************* + ** Input component ** + *********************/ + +typedef Ring_buffer Input_ring_buffer; + +static Input_ring_buffer ev_queue; + +namespace Input { + + void event_handling(bool enable) { } + bool event_pending() { return !ev_queue.empty(); } + Event get_event() { return ev_queue.get(); } +} + + +/** + * Input event call-back function + */ +static void input_callback(enum input_event_type type, + unsigned keycode, + int absolute_x, int absolute_y, + int relative_x, int relative_y) +{ + Input::Event::Type t = Input::Event::INVALID; + switch (type) { + case EVENT_TYPE_PRESS: t = Input::Event::PRESS; break; + case EVENT_TYPE_RELEASE: t = Input::Event::RELEASE; break; + case EVENT_TYPE_MOTION: t = Input::Event::MOTION; break; + case EVENT_TYPE_WHEEL: t = Input::Event::WHEEL; break; + } + + try { + ev_queue.add(Input::Event(t, keycode, + absolute_x, absolute_y, + relative_x, relative_y)); + } catch (Input_ring_buffer::Overflow) { + PWRN("input ring buffer overflow"); + } +} + + +void start_input_service(void *ep) +{ + Rpc_entrypoint *e = static_cast(ep); + static Input::Root input_root(e, env()->heap()); + env()->parent()->announce(e->manage(&input_root)); + + genode_input_register(input_callback); +} diff --git a/dde_linux/src/drivers/usb/lx_emul.cc b/dde_linux/src/drivers/usb/lx_emul.cc new file mode 100644 index 000000000..a8d4a2755 --- /dev/null +++ b/dde_linux/src/drivers/usb/lx_emul.cc @@ -0,0 +1,770 @@ +/* + * \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 +#include +#include +#include +#include + +/* Local includes */ +#include "routine.h" +#include "signal.h" +#include "lx_emul.h" + +/* DDE kit includes */ +extern "C" { +#include +#include +#include +#include +#include +#include +} + + +#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::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 *list() + { + static Genode::List _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); +} diff --git a/dde_linux/src/drivers/usb/lx_emul.h b/dde_linux/src/drivers/usb/lx_emul.h new file mode 100644 index 000000000..cecc5a4eb --- /dev/null +++ b/dde_linux/src/drivers/usb/lx_emul.h @@ -0,0 +1,2647 @@ +/* + * \brief Emulation of the Linux kernel API + * \author Norman Feske + * \author Sebastian Sumpf + * \date 2012-01-28 + * + * The content of this file, in particular data structures, is partially + * derived from Linux-internal headers. + */ + +/* + * 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. + */ + +#ifndef _LX_EMUL_H_ +#define _LX_EMUL_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* DDE Kit includes */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VERBOSE_LX_EMUL 0 + + +#if VERBOSE_LX_EMUL +#define DEBUG_COMPLETION 1 +#define DEBUG_DMA 0 +#define DEBUG_DRIVER 1 +#define DEBUG_IRQ 1 +#define DEBUG_KREF 0 +#define DEBUG_PCI 1 +#define DEBUG_SLAB 0 +#define DEBUG_TIMER 1 +#define DEBUG_THREAD 1 +#else +#define DEBUG_COMPLETION 0 +#define DEBUG_DRIVER 0 +#define DEBUG_DMA 0 +#define DEBUG_IRQ 0 +#define DEBUG_KREF 0 +#define DEBUG_SLAB 0 +#define DEBUG_PCI 0 +#define DEBUG_TIMER 0 +#define DEBUG_THREAD 0 +#endif + +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#define LINUX_VERSION_CODE KERNEL_VERSION(3,2,2) + +#define KBUILD_MODNAME "mod-noname" + +/*************** + ** asm/bug.h ** + ***************/ + +#define WARN_ON(condition) ({ \ + int ret = !!(condition); \ + if (ret) dde_kit_debug("[%s] WARN_ON(" #condition ") ", __func__); \ + ret; }) + +#define WARN(condition, fmt, arg...) ({ \ + int ret = !!(condition); \ + if (ret) dde_kit_debug("[%s] *WARN* " fmt , __func__ , ##arg); \ + ret; }) + +#define BUG() do { \ + dde_kit_debug("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + while (1); \ +} while (0) + +#define WARN_ON_ONCE WARN_ON +#define WARN_ONCE WARN + +#define BUG_ON(condition) do { if (condition) BUG(); } while(0) + + +/***************** + ** asm/param.h ** + *****************/ + +enum { HZ = 100UL }; + + +/******************* + ** linux/magic.h ** + *******************/ + +enum { USBDEVICE_SUPER_MAGIC = 0x9fa2 }; + + +/****************** + ** asm/atomic.h ** + ******************/ + +typedef struct atomic { unsigned int v; } atomic_t; + +void atomic_set(atomic_t *p, unsigned int v); +unsigned int atomic_read(atomic_t *p); + +void atomic_inc(atomic_t *v); +void atomic_dec(atomic_t *v); + +void atomic_add(int i, atomic_t *v); +void atomic_sub(int i, atomic_t *v); +int atomic_inc_return(atomic_t *v); + +#define ATOMIC_INIT(i) { (i) } + + +/******************* + ** linux/types.h ** + *******************/ + +typedef dde_kit_int8_t int8_t; +typedef dde_kit_uint8_t uint8_t; +typedef dde_kit_int16_t int16_t; +typedef dde_kit_uint16_t uint16_t; +typedef dde_kit_int32_t int32_t; +typedef dde_kit_uint32_t uint32_t; +typedef dde_kit_size_t size_t; +typedef dde_kit_int64_t int64_t; +typedef dde_kit_uint64_t uint64_t; + +typedef uint32_t uint; + +typedef int8_t s8; +typedef uint8_t u8; +typedef int16_t s16; +typedef uint16_t u16; +typedef int32_t s32; +typedef uint32_t u32; +typedef int64_t s64; +typedef uint64_t u64; + +typedef int8_t __s8; +typedef uint8_t __u8; +typedef int16_t __s16; +typedef uint16_t __u16; +typedef int32_t __s32; +typedef uint32_t __u32; +typedef int64_t __s64; +typedef uint64_t __u64; + +typedef __u16 __le16; +typedef __u32 __le32; +typedef __u64 __le64; +typedef __u16 __be16; +typedef __u32 __be32; +typedef __u64 __be64; + +typedef u64 sector_t; + +struct list_head { + struct list_head *next, *prev; +}; + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#ifndef __cplusplus +typedef int bool; +enum { true = 1, false = 0 }; +#endif /* __cplusplus */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif /* __cplusplus */ +#endif /* NULL */ + +typedef unsigned gfp_t; +typedef unsigned long pgoff_t; +typedef long long loff_t; +typedef long ssize_t; +typedef unsigned long uintptr_t; +typedef int dev_t; +typedef size_t resource_size_t; +typedef long off_t; +typedef int pid_t; +typedef unsigned fmode_t; +typedef u32 uid_t; +typedef u32 gid_t; +typedef long __kernel_time_t; +typedef unsigned short umode_t; +typedef __u16 __be16; +typedef __u32 __be32; + +#ifndef __cplusplus +typedef u16 wchar_t; +#endif + +/* + * needed by usb.h + */ +typedef unsigned long dma_addr_t; + +/* + * XXX 'mode_t' is 'unsigned int' on x86_64 + */ +typedef unsigned short mode_t; + + +/****************** + ** asm/system.h ** + ******************/ + +#define mb() asm volatile ("": : :"memory") +#define rmb() mb() +#define wmb() asm volatile ("": : :"memory") +#define smp_wmb() wmb() + +static inline void barrier() { mb(); } + + +/********************** + ** linux/compiler.h ** + **********************/ + +#define likely +#define unlikely + +#define __user /* needed by usb/core/devices.c */ +#define __iomem /* needed by usb/hcd.h */ + +#define __releases(x) /* needed by usb/core/devio.c */ +#define __acquires(x) /* needed by usb/core/devio.c */ +#define __force +#define __maybe_unused +#define __bitwise + +#define __rcu +#define __must_check + +#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#define __attribute_const__ + +#undef __always_inline +#define __always_inline + +#undef __unused + + +/*********************** + ** linux/irqreturn.h ** + ***********************/ + +enum irqreturn { + IRQ_NONE, + IRQ_HANDLED = (1 << 0), +}; + +typedef enum irqreturn irqreturn_t; + + +/************************************* + ** linux/byteorder/little_endian.h ** + *************************************/ + +#include + + +/******************************* + ** linux/byteorder/generic.h ** + *******************************/ + +#define le16_to_cpu __le16_to_cpu +#define be16_to_cpu __be16_to_cpu +#define le32_to_cpu __le32_to_cpu +#define be32_to_cpu __be32_to_cpu +#define le16_to_cpus __le16_to_cpus +#define cpu_to_le16p __cpu_to_le16p +#define cpu_to_be16p __cpu_to_be16p +#define cpu_to_le16 __cpu_to_le16 +#define cpu_to_be16 __cpu_to_be16 +#define cpu_to_le32 __cpu_to_le32 +#define cpu_to_be32 __cpu_to_be32 +#define le16_to_cpup __le16_to_cpup +#define be16_to_cpup __be16_to_cpup +#define le32_to_cpup __le32_to_cpup +#define be32_to_cpup __be32_to_cpup + + +struct __una_u32 { u32 x; } __attribute__((packed)); +struct __una_u64 { u64 x; } __attribute__((packed)); + +u16 get_unaligned_le16(const void *p); + +void put_unaligned_le32(u32 val, void *p); +u32 get_unaligned_le32(const void *p); + +void put_unaligned_le64(u64 val, void *p); +u64 get_unaligned_le64(const void *p); + +#define put_unaligned put_unaligned_le32 +#define get_unaligned get_unaligned_le32 + + +/**************** + ** asm/page.h ** + ****************/ + +/* + * For now, hardcoded to x86_32 + */ +enum { + PAGE_SIZE = 4096, + PAGE_SHIFT = 12, +}; + +struct page +{ + void *virt; + dma_addr_t phys; +}; + + +/******************** + ** linux/poison.h ** + ********************/ + +/* + * In list.h, LIST_POISON1 and LIST_POISON2 are assigned to 'struct list_head + * *' as well as 'struct hlist_node *' pointers. Consequently, C++ compiler + * produces an error "cannot convert... in assignment". To compile 'list.h' + * included by C++ source code, we have to define these macros to the only + * value universally accepted for pointer assigments.h + */ + +#ifdef __cplusplus +#define LIST_POISON1 0 +#define LIST_POISON2 0 +#else +#define LIST_POISON1 ((void *)0x00100100) +#define LIST_POISON2 ((void *)0x00200200) +#endif /* __cplusplus */ + + +/******************************* + ** linux/errno.h and friends ** + *******************************/ + +/** + * Error codes + * + * Note that the codes do not correspond to those of the Linux kernel. + */ +enum { + EINVAL = 1, + ENODEV = 2, + ENOMEM = 3, + EFAULT = 4, + EBADF = 5, + EAGAIN = 6, + ERESTARTSYS = 7, + ENOSPC = 8, + EIO = 9, + EBUSY = 10, + EPERM = 11, + EINTR = 12, + ENOMSG = 13, + ECONNRESET = 14, + ENOENT = 15, + EHOSTUNREACH = 16, + ESRCH = 17, + EPIPE = 18, + ENODATA = 19, + EREMOTEIO = 20, + ENOTTY = 21, + ENOIOCTLCMD = 22, + EADDRINUSE = 23, + ENFILE = 23, + EXFULL = 24, + EIDRM = 25, + ESHUTDOWN = 26, + EMSGSIZE = 27, + E2BIG = 28, + EINPROGRESS = 29, + ESPIPE = 29, + ETIMEDOUT = 30, + ENOSYS = 31, + ENOTCONN = 32, + EPROTO = 33, + ENOTSUPP = 34, + EISDIR = 35, + EEXIST = 36, + ENOTEMPTY = 37, + ENXIO = 38, + ENOEXEC = 39, + EXDEV = 40, + EOVERFLOW = 41, + ENOSR = 42, + ECOMM = 43, + EFBIG = 44, + EILSEQ = 45, + ETIME = 46, + EALREADY = 47, + EOPNOTSUPP = 48, +}; + +static inline bool IS_ERR(void *ptr) { + return (unsigned long)(ptr) > (unsigned long)(-1000); } + +long PTR_ERR(const void *ptr); + + +/******************* + ** linux/major.h ** + *******************/ + +enum { + INPUT_MAJOR = 13 +}; + +/******************** + ** linux/kernel.h ** + ********************/ + +/* + * Log tags + */ +#define KERN_DEBUG "DEBUG: " +#define KERN_ERR "ERROR: " +#define KERN_INFO "INFO: " +#define KERN_NOTICE "NOTICE: " + +/* + * Debug macros + */ +#if VERBOSE_LX_EMUL +#define printk dde_kit_printf +#define vprintk dde_kit_vprintf +#define panic dde_kit_panic +#else /* VERBOSE_LX_EMUL */ +#define printk(...) +#define vprintk(...) +#define panic(...) +#endif /* VERBOSE_LX_EMUL */ + +/* + * Bits and types + */ + +/* needed by linux/list.h */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* normally provided by linux/stddef.h, needed by linux/list.h */ +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1: __max2; }) + +/** + * Return minimum of two given values + * + * XXX check how this function is used (argument types) + */ +static inline size_t min(size_t a, size_t b) { + return a < b ? a : b; } + +/** + * Return maximum of two given values + * + * XXX check how this function is used (argument types) + */ +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#define abs(x) ( { \ + typeof (x) _x = (x); \ + _x < 0 ? -_x : _x; }) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +void might_sleep(); + +#define INT_MAX ((int)(~0U>>1)) + +char *kasprintf(gfp_t gfp, const char *fmt, ...); +int kstrtouint(const char *s, unsigned int base, unsigned int *res); + +#define clamp(val, min, max) ({ \ + typeof(val) __val = (val); \ + typeof(min) __min = (min); \ + typeof(max) __max = (max); \ + (void) (&__val == &__min); \ + (void) (&__val == &__max); \ + __val = __val < __min ? __min: __val; \ + __val > __max ? __max: __val; }) + +int strict_strtoul(const char *s, unsigned int base, unsigned long *res); +long simple_strtoul(const char *cp, char **endp, unsigned int base); + + +/* + * Needed by 'usb.h' + */ +int snprintf(char *buf, size_t size, const char *fmt, ...); +int sprintf(char *buf, const char *fmt, ...); +int sscanf(const char *, const char *, ...); +int scnprintf(char *buf, size_t size, const char *fmt, ...); + +struct completion; +void complete_and_exit(struct completion *, long); + +/****************** + ** linux/log2.h ** + ******************/ + +int ilog2(u32 n); +int roundup_pow_of_two(u32 n); + + +/******************** + ** linux/kdev_t.h ** + ********************/ + +#define MINORBITS 20 +#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) + + +/******************** + ** linux/printk.h ** + ********************/ + +enum { DUMP_PREFIX_NONE }; + +void print_hex_dump(const char *level, const char *prefix_str, + int prefix_type, int rowsize, int groupsize, + const void *buf, size_t len, bool ascii); + +#define KERN_WARNING "<4>" +#define pr_info(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__) +#define pr_err(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__) +#define pr_debug(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__) +#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__) +#define pr_warn pr_warning + +#define printk_ratelimit() \ + ({ dde_kit_debug("printk_ratelimit called - not implemented\n"); (0); }) + +static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msec) { + return false; } + + +/********************************** + ** linux/bitops.h, asm/bitops.h ** + **********************************/ + +#include + +#define BIT(nr) (1UL << (nr)) +#define BITS_PER_LONG (sizeof(long) * 8) + +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) + +#include + +#define test_and_clear_bit(nr, addr) \ + __test_and_clear_bit(nr, (volatile unsigned long *)(addr)) +#define test_and_set_bit(nr, addr) \ + __test_and_set_bit(nr, (volatile unsigned long *)(addr)) +#define set_bit(nr, addr) \ + __set_bit(nr, (volatile unsigned long *)(addr)) +#define clear_bit(nr, addr) \ + __clear_bit(nr, (volatile unsigned long *)(addr)) + +/** + * Find first zero bit (limit to machine word size) + */ +long find_next_zero_bit_le(const void *addr, + unsigned long size, unsigned long offset); + +#define find_next_zero_bit find_next_zero_bit_le + +/* normally declared in asm-generic/bitops/ffs.h */ +int ffs(int x); +int fls(int x); + + +/******************** + ** linux/string.h ** + ********************/ + +#ifndef __cplusplus +void *memcpy(void *dest, const void *src, size_t n); +#endif + +void *memset(void *s, int c, size_t n); +int memcmp(const void *, const void *, size_t); +void *memscan(void *addr, int c, size_t size); +char *strcat(char *dest, const char *src); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *cs, const char *ct, size_t count); +char *strncpy(char *, const char *, size_t); +char *strchr(const char *, int); +char *strrchr(const char *,int); +size_t strlcat(char *dest, const char *src, size_t n); +size_t strlcpy(char *dest, const char *src, size_t size); +size_t strlen(const char *); +char * strsep(char **,const char *); +char *strstr(const char *, const char *); +char *kstrdup(const char *s, gfp_t gfp); +void *kmemdup(const void *src, size_t len, gfp_t gfp); + + +/***************** + ** linux/nls.h ** + *****************/ + +enum utf16_endian { UTF16_LITTLE_ENDIAN = 1, }; + +int utf16s_to_utf8s(const wchar_t *pwcs, int len, + enum utf16_endian endian, u8 *s, int maxlen); + + +/******************* + ** linux/ctype.h ** + *******************/ + +int isprint(int); + + +/****************** + ** linux/init.h ** + ******************/ + +#define __init +#define __devinit +#define __devinitconst +#define __exit + +#define subsys_initcall(fn) void subsys_##fn(void) { fn(); } + + +/******************** + ** linux/module.h ** + ********************/ + +#define EXPORT_SYMBOL(x) +#define EXPORT_SYMBOL_GPL(x) +#define MODULE_AUTHOR(x) +#define MODULE_DESCRIPTION(x) +#define MODULE_LICENSE(x) +#define MODULE_PARM_DESC(x, y) +//#define MODULE_ALIAS_MISCDEV(x) /* needed by agp/backend.c */ + +#define THIS_MODULE 0 + +#define MODULE_DEVICE_TABLE(type, name) + +struct module; +#define _MOD_CONCAT(a,b) module_##a##b +#define MOD_CONCAT(a,b) _MOD_CONCAT(a,b) +#define module_init(fn) void MOD_CONCAT(fn, MOD_SUFFIX)(void) { fn(); } +#define module_exit(exit_fn) void MOD_CONCAT(exit_fn, MOD_SUFFIX)(void) { exit_fn(); } + +static inline void module_put(struct module *module) { } +static inline void __module_get(struct module *module) { } + +/************************* + ** linux/moduleparam.h ** + *************************/ + +#define module_param(name, type, perm) +#define module_param_named(name, value, type, perm) +#define module_param_array_named(name, array, type, nump, perm) +#define module_param_string(name, string, len, perm) +#define core_param(name, var, type, perm) + + +/****************** + ** linux/slab.h ** + ******************/ + +enum { + SLAB_HWCACHE_ALIGN = 0x00002000UL, + SLAB_CACHE_DMA = 0x00004000UL, +}; + +void *kzalloc(size_t size, gfp_t flags); +void kfree(const void *); +void *kmalloc(size_t size, gfp_t flags); +void *kcalloc(size_t n, size_t size, gfp_t flags); + +struct kmem_cache; + +/** + * Create slab cache using DDE kit + */ +struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, + unsigned long, void (*)(void *)); + +/** + * Destroy slab cache using DDE kit + */ +void kmem_cache_destroy(struct kmem_cache *); + +/** + * Allocate and zero slab + */ +void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags); + +/** + * Free slab + */ +void kmem_cache_free(struct kmem_cache *, void *); + + +/********************** + ** linux/spinlock.h ** + **********************/ + +typedef dde_kit_spin_lock spinlock_t; +#define DEFINE_SPINLOCK(name) spinlock_t name = 0; + +void spin_lock(spinlock_t *lock); +void spin_lock_nested(spinlock_t *lock, int subclass); +void spin_unlock(spinlock_t *lock); +void spin_lock_init(spinlock_t *lock); +void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); +void spin_lock_irqrestore(spinlock_t *lock, unsigned long flags); +void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); +void spin_lock_irq(spinlock_t *lock); +void spin_unlock_irq(spinlock_t *lock); +void assert_spin_locked(spinlock_t *lock); + + +/******************* + ** linux/mutex.h ** + *******************/ + +struct mutex { struct dde_kit_lock *lock; }; + +void mutex_init(struct mutex *m); +void mutex_lock(struct mutex *m); +void mutex_lock_nested(struct mutex *lock, unsigned int subclass); +void mutex_unlock(struct mutex *m); +int mutex_lock_interruptible(struct mutex *m); + +#define DEFINE_MUTEX(mutexname) struct mutex mutexname = { NULL }; + + +/******************* + ** linux/rwsem.h ** + *******************/ + +struct rw_semaphore { int dummy; }; + +#define DECLARE_RWSEM(name) \ + struct rw_semaphore name = { 0 }; + +void down_read(struct rw_semaphore *sem); +void up_read(struct rw_semaphore *sem); +void down_write(struct rw_semaphore *sem); +void up_write(struct rw_semaphore *sem); + +#define __RWSEM_INITIALIZER(name) { 0 } + + +/********************* + ** linux/jiffies.h ** + *********************/ + +/* + * XXX check how the jiffies variable is used + */ +extern volatile unsigned long jiffies; +unsigned long msecs_to_jiffies(const unsigned int m); +long time_after(long a, long b); +long time_after_eq(long a, long b); + + +/******************* + ** linux/ktime.h ** + *******************/ + +union ktime { s64 tv64; }; + +typedef union ktime ktime_t; + +ktime_t ktime_add_ns(const ktime_t kt, u64 nsec); + +static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec) +{ + return ktime_add_ns(kt, usec * 1000); +} + +s64 ktime_us_delta(const ktime_t later, const ktime_t earlier); + + +/******************* + ** linux/timer.h ** + *******************/ + +struct timer_list { + void (*function)(unsigned long); + unsigned long data; + void *timer; +}; + +void init_timer(struct timer_list *); +int mod_timer(struct timer_list *timer, unsigned long expires); +int del_timer(struct timer_list * timer); +int del_timer_sync(struct timer_list * timer); +void setup_timer(struct timer_list *timer,void (*function)(unsigned long), + unsigned long data); +int timer_pending(const struct timer_list * timer); +unsigned long round_jiffies(unsigned long j); + + +/********************* + ** linux/hrtimer.h ** + *********************/ + +ktime_t ktime_get_real(void); + + +/******************* + ** linux/delay.h ** + *******************/ + +void msleep(unsigned int msecs); +void udelay(unsigned long usecs); +void mdelay(unsigned long usecs); + + +/*********************** + ** linux/workquque.h ** + ***********************/ + +struct work_struct; +typedef void (*work_func_t)(struct work_struct *work); + +struct work_struct { + work_func_t func; + struct list_head entry; +}; + +struct delayed_work { + struct timer_list timer; + struct work_struct work; +}; + +bool cancel_work_sync(struct work_struct *work); +int cancel_delayed_work_sync(struct delayed_work *work); +int schedule_delayed_work(struct delayed_work *work, unsigned long delay); +int schedule_work(struct work_struct *work); +bool flush_work_sync(struct work_struct *work); + + +#define PREPARE_WORK(_work, _func) \ + do { (_work)->func = (_func); } while (0) + +#define PREPARE_DELAYED_WORK(_work, _func) \ + PREPARE_WORK(&(_work)->work, (_func)) + +#define __INIT_WORK(_work, _func, on_stack) \ + do { \ + INIT_LIST_HEAD(&(_work)->entry); \ + PREPARE_WORK((_work), (_func)); \ + } while (0) + +#define INIT_WORK(_work, _func)\ + do { __INIT_WORK((_work), (_func), 0); } while (0) + +#define INIT_DELAYED_WORK(_work, _func) \ + do { \ + INIT_WORK(&(_work)->work, (_func)); \ + init_timer(&(_work)->timer); \ + } while (0) + + +/****************** + ** linux/wait.h ** + ******************/ + +typedef struct wait_queue_head { int dummy; } wait_queue_head_t; + +void init_waitqueue_head(wait_queue_head_t *q); + +#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 } + +typedef struct wait_queue { int dummy; } wait_queue_t; + +#define __WAIT_QUEUE_INITIALIZER(name, tsk) { 0 } + +#define DECLARE_WAITQUEUE(name, tsk) \ + wait_queue_t name = __WAIT_QUEUE_INITIALIZER(name, tsk) + +#define DECLARE_WAIT_QUEUE_HEAD(name) \ + wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) + +void __wake_up(); +void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); +void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); + +#define wake_up(x) __wake_up() +#define wake_up_all(x) __wake_up() +#define wake_up_interruptible(x) __wake_up() + +extern wait_queue_t wait; +void breakpoint(); + +/* our wait event implementation */ +void __wait_event(void); + +#define wait_event(wq, condition) \ + ({ dde_kit_printf("wait_event, not yet implemented\n"); 0; }) + +#define _wait_event(condition) \ + while(!(condition)) { \ + __wait_event(); \ + if (!(condition)) \ + msleep(1); \ + } \ + +#define _wait_event_timeout(condition, timeout) \ +({ \ + unsigned long _j = jiffies + (timeout / HZ); \ + while(1) { \ + __wait_event(); \ + if (condition || _j <= jiffies) \ + break; \ + msleep(1); \ + } \ +}) + +#define wait_event_interruptible(wq, condition) \ +({ \ + _wait_event(condition); \ + 0; \ +}) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + _wait_event_timeout(condition, timeout); \ + 1; \ +}) + +#define wait_event_timeout(wq, condition, timeout) \ +({ \ + _wait_event_timeout(condition, timeout); \ + 1; \ +}) + + +/****************** + ** linux/time.h ** + ******************/ + +struct timespec { + __kernel_time_t tv_sec; + long tv_nsec; +}; + +struct timeval { }; +struct timespec current_kernel_time(void); +void do_gettimeofday(struct timeval *tv); + +#define CURRENT_TIME (current_kernel_time()) + + +/******************* + ** linux/sched.h ** + *******************/ + +enum { TASK_RUNNING = 0, TASK_INTERRUPTIBLE = 1, TASK_NORMAL = 3 }; + +enum { MAX_SCHEDULE_TIMEOUT = (~0U >> 1) }; + +struct task_struct { + char comm[16]; /* needed by usb/core/devio.c, only for debug output */ +}; + +struct cred; +struct siginfo; +struct pid; + +int kill_pid_info_as_cred(int, struct siginfo *, struct pid *, + const struct cred *, u32); +pid_t task_pid_nr(struct task_struct *tsk); + +struct pid *task_pid(struct task_struct *task); + +void __set_current_state(int state); +#define set_current_state(state) __set_current_state(state) +int signal_pending(struct task_struct *p); +void schedule(void); +signed long schedule_timeout_uninterruptible(signed long timeout); +void yield(void); +int wake_up_process(struct task_struct *tsk); + +/* normally defined in asm/current.h, included by sched.h */ +extern struct task_struct *current; + +/* asm/processor.h */ +void cpu_relax(void); + + +/********************* + ** linux/kthread.h ** + *********************/ + +int kthread_should_stop(void); +int kthread_stop(struct task_struct *k); + +struct task_struct *kthread_run(int (*)(void *), void *, const char *, ...); + +struct task_struct *kthread_create(int (*threadfn)(void *data), + void *data, + const char namefmt[], ...); + + +/********************** + ** linux/notifier.h ** + **********************/ + +enum { + NOTIFY_DONE = 0x0000, + NOTIFY_OK = 0x0001, + NOTIFY_STOP_MASK = 0x8000, + NOTIFY_BAD = (NOTIFY_STOP_MASK | 0x0002), +}; + +struct notifier_block { + int (*notifier_call)(struct notifier_block *, unsigned long, void *); +}; + +struct atomic_notifier_head { + spinlock_t lock; + struct notifier_block *head; +}; + +struct blocking_notifier_head { + struct rw_semaphore rwsem; + struct notifier_block *head; +}; + +#define BLOCKING_NOTIFIER_INIT(name) { \ + .rwsem = __RWSEM_INITIALIZER((name).rwsem), .head = NULL } +#define BLOCKING_NOTIFIER_HEAD(name) \ + struct blocking_notifier_head name = BLOCKING_NOTIFIER_INIT(name) + +int blocking_notifier_chain_register(struct blocking_notifier_head *nh, + struct notifier_block *nb); +int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, + struct notifier_block *nb); +int blocking_notifier_call_chain(struct blocking_notifier_head *nh, + unsigned long val, void *v); +int atomic_notifier_chain_register(struct atomic_notifier_head *nh, + struct notifier_block *nb); +int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, + struct notifier_block *nb); + + +/************************* + ** linux/scatterlist.h ** + *************************/ + +struct scatterlist { + unsigned long page_link; + unsigned int offset; + unsigned int length; + dma_addr_t dma_address; + int last; +}; + +struct sg_table +{ + struct scatterlist *sgl; /* the list */ + unsigned int nents; /* number of mapped entries */ +}; + +struct page *sg_page(struct scatterlist *sg); +void *sg_virt(struct scatterlist *sg); +struct scatterlist *sg_next(struct scatterlist *); + +size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen); +size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen); + +#define for_each_sg(sglist, sg, nr, __i) \ + for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) + +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->length) + + +/****************** + ** linux/kref.h ** + ******************/ + +struct kref { atomic_t refcount; }; + +void kref_init(struct kref *kref); +void kref_get(struct kref *kref); +int kref_put(struct kref *kref, void (*release) (struct kref *kref)); + + +/********************* + ** linux/kobject.h ** + *********************/ + +struct kobject { int dummy; }; +struct kobj_uevent_env +{ + char buf[32]; + int buflen; +}; + +struct kobj_uevent_env; + +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); +char *kobject_name(const struct kobject *kobj); +char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask); + + +/******************* + ** linux/sysfs.h ** + *******************/ + +struct attribute { + const char *name; + mode_t mode; +}; + +struct attribute_group { + const char *name; + mode_t (*is_visible)(struct kobject *, struct attribute *, int); + struct attribute **attrs; +}; + +struct file; +struct bin_attribute { + struct attribute attr; + size_t size; + ssize_t (*read)(struct file *, struct kobject *, + struct bin_attribute *, char *, loff_t, size_t); +}; + +#define __ATTR(_name,_mode,_show,_store) { \ + .attr = {.name = #_name, .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +} + +int sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp); +void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp); + + +/**************** + ** linux/pm.h ** + ****************/ + +typedef struct pm_message { int event; } pm_message_t; + +struct dev_pm_info { bool is_prepared; }; + + +/************************ + ** linux/pm_runtime.h ** + ************************/ + +struct device; + +int pm_runtime_set_active(struct device *dev); +void pm_suspend_ignore_children(struct device *dev, bool enable); +void pm_runtime_enable(struct device *dev); +void pm_runtime_disable(struct device *dev); +void pm_runtime_set_suspended(struct device *dev); +void pm_runtime_get_noresume(struct device *dev); +void pm_runtime_put_noidle(struct device *dev); +void pm_runtime_use_autosuspend(struct device *dev); +int pm_runtime_put_sync_autosuspend(struct device *dev); +void pm_runtime_no_callbacks(struct device *dev); + + +/*********************** + ** linux/pm_wakeup.h ** + ***********************/ + +int device_init_wakeup(struct device *dev, bool val); +int device_wakeup_enable(struct device *dev); +bool device_may_wakeup(struct device *dev); +int device_set_wakeup_enable(struct device *dev, bool enable); +bool device_can_wakeup(struct device *dev); + + +/******************** + ** linux/device.h ** + ********************/ + +#ifdef __cplusplus +#define class device_class +#endif + + +#define dev_info(dev, format, arg...) dde_kit_printf("dev_info: " format, ## arg) +#define dev_warn(dev, format, arg...) dde_kit_printf("dev_warn: " format, ## arg) +#define dev_WARN(dev, format, arg...) dde_kit_printf("dev_WARN: " format, ## arg) +#define dev_err( dev, format, arg...) dde_kit_printf("dev_error: " format, ## arg) +#define dev_notice(dev, format, arg...) dde_kit_printf("dev_notice: " format, ## arg) +#define dev_dbg( dev, format, arg...) + +#define dev_printk(level, dev, format, arg...) \ + dde_kit_printf("dev_printk: " format, ## arg) + +enum { + BUS_NOTIFY_ADD_DEVICE = 0x00000001, + BUS_NOTIFY_DEL_DEVICE = 0x00000002, +}; + +struct device_driver; + +struct bus_type { + const char *name; + int (*match)(struct device *dev, struct device_driver *drv); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*probe)(struct device *dev); + int (*remove)(struct device *dev); +}; + +struct device_driver { + char const *name; + struct bus_type *bus; + struct module *owner; + const char *mod_name; + int (*probe) (struct device *dev); + int (*remove) (struct device *dev); +}; + +struct kobj_uevent_env; + +struct device_type { + const char *name; + const struct attribute_group **groups; + void (*release)(struct device *dev); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + char *(*devnode)(struct device *dev, mode_t *mode); +}; + +struct class +{ + const char *name; + char *(*devnode)(struct device *dev, mode_t *mode); +}; + +struct device { + struct device *parent; + struct kobject kobj; + const struct device_type *type; + struct device_driver *driver; + u64 *dma_mask; /* needed by usb/hcd.h */ + struct dev_pm_info power; + dev_t devt; + const struct attribute_group **groups; + void (*release)(struct device *dev); + struct bus_type *bus; + struct class *class; + void *driver_data; +}; + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *dev, struct device_attribute *attr, + char *buf); + ssize_t (*store)(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +}; + +struct driver_attribute { + struct attribute attr; + ssize_t (*show)(struct device_driver *driver, char *buf); + ssize_t (*store)(struct device_driver *driver, const char *buf, + size_t count); +}; + +struct lock_class_key { int dummy; }; + +#define DEVICE_ATTR(_name, _mode, _show, _store) \ +struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) + +#define DRIVER_ATTR(_name, _mode, _show, _store) \ +struct driver_attribute driver_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +void *dev_get_drvdata(const struct device *dev); +int dev_set_drvdata(struct device *dev, void *data); +int dev_set_name(struct device *dev, const char *name, ...); +const char *dev_name(const struct device *dev); +int dev_to_node(struct device *dev); +void set_dev_node(struct device *dev, int node); + +struct device *device_create(struct class *cls, struct device *parent, + dev_t devt, void *drvdata, + const char *fmt, ...); +int device_add(struct device *dev); +void device_destroy(struct class *cls, dev_t devt); +int device_register(struct device *dev); +void device_unregister(struct device *dev); +void device_lock(struct device *dev); +int device_trylock(struct device *dev); +void device_unlock(struct device *dev); +void device_del(struct device *dev); +void device_initialize(struct device *dev); +int device_attach(struct device *dev); +int device_is_registered(struct device *dev); +int device_bind_driver(struct device *dev); +void device_release_driver(struct device *dev); +void device_enable_async_suspend(struct device *dev); +void device_set_wakeup_capable(struct device *dev, bool capable); +int device_create_bin_file(struct device *dev, + const struct bin_attribute *attr); +void device_remove_bin_file(struct device *dev, + const struct bin_attribute *attr); +int device_create_file(struct device *device, + const struct device_attribute *entry); +void device_remove_file(struct device *dev, + const struct device_attribute *attr); + +void put_device(struct device *dev); +struct device *get_device(struct device *dev); + +int driver_register(struct device_driver *drv); +void driver_unregister(struct device_driver *drv); +int driver_attach(struct device_driver *drv); +int driver_create_file(struct device_driver *driver, + const struct driver_attribute *attr); +void driver_remove_file(struct device_driver *driver, + const struct driver_attribute *attr); + +struct device_driver *get_driver(struct device_driver *drv); +void put_driver(struct device_driver *drv); + +struct device *bus_find_device(struct bus_type *bus, struct device *start, + void *data, + int (*match)(struct device *dev, void *data)); +int bus_register(struct bus_type *bus); +void bus_unregister(struct bus_type *bus); +int bus_register_notifier(struct bus_type *bus, + struct notifier_block *nb); +int bus_unregister_notifier(struct bus_type *bus, + struct notifier_block *nb); + +struct class *__class_create(struct module *owner, + const char *name, + struct lock_class_key *key); +#define class_create(owner, name) \ +({ \ + static struct lock_class_key __key; \ + __class_create(owner, name, &__key); \ +}) +int class_register(struct class *cls); +void class_unregister(struct class *cls); +void class_destroy(struct class *cls); + +#ifdef __cplusplus +#undef class +#endif + + +/***************************** + ** linux/platform_device.h ** + *****************************/ + +struct platform_device; +void *platform_get_drvdata(const struct platform_device *pdev); + + +/********************* + ** linux/dmapool.h ** + *********************/ + +struct dma_pool; + +/* + * Needed by usb/core/buffer.c + */ +struct dma_pool *dma_pool_create(const char *, struct device *, size_t, + size_t, size_t); +void dma_pool_destroy(struct dma_pool *); +void *dma_pool_alloc(struct dma_pool *, gfp_t, dma_addr_t *); +void dma_pool_free(struct dma_pool *, void *, dma_addr_t); + + +/* + * Actually defined in asm-generic/dma-mapping-broken.h + */ +void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); +void dma_free_coherent(struct device *, size_t, void *, dma_addr_t); + + +/************************* + ** linux/dma-mapping.h ** + *************************/ + +static inline u64 DMA_BIT_MASK(unsigned n) { + return (n == 64) ? ~0ULL : (1ULL << n) - 1; } + + +/********************* + ** linux/uaccess.h ** + *********************/ + +enum { VERIFY_READ = 0, VERIFY_WRITE = 1 }; + +bool access_ok(int access, void *addr, size_t size); + +size_t copy_from_user(void *to, void const *from, size_t len); +size_t copy_to_user(void *dst, void const *src, size_t len); + +#define get_user(x, ptr) ({ dde_kit_printf("get_user not implemented"); (0);}) +#define put_user(x, ptr) ({ dde_kit_printf("put_user not implemented"); (0);}) + + +/***************** + ** linux/dmi.h ** + *****************/ + +struct dmi_system_id; + +static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } +static inline const char * dmi_get_system_info(int field) { return NULL; } + + +/***************************** + ** linux/mod_devicetable.h ** + *****************************/ + +/* + * Deal with C++ keyword used as member name of 'pci_device_id' + */ +#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 +#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 +#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 +#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 +#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 +#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 +#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 +#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 +#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 +#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 + +/******************** + ** linux/dcache.h ** + ********************/ + +enum dentry_d_lock_class +{ + DENTRY_D_LOCK_NESTED +}; + +struct qstr { + const unsigned char *name; +}; + +struct dentry { + struct inode *d_inode; + struct qstr d_name; + struct list_head d_subdirs; + spinlock_t d_lock; + struct dentry *d_parent; + union { struct list_head d_child; } d_u; +}; + +void d_instantiate(struct dentry *, struct inode *); +int d_unhashed(struct dentry *dentry); +void d_delete(struct dentry *); +struct dentry *d_alloc_root(struct inode *); +struct dentry *dget(struct dentry *dentry); +void dput(struct dentry *); + +void dont_mount(struct dentry *dentry); + + +/****************** + ** linux/poll.h ** + ******************/ + +/* needed by usb/core/devices.c, defined in asm-generic/poll.h */ +#define POLLIN 0x0001 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLRDNORM 0x0040 +#define POLLWRNORM 0x0100 + +typedef struct poll_table_struct { int dummy; } poll_table; + +struct file; + +void poll_wait(struct file *, wait_queue_head_t *, poll_table *); + + +/******************** + ** linux/statfs.h ** + ********************/ + +struct kstatfs; +loff_t default_llseek(struct file *file, loff_t offset, int origin); + + +/************************* + ** asm-generic/fcntl.h ** + *************************/ + +enum { O_NONBLOCK = 0x4000 }; + + +/**************** + ** linux/fs.h ** + ****************/ + +#define FMODE_WRITE 0x2 + +enum { S_DEAD = 16 }; + +enum inode_i_mutex_lock_class { I_MUTEX_PARENT }; + +struct path { + struct dentry *dentry; +}; + +struct file { + u64 f_version; + loff_t f_pos; + struct dentry *f_dentry; + struct path f_path; + unsigned int f_flags; + fmode_t f_mode; + const struct file_operations *f_op; + void *private_data; +}; + +typedef unsigned fl_owner_t; + +struct file_operations { + struct module *owner; + int (*open) (struct inode *, struct file *); + ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); + loff_t (*llseek) (struct file *, loff_t, int); + unsigned int (*poll) (struct file *, struct poll_table_struct *); + long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); + int (*flush) (struct file *, fl_owner_t id); + int (*release) (struct inode *, struct file *); + ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); + int (*fasync) (int, struct file *, int); +}; + +struct inode_operations { int dummy; }; + +struct inode { + umode_t i_mode; + struct mutex i_mutex; + dev_t i_rdev; + struct timespec i_mtime; + struct timespec i_atime; + struct timespec i_ctime; + uid_t i_uid; + gid_t i_gid; + unsigned long i_ino; + const struct file_operations *i_fop; + const struct inode_operations *i_op; + struct super_block *i_sb; + unsigned int i_flags; + void *i_private; + loff_t i_size; +}; + +struct seq_file; +struct vfsmount; +struct super_operations { + int (*show_options)(struct seq_file *, struct vfsmount *); + int (*drop_inode) (struct inode *); + int (*remount_fs) (struct super_block *, int *, char *); + int (*statfs) (struct dentry *, struct kstatfs *); +}; + +struct super_block { + struct dentry *s_root; + const struct super_operations *s_op; + u32 s_time_gran; + unsigned long s_magic; + unsigned char s_blocksize_bits; + unsigned long s_blocksize; +}; + +struct file_system_type { + const char *name; + struct module *owner; + struct dentry *(*mount)(struct file_system_type *, int, + const char *, void *); + void (*kill_sb)(struct super_block *); +}; + +struct fasync_struct { }; + +unsigned iminor(const struct inode *inode); +unsigned imajor(const struct inode *inode); + +int register_chrdev_region(dev_t, unsigned, const char *); +void unregister_chrdev_region(dev_t, unsigned); +static inline struct file_operations const * +fops_get(struct file_operations const *fops) { return fops; } +void fops_put(struct file_operations const *); +loff_t noop_llseek(struct file *file, loff_t offset, int origin); +int register_chrdev(unsigned int major, const char *name, + const struct file_operations *fops); +void unregister_chrdev(unsigned int major, const char *name); +struct inode *new_inode(struct super_block *sb); +unsigned int get_next_ino(void); +void init_special_inode(struct inode *, umode_t, dev_t); +int generic_delete_inode(struct inode *inode); +void drop_nlink(struct inode *inode); +void inc_nlink(struct inode *inode); +void dentry_unhash(struct dentry *dentry); +void iput(struct inode *); +struct dentry *mount_single(struct file_system_type *fs_type, + int flags, void *data, + int (*fill_super)(struct super_block *, + void *, int)); +int nonseekable_open(struct inode *inode, struct file *filp); +int simple_statfs(struct dentry *, struct kstatfs *); +int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count); +ssize_t simple_read_from_buffer(void __user *to, size_t count, + loff_t *ppos, const void *from, size_t available); +void simple_release_fs(struct vfsmount **mount, int *count); +void kill_litter_super(struct super_block *sb); +int register_filesystem(struct file_system_type *); +int unregister_filesystem(struct file_system_type *); + +void kill_fasync(struct fasync_struct **, int, int); +int fasync_helper(int, struct file *, int, struct fasync_struct **); + +extern const struct file_operations simple_dir_operations; +extern const struct inode_operations simple_dir_inode_operations; + +static inline loff_t no_llseek(struct file *file, loff_t offset, int origin) { + return -ESPIPE; } + + +/******************* + ** linux/namei.h ** + *******************/ + +struct dentry *lookup_one_len(const char *, struct dentry *, int); + + +/******************* + ** linux/mount.h ** + *******************/ + +struct vfsmount { + int dummy; + struct super_block *mnt_sb; +}; + + +/************************* + ** asm-/signal.h ** + *************************/ + +enum { SIGIO = 29 }; + + +/********************** + ** linux/seq_file.h ** + **********************/ + +struct seq_file { int dummy; }; + +int seq_printf(struct seq_file *, const char *, ...); + + +/***************** + ** linux/gfp.h ** + *****************/ + +enum { + __GFP_DMA = 0x01u, + GFP_DMA = __GFP_DMA, + __GFP_WAIT = 0x10u, + GFP_ATOMIC = 0x20u, + GFP_KERNEL = 0x0u, + GFP_NOIO = __GFP_WAIT, +}; + +unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); +#define __get_free_page(gfp_mask) __get_free_pages((gfp_mask), 0) + +void __free_pages(struct page *p, unsigned int order); +#define __free_page(p) __free_pages((p), 0) + +void free_pages(unsigned long addr, unsigned int order); +#define free_page(addr) free_pages((addr), 0) + + +/********************* + ** linux/proc_fs.h ** + *********************/ + +struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *); +void remove_proc_entry(const char *name, struct proc_dir_entry *parent); + + +/******************** + * linux/debugfs.h ** + ********************/ + +struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); +struct dentry *debugfs_create_file(const char *name, mode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops); +void debugfs_remove(struct dentry *dentry); +static inline void debugfs_remove_recursive(struct dentry *dentry) { } + + +/************************ + ** linux/page-flags.h ** + ************************/ + +bool is_highmem(void *); +#define PageHighMem(__p) is_highmem(page_zone(__p)) + + +/**************** + ** linux/mm.h ** + ****************/ + +struct zone *page_zone(const struct page *page); + + +/********************* + ** linux/pagemap.h ** + *********************/ + +enum { PAGE_CACHE_SHIFT = PAGE_SHIFT }; +enum { PAGE_CACHE_SIZE = PAGE_SIZE }; + + +/********************** + ** linux/highmem.h ** + **********************/ + +void *kmap(struct page *page); +void kunmap(struct page *page); + + +/********************** + ** asm-generic/io.h ** + **********************/ + +void *ioremap(resource_size_t offset, unsigned long size); +void iounmap(volatile void *addr); + +/** + * Map I/O memory write combined + */ +void *ioremap_wc(resource_size_t phys_addr, unsigned long size); + +#define ioremap_nocache ioremap_wc + +#define writel(value, addr) (*(volatile uint32_t *)(addr) = (value)) +#define readl(addr) (*(volatile uint32_t *)(addr)) +#define readb(addr) (*(volatile uint8_t *)(addr)) + +static inline void outb(u8 value, u32 port) { dde_kit_outb(port, value); } +static inline void outw(u16 value, u32 port) { dde_kit_outw(port, value); } +static inline void outl(u32 value, u32 port) { dde_kit_outl(port, value); } + +static inline u8 inb(u32 port) { return dde_kit_inb(port); } +static inline u16 inw(u32 port) { return dde_kit_inw(port); } +static inline u32 inl(u32 port) { return dde_kit_inl(port); } + +void native_io_delay(void); + +static inline void outb_p(u8 value, u32 port) { outb(value, port); native_io_delay(); } +static inline void outw_p(u16 value, u32 port) { outw(value, port); native_io_delay(); } +static inline void outl_p(u32 value, u32 port) { outl(value, port); native_io_delay(); } + +static inline u8 inb_p(u8 port) { u8 ret = inb(port); native_io_delay(); return ret; } +static inline u16 inw_p(u16 port) { u16 ret = inw(port); native_io_delay(); return ret; } +static inline u32 inl_p(u32 port) { u32 ret = inl(port); native_io_delay(); return ret; } + + +/******************** + ** linux/ioport.h ** + ********************/ + +#define IORESOURCE_IO 0x00000100 + +struct resource +{ + resource_size_t start; + resource_size_t end; + unsigned long flags; +}; + +struct resource *request_region(resource_size_t start, resource_size_t n, + const char *name); +struct resource *request_mem_region(resource_size_t start, resource_size_t n, + const char *name); + +void release_region(resource_size_t start, resource_size_t n); +void release_mem_region(resource_size_t start, resource_size_t n); + + +/*********************** + ** linux/interrupt.h ** + ***********************/ + +#define IRQF_SHARED 0x00000080 +#define IRQF_DISABLED 0x00000020 + +void local_irq_enable(void); +void local_irq_disable(void); + +typedef irqreturn_t (*irq_handler_t)(int, void *); + +int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, + const char *name, void *dev); +void free_irq(unsigned int, void *); + + +/********************* + ** linux/hardirq.h ** + *********************/ + +void synchronize_irq(unsigned int irq); + + +/***************** + ** linux/pci.h ** + *****************/ + +#include +#include + +/* + * Definitions normally found in pci_regs.h + */ +//enum { PCI_BASE_ADDRESS_MEM_MASK = ~0x0fUL }; +//enum { PCI_CAP_ID_AGP = 0x02 }; +extern struct bus_type pci_bus_type; +enum { PCI_ANY_ID = ~0 }; +enum { DEVICE_COUNT_RESOURCE = 6 }; +//enum { PCIBIOS_MIN_MEM = 0UL }; + +#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \ + .class = (dev_class), .class_mask = (dev_class_mask), \ + .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID + +#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) + +#define PCI_DEVICE(vend,dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID + +typedef enum { PCI_D0 = 0 } pci_power_t; + +/* + * Deal with C++ keyword used as member name of 'pci_dev' + */ +#ifdef __cplusplus +#define class device_class +#endif /* __cplusplus */ + +#include + +/* + * PCI types + */ +struct pci_bus; + +struct pci_dev { + unsigned int devfn; + unsigned int irq; + struct resource resource[DEVICE_COUNT_RESOURCE]; + struct pci_bus *bus; /* needed for i915_dma.c */ + unsigned short vendor; /* needed for intel-agp.c */ + unsigned short device; + unsigned int class; /* needed by usb/host/pci-quirks.c */ + u8 revision; /* needed for ehci-pci.c */ + struct device dev; /* needed for intel-agp.c */ + pci_power_t current_state; +}; + +#ifdef __cplusplus +#undef class +#endif /* __cplusplus */ + +enum { + PCI_ROM_RESOURCE = 6 +}; + +/* + * Interface functions provided by the EHCI USB HCD driver. + */ +struct pci_driver { + char *name; + const struct pci_device_id *id_table; + int (*probe) (struct pci_dev *dev, + const struct pci_device_id *id); + void (*remove) (struct pci_dev *dev); + void (*shutdown) (struct pci_dev *dev); + struct device_driver driver; +}; + + +static inline uint32_t PCI_DEVFN(unsigned slot, unsigned func) { + return ((slot & 0x1f) << 3) | (func & 0x07); } + +int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 *val); +int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 *val); +int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 *val); +int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val); +int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val); +int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val); + +static inline +int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) { + return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val); } + +static inline +int pci_read_config_word(struct pci_dev *dev, int where, u16 *val) { + return pci_bus_read_config_word(dev->bus, dev->devfn, where, val); } + +static inline +int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val) { + return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val); } + +static inline +int pci_write_config_byte(struct pci_dev *dev, int where, u8 val) { + return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val); } + +static inline +int pci_write_config_word(struct pci_dev *dev, int where, u16 val) { + return pci_bus_write_config_word(dev->bus, dev->devfn, where, val); } + +static inline +int pci_write_config_dword(struct pci_dev *dev, int where, u32 val) { + return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); } + +size_t pci_resource_len(struct pci_dev *dev, unsigned bar); +size_t pci_resource_start(struct pci_dev *dev, unsigned bar); +void *pci_get_drvdata(struct pci_dev *pdev); +void pci_dev_put(struct pci_dev *dev); +struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, + struct pci_dev *from); +int pci_enable_device(struct pci_dev *dev); +void pci_disable_device(struct pci_dev *dev); +int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); +int pci_register_driver(struct pci_driver *driver); +void pci_unregister_driver(struct pci_driver *driver); +const char *pci_name(const struct pci_dev *pdev); +bool pci_dev_run_wake(struct pci_dev *dev); +unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar); +void pci_set_master(struct pci_dev *dev); +int pci_set_mwi(struct pci_dev *dev); +int pci_find_capability(struct pci_dev *dev, int cap); +struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn); +const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, + struct pci_dev *dev); +void *pci_ioremap_bar(struct pci_dev *pdev, int bar); + +#define to_pci_dev(n) container_of(n, struct pci_dev, dev) + +#define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook) + +#define DEFINE_PCI_DEVICE_TABLE(_table) \ + const struct pci_device_id _table[] __devinitconst + + +/********************** + ** linux/irqflags.h ** + **********************/ + +unsigned long local_irq_save(unsigned long flags); +unsigned long local_irq_restore(unsigned long flags); + + +/************************* + ** linux/dma-direction ** + *************************/ + +enum dma_data_direction +{ + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2 +}; + + +/************************* + ** linux/dma-mapping.h ** + *************************/ + +struct dma_attrs; + +dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, + size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs); + +void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, + size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs); + +void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs); + +dma_addr_t dma_map_page(struct device *dev, struct page *page, + size_t offset, size_t size, + enum dma_data_direction dir); + +int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs); + +#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL) +#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL) +#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) +#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) + +/* linux/dma-mapping-broken.h */ +void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction); +int dma_mapping_error(struct device *dev, dma_addr_t dma_addr); + +/***************** + ** linux/pid.h ** + *****************/ + +struct pid; +void put_pid(struct pid *pid); +struct pid *get_pid(struct pid *pid); + + +/****************** + ** linux/cred.h ** + ******************/ + +struct cred; +void put_cred(struct cred const *); +const struct cred *get_cred(const struct cred *cred); + +#define get_current_cred() 0 + +#define current_fsuid() 0 +#define current_fsgid() 0 + + +/*************************** + ** asm-generic/siginfo.h ** + ***************************/ + +/* needed by usb/core/devio.c */ +struct siginfo { + int si_signo; + int si_errno; + int si_code; + void *si_addr; +}; + +enum { + SI_ASYNCIO = -4, + _P = 2 << 16, + POLL_IN = _P | 1, + POLL_HUP = _P | 6, +}; + + +/********************** + ** linux/security.h ** + **********************/ + +void security_task_getsecid(struct task_struct *p, u32 *secid); + + +/************************* + ** asm-generic/ioctl.h ** + *************************/ + +/* + * Needed by usb/core/devio.h, used to calculate ioctl opcodes + */ +#include + + +/****************** + ** linux/cdev.h ** + ******************/ + +struct cdev { int dummy; }; +void cdev_init(struct cdev *, const struct file_operations *); +int cdev_add(struct cdev *, dev_t, unsigned); +void cdev_del(struct cdev *); + + +/****************** + ** linux/stat.h ** + ******************/ + +#define S_IFMT 00170000 +#define S_IFDIR 0040000 +#define S_IFREG 0100000 +#define S_ISVTX 0001000 +#define S_IALLUGO 0007777 + +#define S_IRUGO 00444 +#define S_IWUSR 00200 +#define S_IXUGO 00111 +#define S_IRWXUGO 00777 + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + + +/********************* + ** linux/utsname.h ** + *********************/ + +#define __NEW_UTS_LEN 64 + +struct new_utsname { + char sysname[__NEW_UTS_LEN + 1]; + char release[__NEW_UTS_LEN + 1]; +}; + +struct new_utsname *init_utsname(void); +struct new_utsname *utsname(void); + +/********************* + ** linux/freezer.h ** + *********************/ + +void set_freezable(void); +static inline void set_freezable_with_signal(void) {} + +#define wait_event_freezable(wq, cond) wait_event_interruptible(wq, cond) + + +/******************** + ** linux/parser.h ** + ********************/ + +/* + * needed for usb/core/inode.c + */ + +enum { MAX_OPT_ARGS = 3 }; + +struct match_token { + int token; + const char *pattern; +}; + +typedef struct substring { int dummy; } substring_t; + +typedef struct match_token match_table_t[]; + +int match_token(char *, const match_table_t table, substring_t args[]); +int match_int(substring_t *, int *result); +int match_octal(substring_t *, int *result); + + +/************************ + ** linux/completion.h ** + ************************/ + +struct completion { unsigned int done; }; +void complete(struct completion *); +void init_completion(struct completion *x); +unsigned long wait_for_completion_timeout(struct completion *x, + unsigned long timeout); +void wait_for_completion(struct completion *x); +int wait_for_completion_interruptible(struct completion *x); +long wait_for_completion_interruptible_timeout(struct completion *x, unsigned long timeout); + + +/******************* + ** linux/input.h ** + *******************/ + +struct input_dev; + +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 8 * sizeof(long)) + + +/********************* + ** linux/semaphore ** + *********************/ + +struct semaphore { }; +void sema_init(struct semaphore *sem, int val); +int down_trylock(struct semaphore *sem); +void up(struct semaphore *sem); +int down_interruptible(struct semaphore *sem); + + +/*********************** + ** linux/hid-debug.h ** + ***********************/ + +enum { HID_DEBUG_BUFSIZE=512 }; + +#define hid_debug_init() do { } while (0) +#define hid_dump_input(a,b,c) do { } while (0) +#define hid_debug_event(a,b) do { } while (0) +#define hid_debug_register(a, b) do { } while (0) +#define hid_debug_unregister(a) do { } while (0) +#define hid_debug_exit() do { } while (0) + + +/****************** + ** linux/list.h ** + ******************/ + +#define new _new +#include +#undef new + + +/******************** + ** linux/hidraw.h ** + ********************/ + +struct hidraw { u32 minor; }; +struct hid_device; + +static inline int hidraw_init(void) { return 0; } +static inline void hidraw_exit(void) { } +static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { } +static inline int hidraw_connect(struct hid_device *hid) { return -1; } +static inline void hidraw_disconnect(struct hid_device *hid) { } + + +/********************** + ** linux/rcupdate.h ** + **********************/ + +static inline void rcu_read_lock(void) { } +static inline void rcu_read_unlock(void) { } +static inline void synchronize_rcu(void) { } + +#define rcu_dereference(p) p +#define rcu_assign_pointer(p,v) p = v + + +/********************* + ** linux/rculist.h ** + *********************/ + +#define list_for_each_entry_rcu(pos, head, member) \ + list_for_each_entry(pos, head, member) + +static inline void list_add_rcu(struct list_head *n, struct list_head *head) { + list_add(n, head); } + +static inline void list_add_tail_rcu(struct list_head *n, + struct list_head *head) { + list_add_tail(n, head); } + +static inline void list_del_rcu(struct list_head *entry) { + list_del(entry); } + + +/******************** + ** linux/random.h ** + ********************/ + +static inline void add_input_randomness(unsigned int type, unsigned int code, + unsigned int value) { } + + +/********************* + ** linux/vmalloc.h ** + *********************/ + +void *vmalloc(unsigned long size); +void *vzalloc(unsigned long size); +void vfree(void *addr); + + +/******************* + ** linux/genhd.h ** + *******************/ + +struct gendisk +{ + void *private_data; +}; + + +/******************** + ** linux/blkdev.h ** + ********************/ + +enum { BLK_BOUNCE_HIGH = -1ULL }; +enum blk_eh_timer_return { DUMMY }; + +#define BLK_MAX_CDB 16 + +#define blk_bidi_rq(rq) ((rq)->next_rq != NULL) + +struct request_queue +{ + spinlock_t *queue_lock; +}; + +enum rq_cmd_type_bits +{ + REQ_TYPE_BLOCK_PC = 2, +}; + +struct request +{ + enum rq_cmd_type_bits cmd_type; + struct gendisk *rq_disk; + void *special; /* opaque pointer available for LLD use */ + struct request *next_rq; +}; + +void blk_queue_bounce_limit(struct request_queue *, u64); +void blk_queue_dma_alignment(struct request_queue *, int); +void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); +sector_t blk_rq_pos(const struct request *rq); +unsigned int queue_max_hw_sectors(struct request_queue *q); + +#include + + +/******************** + ** scsi/scsi_eh.h ** + *******************/ + +struct scsi_eh_save { }; + +struct scsi_sense_hdr +{ + u8 response_code; + u8 sense_key; + u8 asc; + u8 ascq; + u8 additional_length; /* always 0 for fixed sense format */ +}; + +void scsi_report_device_reset(struct Scsi_Host *, int, int); +void scsi_report_bus_reset(struct Scsi_Host *, int); + +void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, + struct scsi_eh_save *ses, unsigned char *cmnd, + int cmnd_size, unsigned sense_bytes); + +void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, + struct scsi_eh_save *ses); + +int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, + struct scsi_sense_hdr *sshdr); + +const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type); + +/********************* + ** scsi/scsi_tcq.h ** + *********************/ + +enum { + MSG_SIMPLE_TAG = 0x20, + MSG_ORDERED_TAG = 0x22, +}; + + +/*********************** + ** drivers/scsi/sd.h ** + **********************/ + +struct scsi_disk +{ + sector_t capacity; /* size in 512-byte sectors */ +}; + +struct scsi_disk *scsi_disk(struct gendisk *disk); + + +/********************** + ** scsi/scsi_cmnd.h ** + **********************/ + +enum { + MAX_COMMAND_SIZE = 16, + SCSI_SENSE_BUFFERSIZE = 96, +}; + +struct scsi_data_buffer +{ + struct sg_table table; + unsigned length; +}; + +struct scsi_cmnd +{ + struct scsi_device *device; + struct list_head list; /* scsi_cmnd participates in queue lists */ + + unsigned long serial_number; + + /* + * This is set to jiffies as it was when the command was first + * allocated. It is used to time how long the command has + * been outstanding + */ + unsigned long jiffies_at_alloc; + + unsigned short cmd_len; + enum dma_data_direction sc_data_direction; + unsigned char *cmnd; + + struct scsi_data_buffer sdb; + struct scsi_data_buffer *prot_sdb; + + unsigned underflow; /* return error if less than + this amount is transferred */ + + struct request *request; /* the command we are working on */ + unsigned char *sense_buffer; /* obtained by REQUEST SENSE when + * CHECK CONDITION is received on original + * command (auto-sense) */ + /** + * Low-level done function + * + * This function can be used by low-level driver to point to completion + * function. Not used by mid/upper level code. + */ + void (*scsi_done) (struct scsi_cmnd *); + + int result; /* status code from lower level driver */ + void *back; /* uur completion */ + + void *packet; + void *session; +}; + + +struct scatterlist *scsi_sglist(struct scsi_cmnd *cmd); +unsigned scsi_sg_count(struct scsi_cmnd *cmd); +unsigned scsi_bufflen(struct scsi_cmnd *cmd); +void scsi_set_resid(struct scsi_cmnd *cmd, int resid); +int scsi_get_resid(struct scsi_cmnd *cmd); + + + +/************************ + ** scsi/scsi_device.h ** + ************************/ + +struct scsi_target +{ + struct list_head devices; + struct device dev; + unsigned int channel; + unsigned int id; + unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */ + unsigned int target_blocked; + char scsi_level; +}; + +enum scsi_device_state +{ + SDEV_DEL, /* device deleted + * no commands allowed */ +}; + +struct scsi_device +{ + struct Scsi_Host *host; + struct request_queue *request_queue; + + struct list_head siblings; /* list of all devices on this host */ + struct list_head same_target_siblings; /* just the devices sharing same target id */ + + spinlock_t list_lock; + struct list_head cmd_list; /* queue of in use SCSI Command structures */ + + unsigned short queue_depth; /* How deep of a queue we want */ + + unsigned short last_queue_full_depth; /* These two are used by */ + unsigned short last_queue_full_count; /* scsi_track_queue_full() */ + unsigned long last_queue_full_time; /* last queue full time */ + + unsigned long id, lun, channel; + char type; + char scsi_level; + unsigned char inquiry_len; /* valid bytes in 'inquiry' */ + struct scsi_target *sdev_target; /* used only for single_lun */ + + unsigned lockable:1; /* able to prevent media removal */ + unsigned simple_tags:1; /* simple queue tag messages are enabled */ + unsigned ordered_tags:1; /* ordered queue tag messages are enabled */ + unsigned use_10_for_rw:1; /* first try 10-byte read / write */ + unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ + unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ + unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ + unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */ + unsigned allow_restart:1; /* issue START_UNIT in error handler */ + unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ + unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */ + unsigned no_read_capacity_16:1; /* avoid READ_CAPACITY_16 cmds */ + unsigned retry_hwerror:1; /* retry HARDWARE_ERROR */ + unsigned last_sector_bug:1; /* do not use multisector accesses on + SD_LAST_BUGGY_SECTORS */ + unsigned no_read_disc_info:1; /* avoid READ_DISC_INFO cmds */ + + unsigned int device_blocked; /* device returned QUEUE_FULL. */ + + atomic_t iorequest_cnt; + struct device sdev_gendev; + enum scsi_device_state sdev_state; +}; + +#define to_scsi_device(d) \ + container_of(d, struct scsi_device, sdev_gendev) + +#define shost_for_each_device(sdev, shost) dde_kit_printf("shost_for_each_device called\n"); +#define __shost_for_each_device(sdev, shost) dde_kit_printf("__shost_for_each_device called\n"); + + +/************************ + ** scsi/scsi_driver.h ** + ************************/ + +struct scsi_driver +{ + int (*done)(struct scsi_cmnd *); +}; + + +/********** + ** misc ** + **********/ + +static inline void dump_stack(void) { } + +static inline void * __must_check ERR_PTR(long error) { + return (void *) error; +} + + +/** + * Genode's evdev event handler + */ +enum input_event_type { + EVENT_TYPE_PRESS, EVENT_TYPE_RELEASE, /* key press and release */ + EVENT_TYPE_MOTION, /* any type of (pointer) motion */ + EVENT_TYPE_WHEEL /* mouse scroll wheel */ +}; + +struct input_handle; + +/** + * Input event callback + * + * \param type input event type + * \param keycode key code if type is EVENT_TYPE_PRESS or + * EVENT_TYPE_RELEASE + * \param absolute_x absolute horizontal coordinate if type is + * EVENT_TYPE_MOTION + * \param absolute_y absolute vertical coordinate if type is + * EVENT_TYPE_MOTION + * \param relative_x relative horizontal coordinate if type is + * EVENT_TYPE_MOTION or EVENT_TYPE_WHEEL + * \param relative_y relative vertical coordinate if type is + * EVENT_TYPE_MOTION or EVENT_TYPE_WHEEL + * + * Key codes conform to definitions in os/include/input/event.h, which is C++ + * and therefore not included here. + * + * Relative coordinates are only significant if absolute_x and absolute_y are + * 0. + */ +typedef void (*genode_input_event_cb)(enum input_event_type type, + unsigned keycode, + int absolute_x, int absolute_y, + int relative_x, int relative_y); + +/** + * Register input handle + * + * \param handler call-back function on input events + * + * \return 0 on success; !0 otherwise + */ +void genode_input_register(genode_input_event_cb handler); + + +void genode_evdev_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value); + +void start_input_service(void *ep); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _LX_EMUL_H_ */ diff --git a/dde_linux/src/drivers/usb/main.cc b/dde_linux/src/drivers/usb/main.cc new file mode 100644 index 000000000..b1144d55f --- /dev/null +++ b/dde_linux/src/drivers/usb/main.cc @@ -0,0 +1,135 @@ +/* + * \brief USB driver main program + * \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 */ +#include +#include +#include +#include +#include +#include + +/* Local */ +#include "storage/component.h" +#include "routine.h" +#include "signal.h" + +extern "C" { +#include +} + +using namespace Genode; + +extern "C" void subsys_usb_init(); +extern "C" void subsys_input_init(); +extern "C" void module_ehci_hcd_init(); +extern "C" void module_evdev_init(); +extern "C" void module_hid_init(); +extern "C" void module_hid_init_core(); +extern "C" void module_uhci_hcd_init(); +extern "C" void module_usb_mouse_init(); +extern "C" void module_usb_kbd_init(); +extern "C" void module_usb_stor_init(); + +extern "C" void start_input_service(void *ep); + +Routine *Routine::_current = 0; +Routine *Routine::_dead = 0; +bool Routine::_all = false; + +void breakpoint() { PDBG("BREAK"); } + + +static void init(bool hid, bool stor) +{ + /* start jiffies */ + dde_kit_timer_init(0, 0); + + /* USB */ + subsys_usb_init(); + + /* input + HID */ + if (hid) { + subsys_input_init(); + module_evdev_init(); + + /* HID */ + module_hid_init(); + module_usb_mouse_init(); + module_usb_kbd_init(); + } + + /* + * Host controller. + * + * ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after + */ + module_ehci_hcd_init(); + module_uhci_hcd_init(); + + /* storage */ + if (stor) + module_usb_stor_init(); +} + + +int main(int, char **) +{ + /* + * Initialize server entry point + */ + enum { STACK_SIZE = 4096 }; + static Cap_connection cap; + static Rpc_entrypoint ep_hid(&cap, STACK_SIZE, "usb_hid_ep"); + static Signal_receiver recv; + + bool hid = false; + bool stor = false; + + try { + config()->xml_node().sub_node("hid"); + start_input_service(&ep_hid); + hid = true; + } catch (Config::Invalid) { + PDBG("No node found - not starting any USB services"); + return 0; + } catch (Xml_node::Nonexistent_sub_node) { + PDBG("No config node found - not starting the USB HID (Input) service"); + } + + try { + config()->xml_node().sub_node("storage"); + stor = true; + } catch (Xml_node::Nonexistent_sub_node) { + PDBG("No config node found - not starting the USB Storage (Block) service"); + } + + Timer::init(&recv); + Irq::init(&recv); + Event::init(&recv); + Service_handler::s()->receiver(&recv); + Storage::init(&recv); + + Routine::add(0, 0, "Main", true); + Routine::current_use_first(); + init(hid, stor); + + Routine::remove(); + + /* will never be reached */ + sleep_forever(); + + return 0; +} diff --git a/dde_linux/src/drivers/usb/pci_driver.cc b/dde_linux/src/drivers/usb/pci_driver.cc new file mode 100644 index 000000000..d0fcd1c68 --- /dev/null +++ b/dde_linux/src/drivers/usb/pci_driver.cc @@ -0,0 +1,320 @@ +/* + * \brief Emulate 'pci_dev' structure + * \author Sebastian Sumpf + * \date 2012-04-02 + */ + +/* + * 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 inludes */ +#include +#include + +/* Linux includes */ +#include + + +struct bus_type pci_bus_type; + + +/** + * Scan PCI bus and probe for HCDs + */ +class Pci_driver +{ + private: + + pci_driver *_drv; /* Linux PCI driver */ + Pci::Device_capability _cap; /* PCI cap */ + pci_device_id const *_id; /* matched id for this driver */ + + public: + + pci_dev *_dev; /* Linux PCI device */ + + private: + + /* offset used in PCI config space */ + enum Pci_config { IRQ = 0x3c, REV = 0x8, CMD = 0x4 }; + + /** + * Match class code of device with driver id + */ + bool _match(pci_device_id const *id) + { + Pci::Device_client client(_cap); + if (!((id->device_class ^ client.class_code()) & id->class_mask)) { + _id = id; + return true; + } + + return false; + } + + /** + * Match supported device ID of driver to this device + */ + bool _match() + { + pci_device_id const *id = _drv->id_table; + + if (!id) + return false; + + while (id->vendor || id->subvendor || id->class_mask) { + if (_match(id)) { + dde_kit_log(DEBUG_PCI, "Device matched %p", this); + return true; + } + id++; + } + + return false; + } + + /** + * Fill Linux device informations + */ + void _setup_pci_device() + { + using namespace Pci; + + _dev = new (Genode::env()->heap()) pci_dev; + Device_client client(_cap); + + _dev->vendor = client.vendor_id(); + _dev->device = client.device_id(); + _dev->device_class = client.class_code(); + _dev->revision = client.config_read(REV, Device::ACCESS_8BIT); + _dev->dev.driver = &_drv->driver; + + /* read interrupt line */ + _dev->irq = client.config_read(IRQ, Device::ACCESS_8BIT); + + /* hide ourselfs in bus structure */ + _dev->bus = (struct pci_bus *)this; + + /* setup resources */ + bool io = false; + for (int i = 0; i < Device::NUM_RESOURCES; i++) { + Device::Resource res = client.resource(i); + _dev->resource[i].start = res.base(); + _dev->resource[i].end = res.base() + res.size() - 1; + _dev->resource[i].flags = res.type() == Device::Resource::IO + ? IORESOURCE_IO : 0; + + /* request port I/O session */ + if (res.type() == Device::Resource::IO) { + if (dde_kit_request_io(res.base(), res.size())) + PERR("Failed to request I/O: [%u,%u)", + res.base(), res.base() + res.size()); + io = true; + dde_kit_log(DEBUG_PCI, "I/O [%u-%u)", + res.base(), res.base() + res.size()); + } + + /* request I/O memory (write combined) */ + if (res.type() == Device::Resource::MEMORY) + dde_kit_log(DEBUG_PCI, "I/O memory [%x-%x)", res.base(), + res.base() + res.size()); + } + + /* enable bus master and io bits */ + uint16_t cmd = client.config_read(CMD, Device::ACCESS_16BIT); + cmd |= io ? 0x1 : 0; + + /* enable bus master */ + cmd |= 0x4; + client.config_write(CMD, cmd, Device::ACCESS_16BIT); + } + + /** + * Probe device with driver + */ + bool _probe() + { + _setup_pci_device(); + + if (!_drv->probe(_dev, _id)) + return true; + + PERR("Probe failed\n"); + return false; + } + + template + Pci::Device::Access_size _access_size(T t) + { + switch (sizeof(T)) + { + case 1: + return Pci::Device::ACCESS_8BIT; + case 2: + return Pci::Device::ACCESS_16BIT; + default: + return Pci::Device::ACCESS_32BIT; + } + } + + public: + + Pci_driver(pci_driver *drv, Pci::Device_capability cap) + : _drv(drv), _cap(cap), _id(0), _dev(0) + { + if (!_match()) + throw -1; + + if (!_probe()) + throw -2; + } + + ~Pci_driver() + { + if (!_dev) + return; + + for (int i = 0; i < Pci::Device::NUM_RESOURCES; i++) { + resource *r = &_dev->resource[i]; + + if (r->flags & IORESOURCE_IO) + dde_kit_release_io(r->start, (r->end - r->start) + 1); + } + + destroy(Genode::env()->heap(), _dev); + } + + /** + * Read/write data from/to config space + */ + template + void config_read(unsigned int devfn, T *val) + { + Pci::Device_client client(_cap); + *val = client.config_read(devfn, _access_size(*val)); + } + + template + void config_write(unsigned int devfn, T val) + { + Pci::Device_client client(_cap); + client.config_write(devfn, val, _access_size(val)); + } +}; + + +/********************* + ** Linux interface ** + *********************/ + +int pci_register_driver(struct pci_driver *drv) +{ + dde_kit_log(DEBUG_PCI, "DRIVER name: %s", drv->name); + drv->driver.name = drv->name; + + using namespace Genode; + Pci::Connection pci; + + Pci::Device_capability cap = pci.first_device(); + Pci::Device_capability old; + while (cap.valid()) { + + uint8_t bus, dev, func; + Pci::Device_client client(cap); + client.bus_address(&bus, &dev, &func); + dde_kit_log(DEBUG_PCI, "bus: %x dev: %x func: %x", bus, dev, func); + + Pci_driver *pci_drv= 0; + try { + pci_drv = new (env()->heap()) Pci_driver(drv, cap); + pci.on_destruction(Pci::Connection::KEEP_OPEN); + return 0; + } catch (...) { + destroy(env()->heap(), pci_drv); + pci_drv = 0; + } + + old = cap; + cap = pci.next_device(cap); + pci.release_device(old); + } + + return -ENODEV; +} + + +size_t pci_resource_start(struct pci_dev *dev, unsigned bar) +{ + if (bar >= DEVICE_COUNT_RESOURCE) + return 0; + + return dev->resource[bar].start; +} + + +size_t pci_resource_len(struct pci_dev *dev, unsigned bar) +{ + size_t start = pci_resource_start(dev, bar); + + if (!start) + return 0; + + return (dev->resource[bar].end - start) + 1; +} + + +unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar) +{ + if (bar >= DEVICE_COUNT_RESOURCE) + return 0; + + return dev->resource[bar].flags; +} + + +int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int, u8 *val) +{ + Pci_driver *drv = (Pci_driver *)bus; + drv->config_read(devfn, val); + dde_kit_log(DEBUG_PCI, "READ %p: %x", drv, *val); + return 0; +} + + +int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int, u16 *val) +{ + Pci_driver *drv = (Pci_driver *)bus; + drv->config_read(devfn, val); + dde_kit_log(DEBUG_PCI, "READ %p: %x", drv, *val); + return 0; +} + + +int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int, u16 val) +{ + Pci_driver *drv = (Pci_driver *)bus; + dde_kit_log(DEBUG_PCI, "WRITE %p: %x", drv, val); + drv->config_write(devfn, val); + return 0; +} + + +int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int, u8 val) +{ + Pci_driver *drv = (Pci_driver *)bus; + dde_kit_log(DEBUG_PCI, "WRITE %p: %x", drv, val); + drv->config_write(devfn, val); + return 0; +} + + +const char *pci_name(const struct pci_dev *pdev) +{ + /* simply return driver name */ + return "dummy"; +} + diff --git a/dde_linux/src/drivers/usb/routine.h b/dde_linux/src/drivers/usb/routine.h new file mode 100644 index 000000000..fc50b3fdd --- /dev/null +++ b/dde_linux/src/drivers/usb/routine.h @@ -0,0 +1,194 @@ +/* + * \brief Pseudo-thread implementation using setjmp/longjmp + * \author Sebastian Sumpf + * \date 2012-04-25 + */ + +/* + * 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. + */ + +#ifndef _ROUTINE_H_ +#define _ROUTINE_H_ + +#include +#include +#include + +extern "C" { +#include +} + +static const bool verbose = false; + + +/** + * Allows pseudo-parallel execution of functions + */ +class Routine : public Genode::List::Element +{ + private: + + enum { STACK_SIZE = 0x2000 }; + bool _started; /* true if already started */ + jmp_buf _env; /* state */ + int (*_func)(void *); /* function to call*/ + void *_arg; /* argument for function */ + char const *_name; /* name of this object */ + char *_stack; /* stack pointer */ + static Routine *_current; /* currently scheduled object */ + static Routine *_dead; /* object to remove */ + static bool _all; /* true when all objects must be scheduled */ + + + /** + * List containing all registered objects + */ + static Genode::List *_list() + { + static Genode::List _l; + return &_l; + } + + /** + * Start/restore + */ + void _run() + { + /* will never return */ + if (!_started) { + _started = true; + _stack = (char *)dde_kit_simple_malloc(STACK_SIZE); + + if (verbose) + PDBG("Start func %s (%p) sp: %p", _name, _func, (_stack + STACK_SIZE)); + + /* XXX move to platform code */ + + /* switch stack and call '_func(_arg)' */ + asm volatile ("movl %2, 0(%0);" + "movl %1, -0x4(%0);" + "movl %0, %%esp;" + "call *-4(%%esp);" + : : "r" (_stack + STACK_SIZE), "r" (_func), "r" (_arg)); + } + + /* restore old state */ + if (verbose) + PDBG("Schedule %s (%p)", _name, _func); + + _longjmp(_env, 1); + } + + /** + * Check for and remove dead objects + */ + static void _check_dead() + { + if (!_dead) + return; + + _list()->remove(_dead); + destroy(Genode::env()->heap(), _dead); + _dead = 0; + } + + /** + * Get next object to schedule + */ + static Routine *_next(bool all) + { + /* on schedule all start at first element */ + if (all) { + _all = true; + return _list()->first(); + } + + /* disable all at last element */ + if (_all && _current && !_current->next()) + _all = false; + + /* return next element (wrap at the end) */ + return _current && _current->next() ? _current->next() : _list()->first(); + } + + public: + + Routine(int (*func)(void*), void *arg, char const *name, bool started) + : _started(started), _func(func), _arg(arg), _name(name), _stack(0) { } + + ~Routine() + { + if (_stack) + dde_kit_simple_free(_stack); + } + + /** + * Schedule next object + * + * If all is true, each object will be scheduled once. + */ + static void schedule(bool all = false) __attribute__((noinline)) + { + if (!_list()->first()) + return; + + Routine *next = _next(all); + + if (next == _current) + return; + + /* return when restored */ + if (_current && _setjmp(_current->_env)) { + _check_dead(); + return; + } + + _current = next; + _current->_run(); + } + + /** + * Schedule each object once + */ + static void schedule_all() { schedule(true); } + + /** + * Set current to first object + */ + static void current_use_first() { _current = _list()->first(); } + + /** + * Add an object + */ + static void add(int (*func)(void *), void *arg, char const *name, + bool started = false) + { + _list()->insert(new (Genode::env()->heap()) + Routine(func, arg, name, started)); + } + + /** + * Remove this object + */ + static void remove() + { + if (!_current) + return; + + _dead = _current; + + schedule(); + } + + /** + * True when 'schedule_all' has been called and is still in progress + */ + static bool all() { return _all; } +}; + +#endif /* _ROUTINE_H_ */ + diff --git a/dde_linux/src/drivers/usb/signal.h b/dde_linux/src/drivers/usb/signal.h new file mode 100644 index 000000000..9c766aa8e --- /dev/null +++ b/dde_linux/src/drivers/usb/signal.h @@ -0,0 +1,121 @@ +/* + * \brief Main-signal receiver and signal-helper functions + * \author Sebastian Sumpf + * \date 2012-05-23 + */ + +/* + * 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. + */ + +#ifndef _SIGNAL_H_ +#define _SIGNAL_H_ + +#include +#include +#include + +#include "routine.h" + +/** + * Context base for IRQ, Timer, etc. + */ +class Driver_context : public Genode::Signal_context +{ + public: + + /** + * Perform context operation + */ + virtual void handle() = 0; +}; + + +/** + * This singelton currently received all signals + */ +class Service_handler +{ + + private: + + Genode::Signal_receiver *_receiver; + + Service_handler() { } + + public: + + static Service_handler * s() + { + static Service_handler _s; + return &_s; + } + + void receiver(Genode::Signal_receiver *recv) { _receiver = recv; } + + /** + * Dispatch for wait for signal + */ + void process() + { + if (Routine::all()) { + Routine::schedule(); + return; + } + + do { + Genode::Signal s = _receiver->wait_for_signal(); + + /* handle signal IRQ, timer, or event signals */ + Driver_context *ctx = static_cast(s.context()); + ctx->handle(); + } while (_receiver->pending()); + } +}; + + +/** + * Helper that holds sender and receiver + */ +class Signal_helper +{ + private: + + Genode::Signal_receiver *_receiver; + Genode::Signal_transmitter *_sender; + + public: + + Signal_helper(Genode::Signal_receiver *recv) + : _receiver(recv), + _sender(new (Genode::env()->heap()) Genode::Signal_transmitter()) { } + + Genode::Signal_receiver *receiver() const { return _receiver; } + Genode::Signal_transmitter *sender() const { return _sender; } +}; + + +namespace Timer +{ + void init(Genode::Signal_receiver *recv); +} + +namespace Irq +{ + void init(Genode::Signal_receiver *recv); +} + +namespace Event +{ + void init(Genode::Signal_receiver *recv); +} + +namespace Storage +{ + void init(Genode::Signal_receiver *recv); +} + +#endif /* _SIGNAL_H_ */ diff --git a/dde_linux/src/drivers/usb/signal/event.cc b/dde_linux/src/drivers/usb/signal/event.cc new file mode 100644 index 000000000..960739a14 --- /dev/null +++ b/dde_linux/src/drivers/usb/signal/event.cc @@ -0,0 +1,167 @@ +/* + * \brief Signal context for completions and events + * \author Sebastian Sumpf + * \date 2012-05-23 + */ + +/* + * 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. + */ + +#include +#include + + +static Signal_helper *_signal = 0; + +/** + * Context for events + */ +class Event_context : public Driver_context +{ + private: + + Genode::Signal_context_capability _ctx_cap; + + Event_context() + : _ctx_cap(_signal->receiver()->manage(this)) { + _signal->sender()->context(_ctx_cap); } + + public: + + static Event_context *e() + { + static Event_context _e; + return &_e; + } + + void submit() { + _signal->sender()->submit(); } + + void handle() { + Routine::schedule_all(); } +}; + + +void Event::init(Genode::Signal_receiver *recv) { + _signal = new (Genode::env()->heap()) Signal_helper(recv); } + + +/************************ + ** linux/completion.h ** + ************************/ + +void __wake_up() { Routine::schedule_all(); } + + +void __wait_event() { + Service_handler::s()->process(); } + + +void init_completion(struct completion *work) +{ + dde_kit_log(DEBUG_COMPLETION, "New completion %p", work); + work->done = 0; +} + + +void complete(struct completion *work) +{ + dde_kit_log(DEBUG_COMPLETION, "%p", work); + work->done = 1; + + /* send signal */ + Event_context::e()->submit(); +} + + +void complete_and_exit(struct completion *work, long code) +{ + dde_kit_log(DEBUG_COMPLETION, "%p", work); + complete(work); + Routine::remove(); +} + + + +static void __wait_completion(struct completion *work) +{ + while (!work->done) + __wait_event(); + + work->done = 0; +} + + +static unsigned long +__wait_completion_timeout(struct completion *work, unsigned long timeout) +{ + unsigned long _j = jiffies + (timeout / HZ); + while (!work->done) { + __wait_event(); + + if (_j >= jiffies) + return 0; + } + + work->done = 0; + + return _j - jiffies; +} + + +unsigned long wait_for_completion_timeout(struct completion *work, + unsigned long timeout) +{ + dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); + __wait_completion(work); + return 1; +} + + +int wait_for_completion_interruptible(struct completion *work) +{ + dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); + + __wait_completion(work); + return 0; +} + + +long wait_for_completion_interruptible_timeout(struct completion *work, + unsigned long timeout) +{ + dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); + __wait_completion(work); + return 1; +} + + +void wait_for_completion(struct completion *work) +{ + dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done); + __wait_completion(work); +} + + +/******************* + ** linux/timer.h ** + *******************/ + +signed long schedule_timeout_uninterruptible(signed long timeout) +{ + dde_kit_log(DEBUG_COMPLETION, "%ld\n", timeout); + __wait_event(); + return 0; +} + + +int wake_up_process(struct task_struct *tsk) +{ + Routine::schedule_all(); + return 0; +} + diff --git a/dde_linux/src/drivers/usb/signal/irq.cc b/dde_linux/src/drivers/usb/signal/irq.cc new file mode 100644 index 000000000..c6c69b193 --- /dev/null +++ b/dde_linux/src/drivers/usb/signal/irq.cc @@ -0,0 +1,140 @@ +/* + * \brief Signal context for IRQ's + * \author Sebastian Sumpf + * \date 2012-05-23 + */ + +/* + * 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. + */ + +#include +#include + +extern "C" { +#include +} + + +/* our local incarnation of sender and receiver */ +static Signal_helper *_signal = 0; + + +/** + * This contains the Linux-driver handlers + */ +struct Irq_handler : Genode::List::Element +{ + void *dev; /* Linux device */ + irq_handler_t handler; /* Linux handler */ + + Irq_handler(void *dev, irq_handler_t handler) + : dev(dev), handler(handler) { } +}; + + +/** + * Signal context for IRQs + */ +class Irq_context : public Driver_context, + public Genode::List::Element +{ + private: + + unsigned int _irq; /* IRQ number */ + Genode::List _handler_list; /* List of registered handlers */ + Genode::Signal_context_capability _ctx_cap; /* capability for this context */ + + static Genode::List *_list() + { + static Genode::List _l; + return &_l; + } + + /** + * Find context for given IRQ number + */ + static Irq_context *_find_ctx(unsigned int irq) + { + for (Irq_context *i = _list()->first(); i; i = i->next()) + if (i->_irq == irq) + return i; + + return 0; + } + + /* called by the DDE kit upon IRQ */ + static void _dde_handler(void *irq) + { + Irq_context *ctx = static_cast(irq); + + /* set context & submit signal */ + _signal->sender()->context(ctx->_ctx_cap); + _signal->sender()->submit(); + } + + public: + + Irq_context(unsigned int irq) + : _irq(irq), + _ctx_cap(_signal->receiver()->manage(this)) + { + /* register at DDE (shared) */ + dde_kit_interrupt_attach(_irq, 1, 0, _dde_handler, this); + dde_kit_interrupt_enable(_irq); + _list()->insert(this); + } + + void handle() + { + /* report IRQ to all clients */ + for (Irq_handler *h = _handler_list.first(); h; h = h->next()) { + irqreturn_t rc; + do { + rc = h->handler(_irq, h->dev); + } + while (rc == IRQ_HANDLED); + dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u", _irq, rc); + if (rc == IRQ_HANDLED) { + Routine::schedule_all(); + return; + } + } + } + + /** + * Request an IRQ + */ + static void request_irq(unsigned int irq, irq_handler_t handler, void *dev) + { + Irq_handler *h = new(Genode::env()->heap()) Irq_handler(dev, handler); + Irq_context *ctx = _find_ctx(irq); + + /* if this IRQ is not registered */ + if (!ctx) + ctx = new (Genode::env()->heap()) Irq_context(irq); + + /* register Linux handler */ + ctx->_handler_list.insert(h); + } +}; + + +void Irq::init(Genode::Signal_receiver *recv) { + _signal = new (Genode::env()->heap()) Signal_helper(recv); } + + +/*********************** + ** linux/interrupt.h ** + ***********************/ + +int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, + const char *name, void *dev) +{ + dde_kit_log(DEBUG_IRQ, "Request irq %u", irq); + Irq_context::request_irq(irq, handler, dev); + return 0; +} diff --git a/dde_linux/src/drivers/usb/signal/timer.cc b/dde_linux/src/drivers/usb/signal/timer.cc new file mode 100644 index 000000000..401d331fc --- /dev/null +++ b/dde_linux/src/drivers/usb/signal/timer.cc @@ -0,0 +1,150 @@ +/* + * \brief Signal context for timer events + * \author Sebastian Sumpf + * \date 2012-05-23 + */ + +/* + * 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. + */ + +#include +#include + +#include +#include "signal.h" + +static void handler(void *timer); + + +/* our local incarnation of sender and receiver */ +static Signal_helper *_signal = 0; + + +/** + * Signal context for time-outs + */ +class Timer_context : public Driver_context +{ + private: + + timer_list *_timer; /* Linux timer */ + dde_kit_timer *_dde_timer; /* DDE kit timer */ + Genode::Signal_context_capability _ctx_cap; /* Signal-context cap + for this timer */ + + public: + + Timer_context(timer_list *timer) + : _timer(timer), _dde_timer(0), + _ctx_cap(_signal->receiver()->manage(this)) { } + + ~Timer_context() + { + _signal->receiver()->dissolve(this); + } + + /* call timer function */ + void handle() { _timer->function(_timer->data); } + + /* schedule next timeout */ + void schedule(unsigned long expires) + { + if (!_dde_timer) + _dde_timer = dde_kit_timer_add(handler, this, expires); + else + dde_kit_timer_schedule_absolute(_dde_timer, expires); + } + + /** + * Return true if timer is pending + */ + bool pending() const + { + return _dde_timer ? dde_kit_timer_pending(_dde_timer) : false; + } + + /** + * Return internal signal cap + */ + Genode::Signal_context_capability cap() const { return _ctx_cap; } + + /** + * Convert 'timer_list' to 'Timer_conext' + */ + static Timer_context *to_ctx(timer_list const *timer) { + return static_cast(timer->timer); } + + void remove() + { + if (_dde_timer) + dde_kit_timer_del(_dde_timer); + + _dde_timer = 0; + } + + timer_list *l() { return _timer; } +}; + + +/** + * C handler for DDE timer interface + */ +static void handler(void *timer) +{ + Timer_context *t = static_cast(timer); + + /* set context and submit */ + _signal->sender()->context(t->cap()); + _signal->sender()->submit(); +} + + +void Timer::init(Genode::Signal_receiver *recv) { + _signal = new (Genode::env()->heap()) Signal_helper(recv); } + + +/******************* + ** linux/timer.h ** + *******************/ + +void init_timer(struct timer_list *timer) { + timer->timer = (void *) new (Genode::env()->heap()) Timer_context(timer); } + + +int mod_timer(struct timer_list *timer, unsigned long expires) +{ + dde_kit_log(DEBUG_TIMER, "Timer: %p j: %lu ex: %lu func %p", + timer, jiffies, expires, timer->function); + Timer_context::to_ctx(timer)->schedule(expires); + return 0; +} + + +void setup_timer(struct timer_list *timer,void (*function)(unsigned long), + unsigned long data) +{ + timer->function = function; + timer->data = data; + init_timer(timer); +} + + +int timer_pending(const struct timer_list * timer) +{ + bool pending = Timer_context::to_ctx(timer)->pending(); + dde_kit_log(DEBUG_TIMER, "Pending %p %u", timer, pending); + return pending; +} + + +int del_timer(struct timer_list *timer) +{ + dde_kit_log(DEBUG_TIMER, "Delete timer %p", timer); + Timer_context::to_ctx(timer)->remove(); + return 0; +} + diff --git a/dde_linux/src/drivers/usb/storage/component.h b/dde_linux/src/drivers/usb/storage/component.h new file mode 100644 index 000000000..244b54fdb --- /dev/null +++ b/dde_linux/src/drivers/usb/storage/component.h @@ -0,0 +1,204 @@ +/* + * \brief Block-session implementation for USB storage + * \author Sebastian Sumpf + * \date 2012-05-23 + */ + +/* + * 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. + */ + +#ifndef _STORAGE__COMPONENT_H_ +#define _STORAGE__COMPONENT_H_ + +#include +#include + +#include "signal.h" + +namespace Block { + + using namespace Genode; + + class Session_component; + + struct Device + { + /** + * Request block size for driver and medium + */ + virtual Genode::size_t block_size() = 0; + + /** + * Request capacity of medium in blocks + */ + virtual Genode::size_t block_count() = 0; + + virtual void io(Session_component *session, Packet_descriptor &packet, + addr_t virt, addr_t phys) = 0; + }; + + + template + class Signal_dispatcher : public Driver_context, + public Signal_context_capability + { + private: + + T &obj; + void (T::*member) (); + Signal_receiver *sig_rec; + + public: + + /** + * Constructor + * + * \param sig_rec signal receiver to associate the signal + * handler with + * \param obj,member object and member function to call when + * the signal occurs + */ + Signal_dispatcher(Signal_receiver *sig_rec, + T &obj, void (T::*member)()) + : + Signal_context_capability(sig_rec->manage(this)), + obj(obj), member(member), + sig_rec(sig_rec) + { } + + ~Signal_dispatcher() { sig_rec->dissolve(this); } + + void handle() { (obj.*member)(); } + }; + + + class Session_component : public Session_rpc_object + { + private: + + addr_t _rq_phys ; /* physical addr. of rq_ds */ + Device *_device; /* device this session is using */ + + Signal_dispatcher _process_packet_dispatcher; + + void _process_packets() + { + while (tx_sink()->packet_avail()) + { + Packet_descriptor packet = tx_sink()->get_packet(); + addr_t virt = (addr_t)tx_sink()->packet_content(packet); + addr_t phys = _rq_phys + packet.offset(); + + try { + _device->io(this, packet, virt, phys); + } catch (...) { PERR("Failed to queue packet"); } + } + } + + public: + + /** + * Constructor + */ + Session_component(Dataspace_capability rq_ds, + Rpc_entrypoint &ep, + Signal_receiver *sig_rec, + Device *device) + : + Session_rpc_object(rq_ds, ep), + _rq_phys(Dataspace_client(rq_ds).phys_addr()), + _device(device), + _process_packet_dispatcher(sig_rec, *this, + &Session_component::_process_packets) + { + /* + * Register '_process_packets' dispatch function as signal + * handler for packet-avail and ready-to-ack signals. + */ + _tx.sigh_packet_avail(_process_packet_dispatcher); + _tx.sigh_ready_to_ack(_process_packet_dispatcher); + } + + void info(size_t *blk_count, size_t *blk_size, + Operations *ops) + { + *blk_count = _device->block_count(); + *blk_size = _device->block_size(); + ops->set_operation(Packet_descriptor::READ); + ops->set_operation(Packet_descriptor::WRITE); + } + + void complete(Packet_descriptor &packet, bool success) + { + packet.succeeded(success); + tx_sink()->acknowledge_packet(packet); + } + }; + + /* + * Shortcut for single-client root component + */ + typedef Root_component Root_component; + + /** + * Root component, handling new session requests + */ + class Root : public Root_component + { + private: + + Rpc_entrypoint &_ep; + Signal_receiver *_sig_rec; + Device *_device; + + protected: + + /** + * Always returns the singleton block-session component + */ + Session_component *_create_session(const char *args) + { + size_t ram_quota = + Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = + Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + + /* delete ram quota by the memory needed for the session */ + size_t session_size = max((size_t)4096, + sizeof(Session_component) + + sizeof(Allocator_avl)); + if (ram_quota < session_size) + throw Root::Quota_exceeded(); + + /* + * Check if donated ram quota suffices for both communication + * buffers. Also check both sizes separately to handle a + * possible overflow of the sum of both sizes. + */ + if (tx_buf_size > ram_quota - session_size) { + PERR("insufficient 'ram_quota', got %zd, need %zd", + ram_quota, tx_buf_size + session_size); + throw Root::Quota_exceeded(); + } + + return new (md_alloc()) + Session_component(env()->ram_session()->alloc(tx_buf_size), + _ep, _sig_rec, _device); + } + + public: + + Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, + Signal_receiver *sig_rec, Device *device) + : + Root_component(session_ep, md_alloc), + _ep(*session_ep), _sig_rec(sig_rec), _device(device) + { } + }; +} + +#endif /* _STORAGE__COMPONENT_H_ */ diff --git a/dde_linux/src/drivers/usb/storage/scsi.c b/dde_linux/src/drivers/usb/storage/scsi.c new file mode 100644 index 000000000..645545181 --- /dev/null +++ b/dde_linux/src/drivers/usb/storage/scsi.c @@ -0,0 +1,218 @@ +/* + * \brief SCSI support emulation + * \author Christian Helmuth + * \author Sebastian Sumpf + * \date 2009-10-29 + * + * XXX NOTES XXX + * + * struct scsi_host_template + * + * struct scsi_host + * + * host_lock used by scsi_unlock, scsi_lock + * max_id used by usb_stor_report_device_reset + * + * struct scsi_cmnd + * + * functions + * + * scsi_add_host + * scsi_host_alloc + * scsi_host_get + * scsi_host_put + * scsi_remove_host + * scsi_report_bus_reset + * scsi_report_device_reset + * scsi_scan_host + */ + +#include + +#include "scsi.h" + +#define DEBUG_SCSI 0 + +/*************** + ** SCSI host ** + ***************/ + +struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *t, int priv_size) +{ + dde_kit_log(DEBUG_SCSI, "t=%p, priv_size=%d", t, priv_size); + + static int free = 1; + + /* XXX we not some extra space for hostdata[] */ + static char buffer[4096] __attribute__((aligned(4096))); + static struct Scsi_Host *host = (struct Scsi_Host *)buffer; + + /* FIXME we support only one host for now */ + if (!free) return 0; + free = 0; + + host->host_lock = &host->default_lock; + spin_lock_init(host->host_lock); + + host->host_no = 13; + host->max_id = 8; + host->hostt = t; + +// rval = scsi_setup_command_freelist(shost); +// if (rval) +// goto fail_kfree; + +// shost->ehandler = kthread_run(scsi_error_handler, shost, +// "scsi_eh_%d", shost->host_no); +// if (IS_ERR(shost->ehandler)) { +// rval = PTR_ERR(shost->ehandler); +// goto fail_destroy_freelist; +// } + + return host; +} + + +static struct page *_page(struct scsi_cmnd *cmnd) +{ + return (struct page *)cmnd->sdb.table.sgl->page_link; +} + + +void scsi_alloc_buffer(size_t size, struct scsi_cmnd *cmnd) +{ + scsi_setup_buffer(cmnd, size, 0, 0); + struct scatterlist *sgl = cmnd->sdb.table.sgl; + struct page *page = _page(cmnd); + page->virt = kmalloc(size, 0); + page->phys = dma_map_single_attrs(0, page->virt, 0, 0, 0); + sgl->dma_address = page->phys; +} + + +void scsi_setup_buffer(struct scsi_cmnd *cmnd, size_t size, void *virt, dma_addr_t addr) +{ + cmnd->sdb.table.nents = 1; + cmnd->sdb.length = size; + + struct scatterlist *sgl = cmnd->sdb.table.sgl; + + struct page *page = _page(cmnd); + page->virt = virt; + page->phys = addr; + + sgl->page_link = (unsigned long)page; + sgl->offset = 0; + sgl->length = size; + sgl->dma_address = addr; + sgl->last = 1; +} + + +void scsi_free_buffer(struct scsi_cmnd *cmnd) +{ + struct page *page = _page(cmnd); + if (page) + kfree(page->virt); +} + + +void *scsi_buffer_data(struct scsi_cmnd *cmnd) +{ + return _page(cmnd)->virt; +} + + +struct scsi_cmnd *_scsi_alloc_command() +{ + struct scsi_cmnd *cmnd = (struct scsi_cmnd *)kmalloc(sizeof(struct scsi_cmnd), GFP_KERNEL); + cmnd->sdb.table.sgl = (struct scatterlist *)kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + cmnd->cmnd = kzalloc(MAX_COMMAND_SIZE, 0); + cmnd->sdb.table.sgl->page_link = (unsigned long) kzalloc(sizeof(struct page), 0); + return cmnd; +} + + +void _scsi_free_command(struct scsi_cmnd *cmnd) +{ + kfree((void *)cmnd->sdb.table.sgl->page_link); + kfree(cmnd->sdb.table.sgl); + kfree(cmnd->cmnd); + kfree(cmnd); +} + + +static void inquiry_done(struct scsi_cmnd *cmnd) +{ + char *data = (char *)scsi_buffer_data(cmnd); + dde_kit_printf("Vendor id: %c%c%c%c%c%c%c%c Product id: %s\n", + data[8], data[9], data[10], data[11], data[12], + data[13], data[14], data[15], &data[16]); + complete(cmnd->back); +} + + +static void scsi_done(struct scsi_cmnd *cmd) +{ + complete(cmd->back); +} + + +void scsi_scan_host(struct Scsi_Host *host) +{ + struct scsi_cmnd *cmnd; + struct scsi_device *sdev; + struct scsi_target *target; + struct completion compl; + void *result; + + init_completion(&compl); + + sdev = (struct scsi_device *)kmalloc(sizeof(struct scsi_device), GFP_KERNEL); + target = (struct scsi_target *)kmalloc(sizeof(struct scsi_target), GFP_KERNEL); + + cmnd = _scsi_alloc_command(); + + /* init device */ + sdev->sdev_target = target; + sdev->host = host; + sdev->id = 0; + sdev->lun = 0; + host->hostt->slave_alloc(sdev); + host->hostt->slave_configure(sdev); + + /* inquiry (36 bytes for usb) */ + scsi_alloc_buffer(sdev->inquiry_len, cmnd); + cmnd->cmnd[0] = INQUIRY; + cmnd->cmnd[4] = sdev->inquiry_len; + cmnd->device = sdev; + cmnd->cmd_len = 6; + cmnd->sc_data_direction = DMA_FROM_DEVICE; + + cmnd->back = &compl; + cmnd->scsi_done = inquiry_done; + + host->hostt->queuecommand(host, cmnd); + wait_for_completion(&compl); + + /* if PQ and PDT are zero we have a direct access block device conntected */ + result = scsi_buffer_data(cmnd); + if (!((char*)result)[0]) + scsi_add_device(sdev); + else { + kfree(sdev); + kfree(target); + } + + scsi_free_buffer(cmnd); + _scsi_free_command(cmnd); +} + + +/********************** + ** scsi/scsi_cmnd.h ** + **********************/ + +unsigned scsi_bufflen(struct scsi_cmnd *cmnd) { return cmnd->sdb.length; } +struct scatterlist *scsi_sglist(struct scsi_cmnd *cmnd) { return cmnd->sdb.table.sgl; } +unsigned scsi_sg_count(struct scsi_cmnd *cmnd) { return cmnd->sdb.table.nents; } diff --git a/dde_linux/src/drivers/usb/storage/scsi.h b/dde_linux/src/drivers/usb/storage/scsi.h new file mode 100644 index 000000000..6b9feb6e0 --- /dev/null +++ b/dde_linux/src/drivers/usb/storage/scsi.h @@ -0,0 +1,88 @@ +/* + * \brief SCSI helpers + * \author Sebastian Sumpf + * \date 2012-05-06 + */ + +/* + * 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. + */ + +#ifndef _SCSI_H_ +#define _SCSI_H_ + +struct scsi_cmnd; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Add a SCSI device + * + * \param sdev Device to add + */ +void scsi_add_device(struct scsi_device *sdev); + + +/** + * Alloc data buffer for command + * + * \param size Size of buffer + * \param cmnd Command to assciate buffer + */ +void scsi_alloc_buffer(size_t size, struct scsi_cmnd *cmnd); + + +/** + * Fill command + * + * \param cmnd Command buffer to setup + * \param size Data size + * \param virt Virtual address of buffer + * \param addr DMA address of buffer + */ +void scsi_setup_buffer(struct scsi_cmnd *cmnd, size_t size, void *virt, dma_addr_t addr); + + +/** + * Free data buffer of command + * + * \param cmnd Command + */ +void scsi_free_buffer(struct scsi_cmnd *cmnd); + + +/** + * Get buffer data for command + * + * \param cmnd Command to retrieve buffer pointer + * + * \return Buffer pointer + */ +void *scsi_buffer_data(struct scsi_cmnd *cmnd); + + +/** + * Allocate a SCSI command + * + * \return Allocated command or zero on failure + */ +struct scsi_cmnd *_scsi_alloc_command(); + + +/** + * Free a SCSI command + * + * \param cmnd Command + */ +void _scsi_free_command(struct scsi_cmnd *cmnd); + +#ifdef __cplusplus +} +#endif + +#endif /* _SCSI_H_ */ diff --git a/dde_linux/src/drivers/usb/storage/storage.cc b/dde_linux/src/drivers/usb/storage/storage.cc new file mode 100644 index 000000000..c47d5aadf --- /dev/null +++ b/dde_linux/src/drivers/usb/storage/storage.cc @@ -0,0 +1,177 @@ +/* + * \brief USB storage glue + * \author Sebastian Sumpf + * \date 2012-05-06 + */ + +/* + * 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. + */ + +#include +#include +#include +#include +#include + +#include + +#include "component.h" +#include "signal.h" +#include "scsi.h" + +static Signal_helper *_signal = 0; + +class Storage_device : public Genode::List::Element, + public Block::Device +{ + private: + + Genode::size_t _block_size; + Block::sector_t _block_count; + struct scsi_device *_sdev; + + static void _sync_done(struct scsi_cmnd *cmnd) { + complete((struct completion *)cmnd->back); } + + static void _async_done(struct scsi_cmnd *cmnd) + { + Block::Session_component *session = static_cast(cmnd->session); + Block::Packet_descriptor *packet = static_cast(cmnd->packet); + + if (verbose) + PDBG("ACK packet for block: %zu status: %d", packet->block_number(), cmnd->result); + + session->complete(*packet, true); + _scsi_free_command(cmnd); + } + + void _capacity() + { + struct completion comp; + + struct scsi_cmnd *cmnd = _scsi_alloc_command(); + + /* alloc data for command */ + scsi_alloc_buffer(8, cmnd); + + cmnd->cmnd[0] = READ_CAPACITY; + cmnd->cmd_len = 10; + cmnd->device = _sdev; + cmnd->sc_data_direction = DMA_FROM_DEVICE; + + init_completion(&comp); + cmnd->back = ∁ + cmnd->scsi_done = _sync_done; + + _sdev->host->hostt->queuecommand(_sdev->host, cmnd); + wait_for_completion(&comp); + + Genode::uint32_t *data = (Genode::uint32_t *)scsi_buffer_data(cmnd); + _block_count = bswap(data[0]); + _block_size = bswap(data[1]); + + /* if device returns the highest block number */ + if (!_sdev->fix_capacity) + _block_count++; + + if (verbose) + PDBG("block size: %zu block count: %llu", _block_size, _block_count); + + scsi_free_buffer(cmnd); + _scsi_free_command(cmnd); + } + + + Storage_device(struct scsi_device *sdev) : _sdev(sdev) + { + /* read device capacity */ + _capacity(); + } + + public: + + static Storage_device *add(struct scsi_device *sdev) { + return new (Genode::env()->heap()) Storage_device(sdev); } + + Genode::size_t block_size() { return _block_size; } + Genode::size_t block_count() { return _block_count; } + + void io(Block::Session_component *session, Block::Packet_descriptor &packet, + Genode::addr_t virt, Genode::addr_t phys) + { + Block::sector_t block_nr = packet.block_number(); + Genode::uint16_t block_count = packet.block_count() & 0xffff; + bool read = packet.operation() == Block::Packet_descriptor::WRITE ? false : true; + + if (block_nr > _block_count) + throw -1; + + if (verbose) + PDBG("PACKET: phys: %lx block: %llu count: %u %s", + phys, block_nr, block_count, read ? "read" : "write"); + + struct scsi_cmnd *cmnd = _scsi_alloc_command(); + + cmnd->cmnd[0] = read ? READ_10 : WRITE_10; + cmnd->cmd_len = 10; + cmnd->device = _sdev; + cmnd->sc_data_direction = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + cmnd->scsi_done = _async_done; + + Block::Packet_descriptor *p = new (Genode::env()->heap()) Block::Packet_descriptor(); + *p = packet; + cmnd->packet = (void *)p; + cmnd->session = (void *)session; + + Genode::uint32_t be_block_nr = bswap(block_nr); + Genode::memcpy(&cmnd->cmnd[2], &be_block_nr, 4); + + /* transfer one block */ + Genode::uint16_t be_block_count = bswap(block_count); + Genode::memcpy(&cmnd->cmnd[7], &be_block_count, 2); + + /* setup command */ + scsi_setup_buffer(cmnd, block_count * _block_size, (void *)virt, phys); + + /* + * Required by 'last_sector_hacks' in 'drivers/usb/storage/transprot.c + */ + struct request req; + req.rq_disk = 0; + cmnd->request = &req; + + /* send command to host driver */ + if (_sdev->host->hostt->queuecommand(_sdev->host, cmnd)) { + throw -2; + } + } +}; + + +void Storage::init(Genode::Signal_receiver *recv) { + _signal = new (Genode::env()->heap()) Signal_helper(recv); } + + +void scsi_add_device(struct scsi_device *sdev) +{ + using namespace Genode; + static bool announce = false; + + Storage_device *device = Storage_device::add(sdev); + + /* + * XXX move to 'main' + */ + if (!announce) { + static Cap_connection cap_stor; + static Rpc_entrypoint ep_stor(&cap_stor, 4096, "usb_stor_ep"); + static Block::Root root(&ep_stor, env()->heap(), _signal->receiver(), device); + env()->parent()->announce(ep_stor.manage(&root)); + announce = true; + } +} + diff --git a/dde_linux/src/drivers/usb/target.mk b/dde_linux/src/drivers/usb/target.mk new file mode 100644 index 000000000..59642fda8 --- /dev/null +++ b/dde_linux/src/drivers/usb/target.mk @@ -0,0 +1,92 @@ +TARGET = usb_drv +REQUIRES = x86 32bit +LIBS = cxx env dde_kit server libc-setjmp signal +SRC_CC = main.cc lx_emul.cc pci_driver.cc irq.cc timer.cc event.cc storage.cc \ + input_component.cc +SRC_C = dummies.c scsi.c evdev.c + +CONTRIB_DIR := $(REP_DIR)/contrib +DRIVERS_DIR := $(CONTRIB_DIR)/drivers +USB_DIR := $(DRIVERS_DIR)/usb + +# +# The order of include-search directories is important, we need to look into +# 'contrib' before falling back to our custom 'lx_emul.h' header. +# +INC_DIR += $(PRG_DIR) +INC_DIR += $(CONTRIB_DIR)/include +INC_DIR += $(shell pwd) + +CC_OPT += -U__linux__ -D__KERNEL__ +CC_OPT += -DCONFIG_USB_DEVICEFS -DCONFIG_HOTPLUG -DCONFIG_PCI -DDEBUG + +CC_WARN = -Wall -Wno-unused-variable -Wno-uninitialized \ + -Wno-unused-function \ + +CC_C_OPT += -Wno-implicit-function-declaration -Wno-unused-but-set-variable \ + -Wno-pointer-sign + +# +# Suffix of global 'module_init' function +# +MOD_SUFFIX = +CC_OPT += -DMOD_SUFFIX=$(MOD_SUFFIX) + +# USB core +SRC_C += $(addprefix usb/core/,$(notdir $(wildcard $(USB_DIR)/core/*.c))) +SRC_C += usb/usb-common.c + +# USB host-controller driver +#SRC_C += $(addprefix usb/host/,uhci-hcd.c pci-quirks.c ehci-hcd.c ohci-hcd.c) +SRC_C += $(addprefix usb/host/,pci-quirks.c uhci-hcd.c ehci-hcd.c) + +# USB hid +SRC_C += $(addprefix hid/usbhid/,hid-core.c hid-quirks.c usbmouse.c usbkbd.c) +SRC_C += hid/hid-input.c hid/hid-core.c input/evdev.c input/input.c + +# USB storage +SRC_C += $(addprefix usb/storage/,scsiglue.c protocol.c transport.c usb.c \ + initializers.c option_ms.c sierra_ms.c usual-tables.c) + +# SCSI +SRC_C += $(addprefix scsi/,scsi.c constants.c) + +# +# Determine the header files included by the contrib code. For each +# of these header files we create a symlink to 'lx_emul.h'. +# +GEN_INCLUDES := $(shell grep -rh "^\#include .*\/" $(CONTRIB_DIR) |\ + sed "s/^\#include *[<\"]\(.*\)[>\"].*/\1/" | sort | uniq) + +# +# Filter out some black-listed headers +# +NO_GEN_INCLUDES := ../../scsi/sd.h + +# +# Filter out original Linux headers that exist in the contrib directory +# +NO_GEN_INCLUDES := $(shell cd $(CONTRIB_DIR)/include; find -name "*.h" | sed "s/.\///") +GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES)) + +# +# Make sure to create the header symlinks prior building +# +$(SRC_C:.c=.o) $(SRC_CC:.cc=.o): $(GEN_INCLUDES) + +# +# Add prefix, since there are two hid-core.c with the same module init function +# +hid/hid-core.o: MOD_SUFFIX="_core" + +$(GEN_INCLUDES): + $(VERBOSE)mkdir -p $(dir $@) + $(VERBOSE)ln -s $(REP_DIR)/src/drivers/usb/lx_emul.h $@ + +vpath %.c $(DRIVERS_DIR) +vpath %.c $(USB_DIR)/host +vpath %.cc $(PRG_DIR)/signal +vpath %.c $(PRG_DIR)/input +vpath %.cc $(PRG_DIR)/input +vpath %.cc $(PRG_DIR)/storage +vpath %.c $(PRG_DIR)/storage diff --git a/os/include/block_session/block_session.h b/os/include/block_session/block_session.h index be3c1e768..df8d34b43 100644 --- a/os/include/block_session/block_session.h +++ b/os/include/block_session/block_session.h @@ -30,6 +30,11 @@ namespace Block { + /** + * Sector type for block session + */ + typedef Genode::uint64_t sector_t; + /** * Represents an operation request with respect to a block, * the data associated with the 'Packet_descriptor' is either diff --git a/os/include/block_session/rpc_object.h b/os/include/block_session/rpc_object.h index accce5c1a..4412093ee 100644 --- a/os/include/block_session/rpc_object.h +++ b/os/include/block_session/rpc_object.h @@ -22,7 +22,7 @@ namespace Block { class Session_rpc_object : public Genode::Rpc_object { - private: + protected: Packet_stream_tx::Rpc_object _tx; diff --git a/tool/builddir/etc/build.conf.drivers_x86 b/tool/builddir/etc/build.conf.drivers_x86 index 32b673a26..98bcceda0 100644 --- a/tool/builddir/etc/build.conf.drivers_x86 +++ b/tool/builddir/etc/build.conf.drivers_x86 @@ -1,9 +1,18 @@ # -# Drivers ported from the Linux kernel +# Drivers ported from the Linux kernel (USB) # # Not supported on the ARM architecture. # +#REPOSITORIES += $(GENODE_DIR)/dde_linux + +# +# Additional drivers ported from the Linux kernel (audio, Intel GEM) +# +# Not supported on the ARM architecture. +# +# This repository is deprecated. +# #REPOSITORIES += $(GENODE_DIR)/linux_drivers #