diff -uprN -X dontdiff linux-2.6.12/drivers/usb/storage/Kconfig linux/drivers/usb/storage/Kconfig
--- linux-2.6.12/drivers/usb/storage/Kconfig	2005-06-17 15:48:29.000000000 -0400
+++ linux/drivers/usb/storage/Kconfig	2005-08-18 18:22:54.000000000 -0400
@@ -111,3 +111,9 @@ config USB_STORAGE_JUMPSHOT
 	  Say Y here to include additional code to support the Lexar Jumpshot
 	  USB CompactFlash reader.
 
+config USB_STORAGE_KARMA
+	bool "Rio Karma MP3 player (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support the Rio Karma
+	  digital music player as a mass storage device.
diff -uprN -X dontdiff linux-2.6.12/drivers/usb/storage/Makefile linux/drivers/usb/storage/Makefile
--- linux-2.6.12/drivers/usb/storage/Makefile	2005-06-17 15:48:29.000000000 -0400
+++ linux/drivers/usb/storage/Makefile	2005-08-18 18:22:54.000000000 -0400
@@ -18,6 +18,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DPC
 usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)	+= isd200.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)	+= datafab.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)	+= jumpshot.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= rio_karma.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
diff -uprN -X dontdiff linux-2.6.12/drivers/usb/storage/rio_karma.c linux/drivers/usb/storage/rio_karma.c
--- linux-2.6.12/drivers/usb/storage/rio_karma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux/drivers/usb/storage/rio_karma.c	2005-08-30 23:50:31.000000000 -0400
@@ -0,0 +1,105 @@
+/* USB driver for DNNA Rio Karma 
+ *
+ * Rio Karma driver v0.1.1
+ * (C) 2005 Bob Copeland (email@bobcopeland.com)
+ *
+ * The Karma is a mass storage device, although it requires some 
+ * initialization code to get in that mode.  
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/jiffies.h>
+#include "rio_karma.h"
+#include "usb.h"
+#include "transport.h"
+#include "debug.h"
+
+#define RIOP_INIT "RIOP\x00\x01\x08"
+#define CMD_LEN 40
+#define RECV_LEN 0x200
+
+/* Initialize the karma and get it into mass storage mode.  
+ * 
+ * The initialization begins by sending RIOP\x00\x01\x08\x00... which
+ * the device will ack with a 512 byte packet with the high four bits
+ * set and everything else null.
+ *
+ * Next, we send RIOP\x80\x00\x08\x00.  Each time, a 512 byte response 
+ * must be read, but we must loop until byte 5 in the response is 0x08,
+ * indicating success. */
+int rio_karma_init(struct us_data *us) 
+{
+	int result, partial;
+	static char init_cmd[] = RIOP_INIT;
+	char *cmd, *recv, *buf;
+	unsigned long timeout = jiffies + 2 * HZ; /* give it a few seconds */
+	
+	if (!(buf = kmalloc(CMD_LEN + RECV_LEN, GFP_KERNEL | __GFP_DMA)))
+		goto init_failed;
+
+	cmd = buf;
+	recv = buf + CMD_LEN;
+
+	us->max_lun = 0;
+
+	US_DEBUGP("Initializing Karma...\n");
+
+	memcpy(cmd, init_cmd, sizeof(init_cmd));
+	memset(&cmd[sizeof(init_cmd)], 0, CMD_LEN - sizeof(init_cmd));
+
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, cmd,
+		CMD_LEN, &partial);
+	if (result != USB_STOR_XFER_GOOD)
+		goto init_failed;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 
+		recv, RECV_LEN, &partial);
+	if (result != USB_STOR_XFER_GOOD)
+		goto init_failed;
+
+	cmd[4] = 0x80;
+	cmd[5] = 0;
+	for (;;) {
+		US_DEBUGP("Sending init command\n");
+		result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 
+			cmd, CMD_LEN, &partial);
+		if (result != USB_STOR_XFER_GOOD)
+			goto init_failed;
+
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 
+			recv, RECV_LEN, &partial);
+		if (result != USB_STOR_XFER_GOOD)
+			goto init_failed;
+		
+		if (recv[5] == 0x08) 
+			break;
+		if (time_after(jiffies, timeout))
+			goto init_failed;
+		msleep(10);
+	}
+	US_DEBUGP("Karma initialized.\n");
+	kfree(buf);
+	return 0;
+
+init_failed:
+	kfree(buf);
+	US_DEBUGP("Could not initialize karma.\n");
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
diff -uprN -X dontdiff linux-2.6.12/drivers/usb/storage/rio_karma.h linux/drivers/usb/storage/rio_karma.h
--- linux-2.6.12/drivers/usb/storage/rio_karma.h	1969-12-31 19:00:00.000000000 -0500
+++ linux/drivers/usb/storage/rio_karma.h	2005-08-18 19:16:57.000000000 -0400
@@ -0,0 +1,31 @@
+/* Header file for USB driver for DNNA Rio Karma 
+ *
+ * Rio Karma driver v0.1.1
+ *
+ * (C) 2005 Bob Copeland (email@bobcopeland.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _RIO_KARMA_H
+#define _RIO_KARMA_H
+
+#include <linux/config.h>
+#include "usb.h"
+
+int rio_karma_init(struct us_data *);
+
+#endif
diff -uprN -X dontdiff linux-2.6.12/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h
--- linux-2.6.12/drivers/usb/storage/unusual_devs.h	2005-06-17 15:48:29.000000000 -0400
+++ linux/drivers/usb/storage/unusual_devs.h	2005-08-30 23:57:51.000000000 -0400
@@ -96,6 +96,14 @@ UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x
  		US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
 #endif
 
+#ifdef CONFIG_USB_STORAGE_KARMA
+UNUSUAL_DEV(  0x045a, 0x5210, 0x0000, 0x9999,
+		"Rio",
+		"Rio Karma",
+		US_SC_SCSI, US_PR_BULK, rio_karma_init,
+		US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN ),
+#endif
+
 /* Patch submitted by Philipp Friedrich <philipp@void.at> */
 UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
 		"Kyocera",
