BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / 1628fcfdfdf2978ed9ccac96ee7d13bb3dc43a01

// Related

Orion

Barry Keyboard/Mouse drivers + POSIX names for structs 1628fcf (2 years, 4 months ago)
diff --git a/drivers/drivers.c b/drivers/drivers.c
index 5ae8c4b..1a2fa8d 100644
--- a/drivers/drivers.c
+++ b/drivers/drivers.c
@@ -29,6 +29,9 @@ Device devices[] = {
 	{0x10ec, 0x8139, "Realtek RTL8139 10/100 NIC", rtl8139_init},
 	{0x8086, 0x100e, "Intel Pro 1000/MT NIC", NULL},
 
+	/* Virtual devices */
+	{0x1b36, 0x000d, "QEMU XHCI Host Adapter", xhci_init},
+
 	/* VGA devices */
 	{0x1234, 0x1111, "QEMU/Bochs VBE Framebuffer", bga_init},
 };
@@ -76,6 +79,7 @@ init_drivers(void)
 {
 	uint16_t bus, slot, func;
 	uint16_t vendor, device;
+	uint8_t class, subclass;
 	uint32_t dev;
 	kprintf("Enumerating PCI devices");
 	for (bus = 0; bus < 256; bus++)
@@ -95,8 +99,11 @@ init_drivers(void)
 		}
 		if (devices[dev].vendor != vendor
 		 || devices[dev].device != device) {
-			kprintf("  PCI(%d,%d,%d) = %#x:%#x",
-			        bus, slot, func, vendor, device);
+			class = pci_read_byte(bus, slot, func, 11);
+			subclass = pci_read_byte(bus, slot, func, 10);
+			kprintf("  PCI(%d,%d,%d) = %#.4x:%#.4x (%#.2x, %#.2x)",
+			        bus, slot, func, vendor, device,
+			        class, subclass);
 		}
 	}
 }
diff --git a/drivers/drivers.h b/drivers/drivers.h
index 47cd243..be7e396 100644
--- a/drivers/drivers.h
+++ b/drivers/drivers.h
@@ -25,6 +25,10 @@ void register_driver(Driver *driver);
 /* Drivers */
 void ide_init(uint8_t bus, uint8_t slot, uint8_t func);
 void rtl8139_init(uint8_t bus, uint8_t dev, uint8_t func);
+void xhci_init(uint8_t bus, uint8_t slot, uint8_t func);
 void bga_init(uint8_t bus, uint8_t slot, uint8_t func);
+void init_tty(void);
+void init_kbd(void);
+void init_mouse(void);
 
 #endif
