Index: elec/CrO2/software/Makefile
===================================================================
--- elec/CrO2/software/Makefile	(revision 4a558d7140b85ad5e63c3387d5e8d66518e429b8)
+++ elec/CrO2/software/Makefile	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -2,19 +2,31 @@
 
 ifdef WINDIR
-	# windows
-USBFLAGS = -I/local/include
-USBLIBS = -L/local/lib -lusb
-EXE_SUFFIX = .exe
+  # windows
+  USBFLAGS = -I/local/include
+  USBLIBS = -L/local/lib -lusb
+  USBOBJS = device_libusb.o
+  IUPFLAGS = -mthreads
+  IUPLIBS = -lcomctl32 -lole32 -mthreads -mwindows
+  EXE_SUFFIX = .exe
 else
-	# some unix
-USBFLAGS = `libusb-config --cflags`
-USBLIBS = `libusb-config --libs` #-framework CoreFoundation
-EXE_SUFFIX =
+  ifdef BE_HOST_CPU
+    # Haiku
+    IUPFLAGS = -I/FileMate/Dev/tecgraf/iup/include/
+    IUPLIBS=-L/FileMate/Dev/tecgraf/iup/lib/Haiku11/
+    USBOBJS = device_bekit.o
+    USBLIBS = -ldevice
+  else
+    # some unix
+    USBFLAGS = $(shell libusb-config --cflags)
+    USBLIBS = $(shell libusb-config --libs)
+    USBOBJS = device_libusb.o
+    IUPFLAGS = -I/usr/include/IUP/
+  endif
+  EXE_SUFFIX =
 endif
 
 CC		= g++
-CPPFLAGS = $(USBFLAGS) -Os -Wall -I/local/include -std=c++0x -mthreads
-LIBS = $(USBLIBS) -Os -mwindows -liup -liupimglib -liupcontrols -liupcd -lcd \
-	-lfreetype -lz -lcomctl32 -lole32 -mthreads
+CPPFLAGS = $(USBFLAGS) -Os -Wall $(IUPFLAGS) -I/local/include -std=c++0x
+LIBS = $(USBLIBS) -Os $(IUPLIBS) -liup -liupcontrols -liupcd -lcd -lfreetype -lz
 
 PROJECT = CrO2
@@ -24,5 +36,5 @@
 all: $(PROGRAM)
 
-$(PROGRAM): $(PROJECT).o device.o gui.o k5.o Tape.o zxtape.o
+$(PROGRAM): cro2.o device.o gui.o k5.o Tape.o zxtape.o $(USBOBJS)
 	$(CC) -o $(PROGRAM) $^ $(LIBS)
 
Index: elec/CrO2/software/Tape.cpp
===================================================================
--- elec/CrO2/software/Tape.cpp	(revision 4a558d7140b85ad5e63c3387d5e8d66518e429b8)
+++ elec/CrO2/software/Tape.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -7,5 +7,5 @@
 #include "Tape.h"
 
-#include "K5.h"
+#include "k5.h"
 #include "zxtape.h"
 
Index: elec/CrO2/software/Tape.h
===================================================================
--- elec/CrO2/software/Tape.h	(revision 4a558d7140b85ad5e63c3387d5e8d66518e429b8)
+++ elec/CrO2/software/Tape.h	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -4,5 +4,6 @@
  * Distributed under the terms of the MIT licence.
  */
-#pragma once
+#ifndef __TAPE_H__
+#define __TAPE_H__
 
 #include <stdint.h>
@@ -42,2 +43,5 @@
 		std::vector<Block*> blocks;
 };
+
+#endif
+
Index: elec/CrO2/software/cro2.cpp
===================================================================
--- elec/CrO2/software/cro2.cpp	(revision 4a558d7140b85ad5e63c3387d5e8d66518e429b8)
+++ elec/CrO2/software/cro2.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -32,5 +32,6 @@
 			memset(buffer, 0, 275);
 			nBytes = dev.read(buffer, sizeof(buffer));