@@ -1039,3 +1047,4 @@ UNUSUAL_DEV(  0x55aa, 0xa103, 0x0000, 0x
 		US_SC_SCSI, US_PR_SDDR55, NULL,
 		US_FL_SINGLE_LUN),
 #endif
+
diff -uprN -X dontdiff linux-2.6.12/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c
--- linux-2.6.12/drivers/usb/storage/usb.c	2005-06-17 15:48:29.000000000 -0400
+++ linux/drivers/usb/storage/usb.c	2005-08-18 18:22:54.000000000 -0400
@@ -90,6 +90,9 @@
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 #include "jumpshot.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_KARMA
+#include "rio_karma.h"
+#endif
 
 
 /* Some informational data */
diff -uprN -X dontdiff linux-2.6.12/fs/Kconfig linux/fs/Kconfig
--- linux-2.6.12/fs/Kconfig	2005-06-17 15:48:29.000000000 -0400
+++ linux/fs/Kconfig	2005-09-03 00:26:07.000000000 -0400
@@ -1699,6 +1699,11 @@ config CODA_FS_OLD_API
 	  
 	  For most cases you probably want to say N.
 
+config OMFS_FS
+	tristate "OMFS (Rio Karma)"
+	help
+	  Say 'Y' to get support for the RIO Karma fs.
+
 config AFS_FS
 # for fs/nls/Config.in
 	tristate "Andrew File System support (AFS) (Experimental)"
diff -uprN -X dontdiff linux-2.6.12/fs/Makefile linux/fs/Makefile
--- linux-2.6.12/fs/Makefile	2005-06-17 15:48:29.000000000 -0400
+++ linux/fs/Makefile	2005-09-03 00:41:26.000000000 -0400
@@ -94,4 +94,5 @@ obj-$(CONFIG_AFS_FS)		+= afs/
 obj-$(CONFIG_BEFS_FS)		+= befs/
 obj-$(CONFIG_HOSTFS)		+= hostfs/
 obj-$(CONFIG_HPPFS)		+= hppfs/
+obj-$(CONFIG_OMFS_FS)		+= omfs/
 obj-$(CONFIG_DEBUG_FS)		+= debugfs/