diff --git a/drivers/keyboard/keyboard.c b/drivers/keyboard/keyboard.c
new file mode 100644
index 0000000..5ef3c6f
--- /dev/null
+++ b/drivers/keyboard/keyboard.c
@@ -0,0 +1,108 @@
+/*
+ * This file implements a keyboard driver.  It generates the /dev/kbd device
+ * file, which can be read and returns a structure of the keyboard data.  This
+ * driver produces raw keyboard data, not parsed text.
+ */
+
+#include <sys/kbd.h>
+#include "../drivers.h"
+#include "../../task/task.h"
+#include "../../proc/proc.h"
+#include "../../io.h"
+
+void tty_keypress(unsigned char key);
+size_t kbd_read(File *file, char *buf, size_t size, off_t offset);
+
+FileOps kbdFileOps = {
+	.read = kbd_read,
+};
+
+Driver kbdDriver = {
+	.major = 10,
+	.ops = &kbdFileOps,
+	.next = NULL,
+};
+
+TaskQueue keyWait;
+
+/* Ring buffer for keys */
+struct KeyBuffer {
+	int start, end;
+	char key[1024];
+} keyBuf;
+
+/* Add a key to the key buffer */
+static void
+add_to_buf(char key)
+{
+	/* No more space in buffer */
+	int start = (keyBuf.start + sizeof(keyBuf.key) - 1)
+	          % sizeof(keyBuf.key);
+	if (keyBuf.end == start)
+		return;
+
+	keyBuf.key[keyBuf.end] = key;
+	keyBuf.end++;
+	keyBuf.end %= sizeof(keyBuf.key);
+}
+
+/* Get a key from the key buffer */
+static char
+get_from_buf(void)
+{
+	/* Nothing to read */
+	if (keyBuf.start == keyBuf.end)
+		return 0x00;
+
+	char key = keyBuf.key[keyBuf.start];
+	keyBuf.start++;
+	keyBuf.start %= sizeof(keyBuf.key);
+	return key;
+}
+
+/* Handle the keyboard interrupt */
+static void
+keyboard_handler(InterruptFrame *frame)
+{
+	unsigned char key;
+	int i;
+	for (i = 0; i < 1000; i++) {
+		if ((inb(0x64) & 1) == 0)
+			continue;
+		key = inb(0x60);
+		break;
+	}
+	if (i == 1000)
+		return;
+	add_to_buf(key);
+	tty_keypress(key);
+
+	for (Task *tmp = keyWait.start; tmp; tmp = tmp->next)
+		unblock_task(pop_from_queue(&keyWait));
+}
+
+/* Initialise the keyboard */
+void
+init_kbd(void)
+{
+	register_driver(&kbdDriver);
+	mknod("/dev/kbd", S_IFCHR | 0666, MKDEV(kbdDriver.major, 0));
+	register_interrupt(1, keyboard_handler);
+}
+
+size_t
+kbd_read(File *file, char *buf, size_t size, off_t offset)
+{
+	char c;
+	size_t count = 0;
+	while (count < size) {
+		c = get_from_buf();
+		if (!c) {
+			add_to_queue(&keyWait, current);
+			block_task(WAITING_FOR_IO);
+		}
+		*(buf + count) = c;
+		count++;
+	}
+	return count;
+}
diff --git a/drivers/mouse/mouse.c b/drivers/mouse/mouse.c
new file mode 100644
index 0000000..f32264e
--- /dev/null
+++ b/drivers/mouse/mouse.c
@@ -0,0 +1,116 @@
+/*
+ * This file contains the mouse driver.  It generates the /dev/mouse device
+ * file, which can be read and returns a structure of the mouse data.
+ */
+
+#include <sys/mouse.h>
+#include "../drivers.h"
+#include "../../proc/proc.h"
+#include "../../io.h"
+
+size_t mouse_read(File *file, char *buf, size_t size, off_t offset);
+
+FileOps mouseFileOps = {
+	.read = mouse_read,
+};
+
+Driver mouseDriver = {
+	.major = 11,
+	.ops = &mouseFileOps,
+	.next = NULL,
+};
+
+unsigned char mouseCycle = 0;
+char mouseByte[3], mouseX = 0, mouseY = 0;
+
+/* Handle the mouse interrupt */
+static void
+mouse_handler(InterruptFrame *frame)
+{
+	mouseByte[mouseCycle++] = inb(0x60);
+	if (mouseCycle < 3)
+		return;
+	mouseCycle = 0;
+	mouseX = mouseByte[1];
+	mouseY = mouseByte[2];
+
+//	kprintf("Mouse at [%d,%d]", mouseX, mouseY);
+}
+
+/* Wait on the mouse */
+static inline void
+mouse_io_wait(int type)
+{
+	int time = 100000;
+	if (!type) {
+		while (time--)
+			if ((inb(0x64) & 1) == 1)
+				return;
+	} else {
+		while (time--)
+			if ((inb(0x64) & 2) == 0)
+				return;
+	}
+}
+
+/* Write to the mouse */
+static inline void
+mouse_io_write(char byte)
+{
+	mouse_io_wait(1);
+	outb(0x64, 0xD4);
+	mouse_io_wait(1);
+	outb(0x60, byte);
+}
+
+/* Read from the mouse */
+static inline char
+mouse_io_read(void)
+{
+	mouse_io_wait(0);
+	return inb(0x60);
+}
+
+/* Initialise the mouse */
+void
+init_mouse(void)
+{
+	register_driver(&mouseDriver);
+	mknod("/dev/mouse", S_IFCHR | 0666, MKDEV(mouseDriver.major, 0));
+	register_interrupt(12, mouse_handler);
+
+	char status;
+	mouse_io_wait(1);
+	outb(0x64, 0xA8);
+
+	/* Enable interrupts */
+	mouse_io_wait(1);
+	outb(0x64, 0x20);
+	mouse_io_wait(0);
+	status = inb(0x60) | 2;
+	mouse_io_wait(1);
+	outb(0x64, 0x60);
+	mouse_io_wait(1);
+	outb(0x60, status);
+
+	/* Use default settings */
+	mouse_io_write(0xF6);
+	mouse_io_read();
+
+	/* Enable the mouse */
+	mouse_io_write(0xF4);
+	mouse_io_read();
+}
+
+/* Read the mouse device */
+size_t
+mouse_read(File *file, char *buf, size_t size, off_t offset)
+{
+	size_t count = 0;
+	while (count < size) {
+		*(buf + count++) = mouseByte[0];
+		*(buf + count++) = mouseX;
+		*(buf + count++) = mouseY;
+	}
+	return count;
+}
diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c
index c65aeaf..94b3fb3 100644
--- a/drivers/tty/tty.c
+++ b/drivers/tty/tty.c
@@ -1,5 +1,5 @@
 /*
- * This file contains the implementation of the TTY Device.  Generates a device
+ * This file contains the implementation of the TTY Device, generates a device
  * /dev/tty, which displays to the default text video output.  This file handles
  * all the formatting required for a TTY.
  */