-			if (nBytes < 0) fprintf(stderr, "USB error %s\n", usb_strerror());
+			// FIXME move error gathering to Device (and throw the string maybe ?)
+			//if (nBytes < 0) fprintf(stderr, "USB error %s\n", usb_strerror());
 		}else if(strcmp(argv[1], "put") == 0){
 
Index: elec/CrO2/software/device.cpp
===================================================================
--- elec/CrO2/software/device.cpp	(revision 4a558d7140b85ad5e63c3387d5e8d66518e429b8)
+++ elec/CrO2/software/device.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -1,14 +1,17 @@
 /* CrO2 datassette emulator
- * Copyright 2012, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
+ * Copyright 2013, Adrien Destugues <pulkomandy@pulkomandy.tk>
  *
  * Distributed under the terms of the MIT licence.
  *
- * Handles device communication through libusb
+ * High-level device management functions shared by all implementations.
  */
 
 #include "device.h"
 #include "k5.h"
+#include "Tape.h"
 
 #include <typeinfo>
+#include <unistd.h>
+
 
 bool Device::initOnce = false;
@@ -17,133 +20,6 @@
 const uint32_t Device::vid = 0x16C0;
 const uint32_t Device::pid = 0x05DC;
-const char* Device::vendor = "pulkomandy.ath.cx";
+const char* Device::vendor = "pulkomandy.ath.cx"; // FIXME update
 const char* Device::product = "CrO2";
-
-/* These are the vendor specific commands implemented by our USB device */
-#define PSCMD_CONFIG  0
-#define PSCMD_GET   1
-#define PSCMD_PUT   2
-#define PSCMD_STATUS   3
-
-
-// Gets the device instance. Throws an error message if something bad happens.
-Device& Device::getDevice() throw(const char*)
-{
-	// If Device constructor throws an exception, instance is not initialized.
-	// So, the constructor will be called again at next getDevice call, until
-	// it succeeds.
-	if (instance == NULL)
-		instance = new Device();
-
-	return *instance;
-}
-
-
-/* USB device lookup by VID and PID, then Vendor and Product strings, as we use
- * V-USB shared ID. */
-static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid,
-	char *buf, int buflen)
-{
-char    buffer[256];
-int     rval, i;
-
-    if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
-			(USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0)
-        return rval;
-    if(buffer[1] != USB_DT_STRING)
-        return 0;
-    if((unsigned char)buffer[0] < rval)
-        rval = (unsigned char)buffer[0];
-    rval /= 2;
-    /* lossy conversion to ISO Latin1 */
-    for(i=1;i<rval;i++){
-        if(i > buflen)  /* destination buffer overflow */
-            break;
-        buf[i-1] = buffer[2 * i];
-        if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
-            buf[i-1] = '?';
-    }
-    buf[i-1] = 0;
-    return i-1;
-}
-
-Device::Device() throw(const char*)
-{
-	handle = NULL;
-
-	if (!initOnce)
-	{
-		initOnce = true;
-		usb_init();
-	}
-
-    usb_find_busses();
-    usb_find_devices();
-
-    for(struct usb_bus* bus=usb_get_busses(); bus; bus=bus->next)
-	{
-		for(struct usb_device* dev=bus->devices; dev; dev=dev->next)
-		{
-			if(dev->descriptor.idVendor != vid || dev->descriptor.idProduct != pid)
-				continue;
-
-			// Found device with correct VID and PID. Now try to match the 
-			// vendor and product strings
-			char    string[256];
-			int     len;
-			handle = usb_open(dev);
-				/* we need to open the device in order to query strings */
-			if(!handle){
-				continue;
-			}
-			/* now check whether the names match: */
-			len = usbGetStringAscii(handle, dev->descriptor.iManufacturer,
-				0x0409, string, sizeof(string));
-			if(len >= 0)
-			{
-				if(strcmp(string, vendor) == 0){
-					len = usbGetStringAscii(handle, dev->descriptor.iProduct,
-						0x0409, string, sizeof(string));
-					if(len >= 0){
-						if(strcmp(string, product) == 0)
-							break;
-					}
-				}
-			}
-			usb_close(handle);
-			handle = NULL;
-		}
-		if(handle)
-			break;
-	}
-
-	// At this point, either we have found a device and handle is pointing to it,
-	// or we failed and handle is NULL.
-	if (!handle)
-		throw "Device not found. Is the USB cable plugged correctly?";
-}
-
-
-Device::~Device()
-{
-	usb_close(handle);
-}
-
-
-int Device::read(uint8_t* buffer, size_t max)
-{
-	return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
-		PSCMD_GET, 0,0, (char*)buffer, max, 5000);
-
-}
-
-
-int Device::write(const uint8_t* buffer, size_t size, int blktype)
-{
-	int rqtype = (size == 0) ? USB_ENDPOINT_IN:USB_ENDPOINT_OUT;
-	return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | rqtype,
-		PSCMD_PUT, blktype,0 /*checksum*/, (char*)buffer, size, 5000);
-
-}
 
 
@@ -154,5 +30,5 @@
 		// wait for motor on
 		while (getStatus() & 8)