diff -uprN -X dontdiff linux-2.6.12/fs/omfs/Makefile linux/fs/omfs/Makefile
--- linux-2.6.12/fs/omfs/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux/fs/omfs/Makefile	2005-09-12 21:25:58.000000000 -0400
@@ -0,0 +1,8 @@
+#
+# Makefile for OMFS filesystem.
+#
+
+
+obj-$(CONFIG_OMFS_FS) += omfs.o 
+
+omfs-objs := inode.o
diff -uprN -X dontdiff linux-2.6.12/fs/omfs/inode.c linux/fs/omfs/inode.c
--- linux-2.6.12/fs/omfs/inode.c	1969-12-31 19:00:00.000000000 -0500
+++ linux/fs/omfs/inode.c	2005-09-12 23:57:17.000000000 -0400
@@ -0,0 +1,440 @@
+/*
+ * fs/omfs/inode.c
+ * OMFS (as used by RIO Karma) inode operations.
+ * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/buffer_head.h>
+#include "omfs.h"
+
+MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>");
+MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux");
+MODULE_LICENSE("GPL");
+
+#define OMFS_DIR 'D'
+#define OMFS_FILE 'F'
+#define OMFS_NAMELEN 256
+#define ERRPTR(foo) 0
+
+static void omfs_read_inode(struct inode *inode);
+static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
+static struct super_block *omfs_get_sb(struct file_system_type *fs_type,
+				       int flags, const char *dev_name,
+				       void *data);
+static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
+				  struct nameidata *nd);
+static int omfs_readpage(struct file *file, struct page *page);
+
+struct omfs_super_block {
+	char fill1[256];
+	u32 fill2;
+	u32 root_block;
+	u64 num_blocks;
+	u32 magic;
+	u32 blocksize;
+	u32 mirrors;
+	u32 sys_blocksize;
+};
+
+struct omfs_header {
+	u32 fill1;
+	u32 self;
+	u32 body_size;
+	u16 crc;
+	char fill2[5];
+	u8 check_xor;
+	u32 fill3;
+};
+
+struct omfs_root_block {
+	struct omfs_header head;
+	u64 fill3;
+	u64 num_blocks;
+	u32 fill4;
+	u32 root_dir;
+	u64 fill5;
+	u32 blocksize;
+	u32 clustersize;
+	u64 mirrors;
+	char name[OMFS_NAMELEN];
+};
+
+struct omfs_inode {
+	struct omfs_header head;
+	u32 fill1;
+	u32 parent;
+	u32 fill2;
+	u32 sibling;
+	u64 ctime;
+	char fill3[35];
+	char type;
+	u32 fill4;
+	char fill5[64];
+	char name[OMFS_NAMELEN];
+	u64 size;
+	// 198 bytes of nonsense.
+};
+
+struct omfs_extent {
+	u32 fill1;
+	u32 next;
+	u32 extent_count;
+	u32 fill2;
+	u32 fill3;
+	u32 cluster;
+	u32 fill4;
+	u32 blocks;
+};
+
+static inline sector_t logical_to_sector(sector_t in)
+{
+	return in << 4;
+}
+
+static struct file_operations omfs_file_operations = {
+	.llseek = generic_file_llseek,
+	.read = generic_file_read,
+	.write = generic_file_write,
+	.mmap = generic_file_mmap,
+	.sendfile = generic_file_sendfile,
+};
+
+static struct address_space_operations omfs_aops = {
+	.readpage = omfs_readpage,
+};
+
+static struct inode_operations omfs_dir_inops = {
+	.lookup = omfs_lookup,
+};
+
+static struct file_operations omfs_dir_operations = {
+	.read = generic_read_dir,
+	.readdir = omfs_readdir,
+};
+
+static struct super_operations omfs_sops = {
+	.read_inode = omfs_read_inode,
+};
+
+/**** directory stuff ****/
+
+static struct buffer_head *omfs_find_entry(struct inode *dir,
+					   const char *name, int namelen)
+{
+	struct buffer_head *bh, *bh2;
+	struct omfs_inode *oi;
+
+	// get the bh for this inode (should be cached w/?)
+	// read bh+1 up to i_size.  make this cleaner like bfs?
+	int block = 1 + logical_to_sector(dir->i_ino);
+	loff_t offset = 0x200;	// FIXME
+
+	while (offset < dir->i_size) {
+		int i = 0;
+
+		bh = sb_bread(dir->i_sb, block++);
+		if (!bh)
+			goto out;
+
+		for (i = 0; i < dir->i_sb->s_blocksize && offset < dir->i_size;
+		     i += 8, offset += 8) {
+			u64 cluster = be64_to_cpu(*((u64 *) & bh->b_data[i]));
+			if (cluster != ~0) {
+				bh2 =
+				    sb_bread(dir->i_sb,
+					     logical_to_sector(cluster));
+				if (!bh2)
+					goto out;
+
+				oi = (struct omfs_inode *)bh2->b_data;
+				if (strncmp(oi->name, name, namelen) == 0) {
+					brelse(bh);
+					return bh2;
+				}
+				brelse(bh2);
+			}
+		}
+		brelse(bh);
+	}
+      out:
+	return 0;
+}
+
+static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
+				  struct nameidata *nd)
+{
+	struct buffer_head *bh;
+	struct inode *inode = NULL;
+
+	if (dentry->d_name.len > OMFS_NAMELEN)
+		return ERRPTR(-ENAMETOOLONG);
+
+	printk(KERN_DEBUG "looked up %s\n", dentry->d_name.name);
+
+	bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
+	if (bh) {
+		struct omfs_inode *oi = (struct omfs_inode *)bh->b_data;
+		ino_t ino = be32_to_cpu(oi->head.self);
+		brelse(bh);
+		inode = iget(dir->i_sb, ino);
+		if (!inode) {
+			unlock_kernel();
+			return ERR_PTR(-EINVAL);	//FIXME Acc
+		}
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *dir = filp->f_dentry->d_inode;
+	struct buffer_head *bh, *bh2;
+	struct omfs_inode *oi;
+	int ret = 0;
+
+	printk(KERN_DEBUG "in readdir %lu\n", dir->i_ino);
+
+	loff_t offset = filp->f_pos;
+
+	// add locking
+	while (offset < dir->i_size) {
+		unsigned int block = 1 + (offset >> 9);	// FIXME (blocksize bits??)
+		unsigned int bl_ofs = offset & (dir->i_sb->s_blocksize - 1);
+
+		bh = sb_bread(dir->i_sb, block + logical_to_sector(dir->i_ino));
+		if (!bh) {
+			ret = -EINVAL;
+			goto out;
+		}
+		do {
+			unsigned char d_type = DT_DIR;
+			u64 cluster =
+			    be64_to_cpu(*((u64 *) & bh->b_data[bl_ofs]));
+			if (cluster != ~0) {
+				bh2 =
+				    sb_bread(dir->i_sb,
+					     logical_to_sector(cluster));
+				if (!bh2) {
+					ret = -EINVAL;
+					goto out;
+				}
+
+				oi = (struct omfs_inode *)bh2->b_data;
+				if (oi->type == OMFS_DIR)
+					d_type = DT_DIR;
+				else
+					d_type = DT_REG;
+
+				filldir(dirent, oi->name,
+					strnlen(oi->name, OMFS_NAMELEN),
+					filp->f_pos, cluster, d_type);
+				printk(KERN_DEBUG "omfs: added file %s\n",
+				       oi->name);
+				brelse(bh2);
+			}
+			bl_ofs += 8;
+			offset += 8;
+			filp->f_pos += 8;
+
+		} while (offset < dir->i_size &&
+			 bl_ofs < dir->i_sb->s_blocksize);
+		brelse(bh);
+	}
+      out:
+	return ret;
+}
+
+/**** file stuff ****/
+
+static int omfs_get_block(struct inode *inode, sector_t block,
+			  struct buffer_head *bh_result, int create)
+{
+	struct buffer_head *bh;
+	sector_t start, next;
+	struct omfs_extent *oe;
+	if (create)
+		return -EIO;
+
+	if (block < 0)		// || > stuff
+		return -EIO;
+
+	/* wants block 0.. N of a given file.  we have to count
+	 * the blocks in clusters and total clusters in an extent
+	 * to find the right extent.  we have to search the extents
+	 * in order.
+	 */
+	sector_t logical = block >> 4;	// logic = block/16 (8192->512)
+	sector_t phys_ofs = block & 15;	//       = block % 16
+
+	// FIXME store this stuff ?
+	bh = sb_bread(inode->i_sb, logical_to_sector(inode->i_ino));
+	if (!bh)
+		return -EIO;
+
+	oe = (struct omfs_extent *)(&bh->b_data[0x1d0]);
+
+	// skip to the right extent
+	start = 0;
+	for (;;) {
+		u32 *eptr = &oe->cluster;
+		int count = be32_to_cpu(oe->extent_count);
+		while (count-- > 0) {
+			sector_t cluster = be32_to_cpu(*eptr);
+			/* size is size in 8192-blocks */
+			int size = be32_to_cpu(*eptr + 2);
+
+			if (logical >= start && logical < start + size) {
+				map_bh(bh_result, inode->i_sb,
+				       ((cluster + logical) << 4) + phys_ofs);
+				return 0;
+			}
+			start += size;
+			eptr += 6;
+		}
+		next = be32_to_cpu(oe->next);
+		brelse(bh);
+
+		if (next == ~0)
+			break;
+
+		bh = sb_bread(inode->i_sb, logical_to_sector(oe->next));
+		if (!bh)
+			return -EIO;
+		oe = (struct omfs_extent *)(&bh->b_data[0x40]);
+	}
+	return 0;
+}
+
+static int omfs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, omfs_get_block);
+}
+
+/**** inode stuff ****/
+
+static void omfs_read_inode(struct inode *inode)
+{
+	struct omfs_inode *oi;
+	struct buffer_head *bh;
+	unsigned int block;
+	ino_t ino = inode->i_ino;
+
+	printk(KERN_DEBUG "omfs: Reading inode: %lx\n", ino);
+
+	// check against num_blocks
+	block = logical_to_sector(ino);
+	bh = sb_bread(inode->i_sb, block);
+	if (!bh) {
+		make_bad_inode(inode);
+		return;
+	}
+
+	oi = (struct omfs_inode *)bh->b_data;
+
+	// check self
+	if (ino != be32_to_cpu(oi->head.self)) {
+		make_bad_inode(inode);
+		return;
+	}
+
+	inode->i_uid = 0;
+	inode->i_gid = 0;
+
+	if (oi->type == OMFS_DIR) {
+		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+		inode->i_mode |= S_IFDIR;
+		inode->i_op = &omfs_dir_inops;
+		inode->i_fop = &omfs_dir_operations;
+		inode->i_size = (loff_t) be32_to_cpu(oi->head.body_size) +
+		    sizeof(struct omfs_header);
+	} else if (oi->type == OMFS_FILE) {
+		inode->i_mode = S_IFREG | S_IRUGO;
+		inode->i_mapping->a_ops = &omfs_aops;
+		inode->i_fop = &omfs_file_operations;
+		inode->i_size = (loff_t) be64_to_cpu(oi->size);
+	}
+}
+
+/**** super stuff ****/
+
+static int omfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct buffer_head *bh, *bh2;
+	struct omfs_super_block *omfs_sb;
+	struct omfs_root_block *omfs_rb;
+	struct inode *root;
+
+	sb->s_flags |= MS_RDONLY;
+	sb->s_maxbytes = 0xffffffff;
+
+	sb_set_blocksize(sb, 0x200);
+
+	if (!(bh = sb_bread(sb, 0)))
+		goto out;
+
+	omfs_sb = (struct omfs_super_block *)bh->b_data;
+	if (be32_to_cpu(omfs_sb->magic) != OMFS_MAGIC) {
+		if (!silent)
+			printk(KERN_ERR "omfs: Invalid superblock (%x)\n",
+			       omfs_sb->magic);
+		goto out;
+	}
+	sb->s_magic = OMFS_MAGIC;
+
+	sector_t start = logical_to_sector(be32_to_cpu(omfs_sb->root_block));
+	if (!(bh2 = sb_bread(sb, start)))
+		goto out;
+
+	omfs_rb = (struct omfs_root_block *)bh2->b_data;
+	printk(KERN_DEBUG "omfs: volume: %s\n", omfs_rb->name);
+
+	sb->s_op = &omfs_sops;
+	root = iget(sb, be32_to_cpu(omfs_rb->root_dir));
+	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root) {
+		iput(root);
+		goto out;
+	}
+
+	brelse(bh);
+	brelse(bh2);
+	return 0;
+
+      out:
+	// fixup brelses
+	return -EINVAL;
+}
+
+static struct super_block *omfs_get_sb(struct file_system_type *fs_type,
+				       int flags, const char *dev_name,
+				       void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, omfs_fill_super);
+}
+
+static struct file_system_type omfs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "omfs",
+	.get_sb = omfs_get_sb,
+	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV,
+};
+
+static int __init init_omfs_fs(void)
+{
+	register_filesystem(&omfs_fs_type);
+	return 0;
+}
+
+static void __exit exit_omfs_fs(void)
+{
+	unregister_filesystem(&omfs_fs_type);
+}
+
+module_init(init_omfs_fs);
+module_exit(exit_omfs_fs);
diff -uprN -X dontdiff linux-2.6.12/fs/omfs/omfs.h linux/fs/omfs/omfs.h
--- linux-2.6.12/fs/omfs/omfs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux/fs/omfs/omfs.h	2005-09-02 08:05:59.000000000 -0400
@@ -0,0 +1,6 @@
+#ifndef _OMFS_H
+#define _OMFS_H
+
+#define OMFS_MAGIC 0xC2993D87
+
+#endif
diff -uprN -X dontdiff linux-2.6.12/fs/partitions/Kconfig linux/fs/partitions/Kconfig
--- linux-2.6.12/fs/partitions/Kconfig	2005-06-17 15:48:29.000000000 -0400
+++ linux/fs/partitions/Kconfig	2005-08-30 18:58:53.000000000 -0400
@@ -225,4 +225,11 @@ config EFI_PARTITION
 	  were partitioned using EFI GPT.  Presently only useful on the
 	  IA-64 platform.
 