@@ -230,7 +230,7 @@ print_char(char c)
 		draw_char(' ', ttyX*8, ttyY*16, 0xFFFFFF, 0x000000);
 
 	/* Characters */
-	if (!(tty.lflag & ECHO) && c != '\n')
+	if (!(tty.c_lflag & ECHO) && c != '\n')
 		goto curctl;
 	switch (c) {
 	case '\r':
@@ -294,17 +294,9 @@ curctl:
 
 /* Handle the keyboard interrupt */
 void
-keyboard_handler(InterruptFrame *frame)
+tty_keypress(unsigned char key)
 {
 	char c;
-	unsigned char key;
-	int i;
-	for (i = 0; i < 1000; i++) {
-		if ((inb(0x64) & 1) == 0)
-			continue;
-		key = inb(0x60);
-		break;
-	}
 	if (key == 0x1D)
 		ctrl = 128;
 	if (key == 0x9D)
@@ -323,6 +315,11 @@ keyboard_handler(InterruptFrame *frame)
 	if (!c)
 		return;
 
+	if (ctrl && c == 'c') {
+		kprintf("Killing foreground process");
+		return;
+	}
+
 	if (c == '\b' && lineBufLen == 0)
 		return;
 	if (c == '\b')
@@ -347,7 +344,7 @@ init_tty(void)
 	register_driver(&ttyDriver);
 	mknod("/dev/tty", S_IFCHR | 0666, MKDEV(ttyDriver.major, 0));
 
-	tty.lflag = ICANON | ECHO;
+	tty.c_lflag = ICANON | ECHO;
 
 	int fd = open("/dev/fb", O_RDWR);
 	if (fd < 0) {
@@ -375,7 +372,6 @@ init_tty(void)
 
 	lineBuf = kmalloc(4096);
 	line = kmalloc(4096);
-	register_interrupt(1, keyboard_handler);
 }
 
 /* Read from the TTY */
@@ -384,7 +380,7 @@ tty_read(File *file, char *buf, size_t size, off_t offset)
 {
 	if (!lineLen) {
 		add_to_queue(&ttyWait, current);
-		block_task(WAITING_FOR_READ);
+		block_task(WAITING_FOR_IO);
 	}
 	size_t count = (size < lineLen) ? size : lineLen;
 	memcpy(buf, line, count);
diff --git a/drivers/usb/xhci.c b/drivers/usb/xhci.c
new file mode 100644
index 0000000..715c3e6
--- /dev/null
+++ b/drivers/usb/xhci.c
@@ -0,0 +1,74 @@
+/*
+ * This file implements the driver for the Bochs Graphics Adapter video card.
+ * It is a simple card available in virtual machines.  It creates a framebuffer
+ * device node, and handles the reading/writing to it, and also mapping the
+ * framebuffer into memory.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/fb.h>
+#include "../drivers.h"
+#include "../pci.h"
+#include "../../mem/paging.h"
+#include "../../vfs/vfs.h"
+#include "../../io.h"
+
+size_t xhci_read(File *file, char *buf, size_t size, off_t offset);
+size_t xhci_write(File *file, char *buf, size_t size, off_t offset);
+int xhci_ioctl(File *file, unsigned long request, uintptr_t argp);
+
+FileOps xhciFileOps = {
+	.read = xhci_read,
+	.write = xhci_write,
+	.ioctl = xhci_ioctl,
+};
+
+Driver xhciDriver = {
+	.major = 9,
+	.ops = &xhciFileOps,
+	.next = NULL,
+};
+
+/* Initialise the USB driver */
+void
+xhci_init(uint8_t bus, uint8_t slot, uint8_t func)
+{
+	register_driver(&xhciDriver);
+
+	uint8_t intf, class, subclass;
+	intf = pci_read_byte(bus, slot, func, 9);
+	subclass = pci_read_byte(bus, slot, func, 10);
+	class = pci_read_byte(bus, slot, func, 11);
+	kprintf("    Initialising USB (%#.2x, %#.2x, %#.2x)",
+	        class, subclass, intf);
+
+	/* Map MMIO registers */
+	uint32_t bar0, bar1;
+	bar0 = pci_read_dword(bus, slot, func, 0x10);
+	bar1 = pci_read_dword(bus, slot, func, 0x14);
+	*get_page((void *) bar0) = bar0 | PTE_PRESENT | PTE_WRITE | PTE_GLOBAL;
+
+	
+}
+
+/* Read from a USB device */
+size_t
+xhci_read(File *file, char *buf, size_t size, off_t offset)
+{
+	return 0;
+}
+
+/* Write to a USB device */
+size_t
+xhci_write(File *file, char *buf, size_t size, off_t offset)
+{
+	return 0;
+}
+
+/* Control a USB device */
+int
+xhci_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+	return 0;
+}
diff --git a/drivers/usb/xhci.h b/drivers/usb/xhci.h
new file mode 100644
index 0000000..250abf6
--- /dev/null
+++ b/drivers/usb/xhci.h
@@ -0,0 +1,6 @@
+#ifndef DRIVERS_USB_XHCI_H
+#define DRIVERS_USB_XHCI_H
+
+
+
+#endif
diff --git a/drivers/vga/bga.c b/drivers/vga/bga.c
index aff91aa..4548593 100644
--- a/drivers/vga/bga.c
+++ b/drivers/vga/bga.c
@@ -16,10 +16,12 @@
 
 size_t bga_write(File *file, char *buf, size_t size, off_t offset);
 int bga_ioctl(File *file, unsigned long request, uintptr_t argp);
+void bga_mmap(File *file, void *addr, size_t len, off_t offset);
 
 FileOps bgaFileOps = {
 	.write = bga_write,
 	.ioctl = bga_ioctl,
+	.mmap = bga_mmap,
 };
 
 Driver bgaDriver = {
@@ -129,3 +131,25 @@ bga_ioctl(File *file, unsigned long request, uintptr_t argp)
 		return 0;
 	}
 }
+
+/* Map the linear frame buffer into memory */
+void
+bga_mmap(File *file, void *addr, size_t len, off_t offset)
+{
+	if (offset >= bgaWidth*bgaHeight*(bgaBpp/8))
+		return;
+	if (len + offset > bgaWidth*bgaHeight*(bgaBpp/8))
+		len = (bgaWidth*bgaHeight*(bgaBpp/8)) - offset;
+
+	page_t *pg, new;
+	size_t max, count = 0;
+	while (len) {
+		max = (len < 0x1000) ? len : 0x1000;
+		pg = get_page(addr + count);
+		new = PG_ATTR(*pg);
+		free_page(pg);
+		alloc_page(pg, PG_ATTR(new), 0xFD000000 + offset + count);
+		count += max;
+		len -= max;
+	}
+}
diff --git a/main.c b/main.c
index d4e1421..d25b7e8 100644
--- a/main.c
+++ b/main.c
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/mount.h>
 #include "mem/frame.h"
 #include "mem/paging.h"
 #include "mem/heap.h"
@@ -23,10 +24,6 @@
 #include "spinlock.h"
 #include "multiboot.h"
 
-#include <sys/mount.h>
-
-void init_tty(void);
-
 extern char _bss[], _end[];
 
 uintptr_t initialStack;
@@ -101,6 +98,8 @@ kmain(uint32_t esp, struct MultibootInfo *mbinfo)
 	/* Search for devices */
 	init_drivers();
 	init_tty();
+	init_kbd();
+//	init_mouse();
 	/* Initialise Networking */
 //	init_net();
 
diff --git a/vfs/devfs/file.c b/vfs/devfs/file.c
index d2da4e4..95d8aeb 100644
--- a/vfs/devfs/file.c
+++ b/vfs/devfs/file.c
@@ -53,32 +53,32 @@ devfs_readdir(File *file, DirEnt *dent, off_t index)
 	DirEntry *de;
 
 	if (!index--) {
-		dent->ino = file->inode->ino;
-		dent->type = DT_DIR;
-		dent->namelen = 2;
-		strncpy(dent->name, ".", dent->namelen);
+		dent->d_ino = file->inode->ino;
+		dent->d_type = DT_DIR;
+		dent->d_namelen = 2;
+		strncpy(dent->d_name, ".", dent->d_namelen);
 		return 0;
 	}
 
 	for (de = file->inode->dirEntries; de && index; de = de->next, index--);
 	if (!de)
 		return -ENOENT;
-	dent->ino = de->inode->ino;
+	dent->d_ino = de->inode->ino;
 	if (S_ISBLK(de->inode->mode))
-		dent->type = DT_BLK;
+		dent->d_type = DT_BLK;
 	if (S_ISCHR(de->inode->mode))
-		dent->type = DT_CHR;
+		dent->d_type = DT_CHR;
 	if (S_ISDIR(de->inode->mode))
-		dent->type = DT_DIR;
+		dent->d_type = DT_DIR;
 	if (S_ISFIFO(de->inode->mode))
-		dent->type = DT_FIFO;
+		dent->d_type = DT_FIFO;
 	if (S_ISLNK(de->inode->mode))
-		dent->type = DT_LNK;
+		dent->d_type = DT_LNK;
 	if (S_ISREG(de->inode->mode))
-		dent->type = DT_REG;
+		dent->d_type = DT_REG;
 	if (S_ISSOCK(de->inode->mode))
-		dent->type = DT_SOCK;
-	dent->namelen = strnlen(de->name, NAME_MAX) + 1;
-	strncpy(dent->name, de->name, NAME_MAX);
+		dent->d_type = DT_SOCK;
+	dent->d_namelen = strnlen(de->name, NAME_MAX) + 1;
+	strncpy(dent->d_name, de->name, NAME_MAX);
 	return 0;
 }