-			Sleep(1000);
+			usleep(1000 * 1000);
 
 		const Tape::Block& block = file.getBlock(k);
@@ -166,14 +42,6 @@
 
 		// TODO wait for correct time (read status from usb OR compute from size+type)
-		Sleep(1400);
+		usleep(1400 * 1000);
 	}
 }
 
-uint8_t Device::getStatus()
-{
-	uint8_t status;
-	usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
-			PSCMD_STATUS, 0,0, (char*)&status, 1, 5000);
-		// TODO handle errors (return value)
-	return status;
-}
Index: elec/CrO2/software/device.h
===================================================================
--- elec/CrO2/software/device.h	(revision 4a558d7140b85ad5e63c3387d5e8d66518e429b8)
+++ elec/CrO2/software/device.h	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -8,5 +8,5 @@
 
 #include <stdint.h>
-#include <lusb0_usb.h>
+#include <string.h>
 
 class Tape;
@@ -15,22 +15,24 @@
 {
 	public:
+		// Implemented in subclasses object files. Only one of them is linked
+		// and takes care of instanciating itself.
 		static Device& getDevice() throw(const char*);
 
-		~Device();
+		// High-level layer (will call functions below)
+		void write(const Tape& file) throw (const char*);
 
-		int read(uint8_t* buffer, size_t max); // Fill the buffer with data from device
-		int write(const uint8_t* buffer, size_t size, int blktype);
-		void write(const Tape& file) throw (const char*);
-		uint8_t getStatus();
+		// Low-level layer (to be implemented by subclasses
+		virtual int read(uint8_t* buffer, size_t max) = 0;
+			// Fill the buffer with data from device
+		virtual int write(const uint8_t* buffer, size_t size, int blktype) = 0;
+		virtual uint8_t getStatus() = 0;
+			// Get the status word from the device
 
-	private:
-		Device() throw(const char*); // Open device and set it up for communication
-		Device(const Device& other);
-
-
-		usb_dev_handle* handle;
-
-		static bool initOnce;
-		static Device* instance;
+	protected:
+		/* These are the vendor specific commands implemented by our USB device */
+		static const int PSCMD_CONFIG = 0;
+		static const int PSCMD_GET = 1;
+		static const int PSCMD_PUT = 2;
+		static const int PSCMD_STATUS = 3;
 
 		static const uint32_t vid;
@@ -38,3 +40,6 @@
 		static const char* vendor;
 		static const char* product;
+	private:
+		static bool initOnce;
+		static Device* instance;
 };