+config KARMA_PARTITION
+	bool "Karma Partition support"
+	depends on PARTITION_ADVANCED
+	help
+	  Say Y here if you would like to mount the Rio Karma MP3 player,
+          as it uses a proprietary partition table.
+
 #      define_bool CONFIG_ACORN_PARTITION_CUMANA y
diff -uprN -X dontdiff linux-2.6.12/fs/partitions/Makefile linux/fs/partitions/Makefile
--- linux-2.6.12/fs/partitions/Makefile	2005-06-17 15:48:29.000000000 -0400
+++ linux/fs/partitions/Makefile	2005-08-30 18:58:58.000000000 -0400
@@ -18,3 +18,4 @@ obj-$(CONFIG_ULTRIX_PARTITION) += ultrix
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
 obj-$(CONFIG_NEC98_PARTITION) += nec98.o msdos.o
+obj-$(CONFIG_KARMA_PARTITION) += karma.o
diff -uprN -X dontdiff linux-2.6.12/fs/partitions/check.c linux/fs/partitions/check.c
--- linux-2.6.12/fs/partitions/check.c	2005-06-17 15:48:29.000000000 -0400
+++ linux/fs/partitions/check.c	2005-08-30 18:59:38.000000000 -0400
@@ -35,6 +35,7 @@
 #include "ibm.h"
 #include "ultrix.h"
 #include "efi.h"