diff --git a/vfs/ext2fs/file.c b/vfs/ext2fs/file.c
index d0caa35..9701e37 100644
--- a/vfs/ext2fs/file.c
+++ b/vfs/ext2fs/file.c
@@ -71,10 +71,10 @@ ext2fs_readdir(File *file, DirEnt *dent, off_t index)
 	}
 	if (!de->ino)
 		return -ENOENT;
-	dent->ino = de->ino;
-	dent->type = de->type;
-	dent->namelen = de->nameLen + 1;
-	strncpy(dent->name, de->name, de->size);
+	dent->d_ino = de->ino;
+	dent->d_type = de->type;
+	dent->d_namelen = de->nameLen + 1;
+	strncpy(dent->d_name, de->name, de->size);
 	return 0;
 }
 
diff --git a/vfs/procfs/file.c b/vfs/procfs/file.c
index b292cf4..979c2c9 100644
--- a/vfs/procfs/file.c
+++ b/vfs/procfs/file.c
@@ -88,33 +88,33 @@ procfs_readdir(File *file, DirEnt *dent, off_t index)
 	DirEntry *de;
 
 	if (!index--) {
-		dent->ino = file->inode->ino;
-		dent->type = DT_DIR;
-		dent->namelen = 2;
-		strncpy(dent->name, ".", dent->namelen);
+		dent->d_ino = file->inode->ino;
+		dent->d_type = DT_DIR;
+		dent->d_namelen = 2;
+		strncpy(dent->d_name, ".", dent->d_namelen);
 		return 0;
 	}
 
 	for (de = file->inode->dirEntries; de && index; de = de->next, index--);
 	if (!de)
 		return -ENOENT;