Index: elec/CrO2/software/device_bekit.cpp
===================================================================
--- elec/CrO2/software/device_bekit.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
+++ elec/CrO2/software/device_bekit.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -0,0 +1,102 @@
+/* CrO2 datassette emulator
+ * Copyright 2013, Adrien Destugues <pulkomandy@pulkomandy.tk>
+ *
+ * Distributed under the terms of the MIT licence.
+ *
+ * Handles device communication through libusb
+ */
+
+#include "device_bekit.h"
+#include "k5.h"
+
+#include <typeinfo>
+#include <USBKit.h>
+
+
+// Gets the device instance. Throws an error message if something bad happens.
+Device& Device::getDevice() throw(const char*)
+{
+	if (instance == NULL) {
+		instance = new HaikuDevice();
+	}
+
+	return *instance;
+}
+
+
+HaikuDevice::HaikuDevice() throw(const char*)
+{
+	// At this point, either we have found a device and handle is pointing to it,
+	// or we failed and handle is NULL.
+	if (!handle)
+		throw "Device not found. Is the USB cable plugged correctly?";
+}
+
+
+HaikuDevice::~HaikuDevice()
+{
+	delete handle;
+}
+
+
+int HaikuDevice::read(uint8_t* buffer, size_t max)
+{
+	return handle->ControlTransfer(USB_REQTYPE_VENDOR | USB_REQTYPE_ENDPOINT_IN,
+		PSCMD_GET, 0,0, max, (char*)buffer);
+
+}
+
+
+int HaikuDevice::write(const uint8_t* buffer, size_t size, int blktype)
+{
+	int rqtype = (size == 0) ? USB_REQTYPE_ENDPOINT_IN:USB_REQTYPE_ENDPOINT_OUT;
+	return handle->ControlTransfer(USB_REQTYPE_VENDOR | rqtype,
+		PSCMD_PUT, blktype,0 /*checksum*/, size, (char*)buffer);
+
+}
+
+
+uint8_t HaikuDevice::getStatus()
+{
+	uint8_t status;
+	handle->ControlTransfer(USB_REQTYPE_VENDOR | USB_REQTYPE_ENDPOINT_IN,
+			PSCMD_STATUS, 0,0, 1, (char*)&status);
+		// TODO handle errors (return value)
+	return status;
+}
+
+
+status_t HaikuDevice::DeviceAdded(BUSBDevice* device)
+{
+	if (handle != NULL) {
+		// We already have a device !
+		return B_ERROR;
+	}
+
+	// Check if the device matches what we can handle
+	
+	if (device->VendorID() != vid && device->ProductID() != pid)
+		return B_ERROR;
+
+	// Since we use V-USB shared vid/pid pair, we also have to check the
+	// manufacturer and product strings to actually identify the device amongst
+	// other users of the pair.
+	if (strcmp(device->ManufacturerString(), vendor) != 0)
+		return B_ERROR;
+
+	if (strcmp(device->ProductString(), product) != 0)
+		return B_ERROR;
+
+	// Ok, we have found our device !
+	handle = device;
+	return B_OK;
+}
+
+
+void HaikuDevice::DeviceRemoved(BUSBDevice* device)
+{
+	// This is only called for devices we accepted in DeviceAdded. We accept
+	// only one, so we can safely remove it.
+	handle = NULL;
+}
+
Index: elec/CrO2/software/device_bekit.h
===================================================================
--- elec/CrO2/software/device_bekit.h	(revision e017851e1d36b1973f286e248d24668462f91445)
+++ elec/CrO2/software/device_bekit.h	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -0,0 +1,38 @@
+/* CrO2 datassette emulator
+ * Copyright 2013, Adrien Destugues <pulkomandy@pulkomandy.tk>
+ *
+ * Distributed under the terms of the MIT licence.
+ *
+ * Handles device communication through Haiku USB Kit
+ */
+
+#include "device.h"
+
+#include <stdint.h>
+#include <USBKit.h>
+
+class Tape;
+
+class HaikuDevice: public Device, BUSBRoster
+{
+	public:
+		~HaikuDevice();
+
+		// Device
+		int read(uint8_t* buffer, size_t max);
+			// Fill the buffer with data from device
+		int write(const uint8_t* buffer, size_t size, int blktype);
+		uint8_t getStatus();
+
+		// BUSBRoster
+		status_t DeviceAdded(BUSBDevice* device);
+		void DeviceRemoved(BUSBDevice* device);
+	private:
+		HaikuDevice() throw(const char*);
+			// Open device and set it up for communication
+		HaikuDevice(const Device& other);
+
+		BUSBDevice* handle;
+
+		friend Device& Device::getDevice();
+};
Index: elec/CrO2/software/device_libusb.cpp
===================================================================
--- elec/CrO2/software/device_libusb.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
+++ elec/CrO2/software/device_libusb.cpp	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -0,0 +1,154 @@
+/* CrO2 datassette emulator
+ * Copyright 2012, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
+ *
+ * Distributed under the terms of the MIT licence.
+ *
+ * Handles device communication through libusb
+ */
+
+#include "device_libusb.h"
+#include "k5.h"
+
+#include <typeinfo>
+
+bool Device::initOnce = false;
+Device* Device::instance = NULL;
+
+const uint32_t Device::vid = 0x16C0;
+const uint32_t Device::pid = 0x05DC;
+const char* Device::vendor = "pulkomandy.ath.cx";
+const char* Device::product = "CrO2";
+
+/* These are the vendor specific commands implemented by our USB device */
+#define PSCMD_CONFIG  0
+#define PSCMD_GET   1
+#define PSCMD_PUT   2
+#define PSCMD_STATUS   3
+
+
+// Gets the device instance. Throws an error message if something bad happens.
+Device& Device::getDevice() throw(const char*)
+{
+	if (instance == NULL)
+		instance = new LibUsbDevice();
+
+	return *instance;
+}
+
+
+/* USB device lookup by VID and PID, then Vendor and Product strings, as we use
+ * V-USB shared ID. */
+static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid,
+	char *buf, int buflen)
+{
+char    buffer[256];
+int     rval, i;
+
+    if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+			(USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0)
+        return rval;
+    if(buffer[1] != USB_DT_STRING)
+        return 0;
+    if((unsigned char)buffer[0] < rval)
+        rval = (unsigned char)buffer[0];
+    rval /= 2;
+    /* lossy conversion to ISO Latin1 */
+    for(i=1;i<rval;i++){
+        if(i > buflen)  /* destination buffer overflow */
+            break;
+        buf[i-1] = buffer[2 * i];
+        if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
+            buf[i-1] = '?';
+    }
+    buf[i-1] = 0;
+    return i-1;
+}
+
+LibUsbDevice::LibUsbDevice() throw(const char*)
+{
+	handle = NULL;
+
+	if (!initOnce)
+	{
+		initOnce = true;
+		usb_init();
+	}
+
+    usb_find_busses();
+    usb_find_devices();
+
+    for(struct usb_bus* bus=usb_get_busses(); bus; bus=bus->next)
+	{
+		for(struct usb_device* dev=bus->devices; dev; dev=dev->next)
+		{
+			if(dev->descriptor.idVendor != vid || dev->descriptor.idProduct != pid)
+				continue;
+
+			// Found device with correct VID and PID. Now try to match the 
+			// vendor and product strings
+			char    string[256];
+			int     len;
+			handle = usb_open(dev);
+				/* we need to open the device in order to query strings */
+			if(!handle){
+				continue;
+			}
+			/* now check whether the names match: */
+			len = usbGetStringAscii(handle, dev->descriptor.iManufacturer,
+				0x0409, string, sizeof(string));
+			if(len >= 0)
+			{
+				if(strcmp(string, vendor) == 0){
+					len = usbGetStringAscii(handle, dev->descriptor.iProduct,
+						0x0409, string, sizeof(string));
+					if(len >= 0){
+						if(strcmp(string, product) == 0)
+							break;
+					}
+				}
+			}
+			usb_close(handle);
+			handle = NULL;
+		}
+		if(handle)
+			break;
+	}
+
+	// At this point, either we have found a device and handle is pointing to it,
+	// or we failed and handle is NULL.
+	if (!handle)
+		throw "Device not found. Is the USB cable plugged correctly?";
+}
+
+
+LibUsbDevice::~LibUsbDevice()
+{
+	usb_close(handle);
+}
+
+
+int LibUsbDevice::read(uint8_t* buffer, size_t max)
+{
+	return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
+		PSCMD_GET, 0,0, (char*)buffer, max, 5000);
+
+}
+
+
+int LibUsbDevice::write(const uint8_t* buffer, size_t size, int blktype)
+{
+	int rqtype = (size == 0) ? USB_ENDPOINT_IN:USB_ENDPOINT_OUT;
+	return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | rqtype,
+		PSCMD_PUT, blktype,0 /*checksum*/, (char*)buffer, size, 5000);
+
+}
+
+
+uint8_t LibUsbDevice::getStatus()
+{
+	uint8_t status;
+	usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
+			PSCMD_STATUS, 0,0, (char*)&status, 1, 5000);
+		// TODO handle errors (return value)
+	return status;
+}
Index: elec/CrO2/software/device_libusb.h
===================================================================
--- elec/CrO2/software/device_libusb.h	(revision e017851e1d36b1973f286e248d24668462f91445)
+++ elec/CrO2/software/device_libusb.h	(revision e017851e1d36b1973f286e248d24668462f91445)
@@ -0,0 +1,31 @@
+/* CrO2 datassette emulator
+ * Copyright 2012, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
+ *
+ * Distributed under the terms of the MIT licence.
+ *
+ * Handles device communication through libusb
+ */
+
+#include <stdint.h>
+#include <lusb0_usb.h>
+
+class Tape;
+
+class LibUSBDevice: public Device
+{
+	public:
+		~LibUSBDevice();
+
+		int read(uint8_t* buffer, size_t max);
+			// Fill the buffer with data from device
+		int write(const uint8_t* buffer, size_t size, int blktype);
+		uint8_t getStatus();
+
+	private:
+		LibUSBDevice() throw(const char*);
+			// Open device and set it up for communication
+		LibUSBDevice(const Device& other);
+
+
+		usb_dev_handle* handle;
+};