+#include "karma.h"
 
 #ifdef CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(dev_t dev);
@@ -106,6 +107,9 @@ static int (*check_part[])(struct parsed
 #ifdef CONFIG_IBM_PARTITION
 	ibm_partition,
 #endif
+#ifdef CONFIG_KARMA_PARTITION
+	karma_partition,
+#endif
 	NULL
 };
  
diff -uprN -X dontdiff linux-2.6.12/fs/partitions/karma.c linux/fs/partitions/karma.c
--- linux-2.6.12/fs/partitions/karma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux/fs/partitions/karma.c	2005-08-30 18:58:35.000000000 -0400
@@ -0,0 +1,58 @@
+/*
+ *  fs/partitions/karma.c
+ *  Rio Karma partition info.
+ *
+ *  Copyright (C) 2005 Bob Copeland, based on ofs.c
+ */
+
+#include "check.h"
+#include "karma.h"
+
+int karma_partition(struct parsed_partitions *state, struct block_device *bdev)
+{
+	int i;
+	int slot = 1;
+	Sector sect;
+	unsigned char *data;
+	struct disklabel {
+		u8 reserved[270];
+		struct d_partition {
+			__le32 res;
+			u8 fstype;
+			u8 res2[3];
+			__le32 offset;
+			__le32 size;
+		} partitions[2];
+		u8 blank[208];
+		__le16 magic;
+	} __attribute__((packed)) *label;
+	struct d_partition *p;
+
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
+		return -1;
+
+	label = (struct disklabel *) data;
+	if (le16_to_cpu(label->magic) != KARMA_LABEL_MAGIC) {
+		put_dev_sector(sect);
+		return 0;
+	}
+
+	p = label->partitions;
+	for (i = 0 ; i < 2; i++, p++) {
+		if (slot == state->limit)
+		        break;
+
+		if (p->fstype == 0x4d &&
+		    le32_to_cpu(p->size)) {
+			put_partition(state, slot,
+				le32_to_cpu(p->offset),
+				le32_to_cpu(p->size));
+                }
+		slot++;
+	}
+	printk("\n");
+	put_dev_sector(sect);
+	return 1;
+}
+
diff -uprN -X dontdiff linux-2.6.12/fs/partitions/karma.h linux/fs/partitions/karma.h
--- linux-2.6.12/fs/partitions/karma.h	1969-12-31 19:00:00.000000000 -0500
+++ linux/fs/partitions/karma.h	2005-08-30 18:58:35.000000000 -0400
@@ -0,0 +1,8 @@
+/*
+ *  fs/partitions/karma.h
+ */
+
+#define KARMA_LABEL_MAGIC		0xAB56
+
+int karma_partition(struct parsed_partitions *state, struct block_device *bdev);
+