-	dent->ino = de->inode->ino;
+	dent->d_ino = de->inode->ino;
 	if (S_ISBLK(de->inode->mode))
-		dent->type = DT_BLK;
+		dent->d_type = DT_BLK;
 	if (S_ISCHR(de->inode->mode))
-		dent->type = DT_CHR;
+		dent->d_type = DT_CHR;
 	if (S_ISDIR(de->inode->mode))
-		dent->type = DT_DIR;
+		dent->d_type = DT_DIR;
 	if (S_ISFIFO(de->inode->mode))
-		dent->type = DT_FIFO;
+		dent->d_type = DT_FIFO;
 	if (S_ISLNK(de->inode->mode))
-		dent->type = DT_LNK;
+		dent->d_type = DT_LNK;
 	if (S_ISREG(de->inode->mode))
-		dent->type = DT_REG;
+		dent->d_type = DT_REG;
 	if (S_ISSOCK(de->inode->mode))
-		dent->type = DT_SOCK;
-	dent->namelen = strnlen(de->name, NAME_MAX) + 1;
-	strncpy(dent->name, de->name, NAME_MAX);
+		dent->d_type = DT_SOCK;
+	dent->d_namelen = strnlen(de->name, NAME_MAX) + 1;
+	strncpy(dent->d_name, de->name, NAME_MAX);
 	return 0;
 }
 
diff --git a/vfs/tmpfs/file.c b/vfs/tmpfs/file.c
index bc320ed..275e77c 100644
--- a/vfs/tmpfs/file.c
+++ b/vfs/tmpfs/file.c
@@ -90,33 +90,33 @@ tmpfs_readdir(File *file, DirEnt *dent, off_t index)
 	DirEntry *de;
 
 	if (!index--) {
-		dent->ino = file->inode->ino;
-		dent->type = DT_DIR;
-		dent->namelen = 2;
-		strncpy(dent->name, ".", dent->namelen);
+		dent->d_ino = file->inode->ino;
+		dent->d_type = DT_DIR;
+		dent->d_namelen = 2;
+		strncpy(dent->d_name, ".", dent->d_namelen);
 		return 0;
 	}
 
 	for (de = file->inode->dirEntries; de && index; de = de->next, index--);
 	if (!de)
 		return -ENOENT;
-	dent->ino = de->inode->ino;
+	dent->d_ino = de->inode->ino;
 	if (S_ISBLK(de->inode->mode))
-		dent->type = DT_BLK;
+		dent->d_type = DT_BLK;
 	if (S_ISCHR(de->inode->mode))
-		dent->type = DT_CHR;
+		dent->d_type = DT_CHR;
 	if (S_ISDIR(de->inode->mode))
-		dent->type = DT_DIR;
+		dent->d_type = DT_DIR;
 	if (S_ISFIFO(de->inode->mode))
-		dent->type = DT_FIFO;
+		dent->d_type = DT_FIFO;
 	if (S_ISLNK(de->inode->mode))
-		dent->type = DT_LNK;
+		dent->d_type = DT_LNK;
 	if (S_ISREG(de->inode->mode))
-		dent->type = DT_REG;
+		dent->d_type = DT_REG;
 	if (S_ISSOCK(de->inode->mode))
-		dent->type = DT_SOCK;
-	dent->namelen = strnlen(de->name, NAME_MAX) + 1;
-	strncpy(dent->name, de->name, NAME_MAX);
+		dent->d_type = DT_SOCK;
+	dent->d_namelen = strnlen(de->name, NAME_MAX) + 1;
+	strncpy(dent->d_name, de->name, NAME_MAX);
 	return 0;
 }
 
diff --git a/vfs/vfs.c b/vfs/vfs.c
index c4784f2..396fd8f 100644
--- a/vfs/vfs.c
+++ b/vfs/vfs.c
@@ -475,7 +475,7 @@ getdents(int fd, void *buf, size_t count)
 		err = file_readdir(file, dent, i);
 		if (err < 0)
 			goto out;
-		size += sizeof(DirEnt) + dent->namelen;
+		size += sizeof(DirEnt) + dent->d_namelen;
 		*((char *) buf + size - 1) = '\0';
 		dent = (void *) ((char *) buf + size);
 	}