LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
@ 2007-02-15 22:34 Ivan Babkin
  2007-03-09 13:23 ` James
  0 siblings, 1 reply; 10+ messages in thread
From: Ivan Babkin @ 2007-02-15 22:34 UTC (permalink / raw)
  To: linux-kernel

Hi!
> Apart from that I did the following changes:
> - implemented suspend/resume support (not tested very much)
> - named the registers
> - fixed a bug that caused a major slowdown when modprobed without debug=1
> - added writting support (disabled by default, modprobe with write=1)
> Before you enable writting please make sure that you did a proper backup of 
> the data on the card. Do not use this driver to save important data.
Thank for the job you've done!
Your driver works with 1 Gb sd-card (x86_64 suse's 2.16.18.2 kernel).
Read rate for me was around 250 Kb/s, write - 28 Kb/s (using dd utility).
BTW, I get continuous flow of "sdricoh_cs: timeout waiting for data"
messages in dmesg.

Good luck!

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-02-15 22:34 Experimental driver for Ricoh Bay1Controller SD Card readers Ivan Babkin
@ 2007-03-09 13:23 ` James
  0 siblings, 0 replies; 10+ messages in thread
From: James @ 2007-03-09 13:23 UTC (permalink / raw)
  To: Ivan Babkin; +Cc: linux-kernel

On 2/16/07, Ivan Babkin <ivan.babkin@miclab.chem.msu.ru> wrote:
> Thank for the job you've done!
> Your driver works with 1 Gb sd-card (x86_64 suse's 2.16.18.2 kernel).
> Read rate for me was around 250 Kb/s, write - 28 Kb/s (using dd utility).
> BTW, I get continuous flow of "sdricoh_cs: timeout waiting for data"
> messages in dmesg.

Works for me too. Using a 512mb SD card, and a 256miniSD in an adaptor.

Managed to mount both SD cards and play mp3's off each with mpg321.
Literally music to my ears. I used the 0.1 release on the homepage, so
it still oopsed on removal when I hadnt unmounted.

Laptop is an Acer Travelmate 370 for the record.

James

-- 
iphitus // Arch Developer // kernel26beyond // iphitus.loudas.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-02-13  5:47     ` Pierre Ossman
  2007-02-13  9:48       ` Samuel Thibault
@ 2007-02-13 11:42       ` Sascha Sommer
  1 sibling, 0 replies; 10+ messages in thread
From: Sascha Sommer @ 2007-02-13 11:42 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: Jiri Slaby, LKML, rmk+mmc, Elladan, Samuel Thibault

Hi,

On Tuesday 13 February 2007 06:47, Pierre Ossman wrote:
> Sascha Sommer wrote:
> > I still consider this driver experimental, but without documentation this
> > is probably not going to change anytime soon.
> > The question is now what I should do with the driver?
> > Is it worth to be included in the kernel? If yes where and against what
> > kernelversion should I send the patch?
>
> That's up to you. The most important thing for any part of the kernel is
> that it must have a maintainer. So if you are ready to keep the driver
> up to date and handle the support requests that show, then you should
> really submit it.
>
> Patches should always be sent against the current version of the kernel
> (i.e. git HEAD). Usually the latest packaged release will also do.
>
> (Note that I haven't had time to review your latest version of the driver)
>

Yes, I'm going to maintain it. There are still some bugs that need to be fixed 
first, though. I also got a mail from someone else how also did some 
reverseengineering work for this reader. I'm waiting for his feedback before 
I will submit a patch that can be included.

Thanks.

Sascha


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-02-13  5:47     ` Pierre Ossman
@ 2007-02-13  9:48       ` Samuel Thibault
  2007-02-13 11:42       ` Sascha Sommer
  1 sibling, 0 replies; 10+ messages in thread
From: Samuel Thibault @ 2007-02-13  9:48 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: Sascha Sommer, Jiri Slaby, LKML, rmk+mmc, Elladan

Pierre Ossman, le Tue 13 Feb 2007 06:47:41 +0100, a écrit :
> Sascha Sommer wrote:
> > I still consider this driver experimental, but without documentation this is 
> > probably not going to change anytime soon.
> > The question is now what I should do with the driver?
> > Is it worth to be included in the kernel? If yes where and against what 
> > kernelversion should I send the patch?
> 
> That's up to you. The most important thing for any part of the kernel is
> that it must have a maintainer. So if you are ready to keep the driver
> up to date and handle the support requests that show, then you should
> really submit it.

You can mark your Kconfig entry with EXPERIMENTAL for letting people
know about the status :)

Samuel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-02-11 20:22   ` Sascha Sommer
@ 2007-02-13  5:47     ` Pierre Ossman
  2007-02-13  9:48       ` Samuel Thibault
  2007-02-13 11:42       ` Sascha Sommer
  0 siblings, 2 replies; 10+ messages in thread
From: Pierre Ossman @ 2007-02-13  5:47 UTC (permalink / raw)
  To: Sascha Sommer; +Cc: Jiri Slaby, LKML, rmk+mmc, Elladan, Samuel Thibault

Sascha Sommer wrote:
> I still consider this driver experimental, but without documentation this is 
> probably not going to change anytime soon.
> The question is now what I should do with the driver?
> Is it worth to be included in the kernel? If yes where and against what 
> kernelversion should I send the patch?
>
>   

That's up to you. The most important thing for any part of the kernel is
that it must have a maintainer. So if you are ready to keep the driver
up to date and handle the support requests that show, then you should
really submit it.

Patches should always be sent against the current version of the kernel
(i.e. git HEAD). Usually the latest packaged release will also do.

(Note that I haven't had time to review your latest version of the driver)

Rgds

-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-01-07  9:56 ` Jiri Slaby
@ 2007-02-11 20:22   ` Sascha Sommer
  2007-02-13  5:47     ` Pierre Ossman
  0 siblings, 1 reply; 10+ messages in thread
From: Sascha Sommer @ 2007-02-11 20:22 UTC (permalink / raw)
  To: Jiri Slaby; +Cc: LKML, rmk+mmc, Elladan, Samuel Thibault, Pierre Ossman

[-- Attachment #1: Type: text/plain, Size: 2350 bytes --]

Hi,

On Sunday 07 January 2007 10:56, Jiri Slaby wrote:
> Sascha Sommer wrote:
> > Hi,
> >
> > Attached is a very experimental driver for a Ricoh SD Card reader that
> > can be found in some notebooks like the Samsung P35.
> >
> > Whenever a sd card is inserted into one of these notebooks, a virtual
> > pcmcia card will show up:
> >
> > Socket 0:
> >   product info: "RICOH", "Bay1Controller", "", ""
> >   manfid: 0x0000, 0x0000
> >
> > In order to write this driver I hacked qemu to have access to the cardbus
> > bridge containing this card. I then logged the register accesses of the
> > windows xp driver and tryed to analyse them.
> >
> > As the meanings of most of the register are still unknown to me, I
> > consider this driver very experimental. It is possible that this driver
> > might destroy your data or your hardware. Use at your own risk!
> >
> > Other problems:
> > - I only implemented reading support
> > - I only tested with a 128 MB SD card, no idea what would be needed to
> > support other card types
> > - irqs are not supported
> > - dma is not supported
> > - it is very slow
> > - the registers can be found on the cardbus bridge and not on the virtual
> >   pcmcia card. The cardbus bridge is already claimed by yenta_socket.
> >   Therefore the driver currently uses pci_find_device to find the cardbus
>
> - pci_find_device is no go today. Use pci_get_device (+ pci_dev_get, _put).
> - ioremap->pci_iomap
> - iobase should be __iomem.
> - codingstyle (char* buffer, for(loop, if(data){, ...)
>

Thanks for your feedback and testing.
I fixed the above problems and ran the code through Lindent.
Apart from that I did the following changes:
- implemented suspend/resume support (not tested very much)
- named the registers
- fixed a bug that caused a major slowdown when modprobed without debug=1
- added writting support (disabled by default, modprobe with write=1)
Before you enable writting please make sure that you did a proper backup of 
the data on the card. Do not use this driver to save important data.

I still consider this driver experimental, but without documentation this is 
probably not going to change anytime soon.
The question is now what I should do with the driver?
Is it worth to be included in the kernel? If yes where and against what 
kernelversion should I send the patch?


Thanks

Sascha


[-- Attachment #2: Makefile --]
[-- Type: text/x-makefile, Size: 406 bytes --]

KERNEL_VERSION = $(shell uname -r)
KERNEL_DIR = /lib/modules/$(KERNEL_VERSION)/build
MDIR = /lib/modules/$(KERNEL_VERSION)/kernel/drivers/mmc

obj-m += sdricoh_cs.o

default:
	$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules

install:
	if test ! -d $(MDIR) ; then mkdir -p $(MDIR) ; fi
	install -D -m 644 *.ko $(MDIR)
	depmod -a

clean:
	rm -f *.o *.ko *.mod.c .*o.cmd .*o.d .*o.flags
	rm -rf .tmp_versions

[-- Attachment #3: sdricoh_cs.c --]
[-- Type: text/x-csrc, Size: 15049 bytes --]

/*
 *  sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be found
 *     on some Ricoh RL5c476 II cardbus bridge
 *
 *  Copyright (C) 2006 - 2007 Sascha Sommer <saschasommer@freenet.de>
 *
 * 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 of the License, 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.
 * 
 * FIXME:
 *   - what about irqs and dma?
 */

#include <linux/delay.h>
#include <linux/highmem.h>
#include <linux/pci.h>
#include <linux/ioport.h>

#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
#include <asm/io.h>

#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>

#define DRIVER_NAME "sdricoh_cs"
#define DRIVER_VERSION "0.1"

static unsigned int debug = 0;
static unsigned int write = 0;

//#define DEBUG

/* debug macros */

#ifdef DEBUG
#define REGDBG(fmt, arg...) do {\
        if (debug > 1) \
                printk(KERN_INFO "sdricoh_cs: "fmt, \
                         ##arg); } while (0)
#else
#define REGDBG(fmt, arg...)
#endif

#define DBG(fmt, arg...) do {\
        if (debug > 0) \
                printk(KERN_INFO "sdricoh_cs: "fmt, \
                         ##arg); } while (0)

#define ERR(fmt, arg...) do {\
                printk(KERN_INFO "sdricoh_cs: "fmt, \
                         ##arg); } while (0)

/* i/o region */
#define SDRICOH_PCI_REGION 0
#define SDRICOH_PCI_REGION_SIZE 0x1000

/* registers */
#define R104_VERSION     0x104
#define R200_CMD         0x200
#define R204_CMD_ARG     0x204
#define R208_DATAIO      0x208
#define R20C_RESP        0x20c
#define R21C_STATUS      0x21c
#define R2E0_INIT        0x2e0
#define R2E4_STATUS_RESP 0x2e4
#define R2F0_RESET       0x2f0
#define R224_CLOCK       0x224
#define R228_POWER       0x228
#define R230_DATA        0x230

/* flags for the R21C_STATUS register */
#define STATUS_CMD_FINISHED   0x00000001
#define STATUS_CARD_INSERTED  0x00000020
#define STATUS_CARD_LOCKED    0x00000080
#define STATUS_CMD_TIMEOUT    0x00400000
#define STATUS_READY_TO_READ  0x01000000
#define STATUS_READY_TO_WRITE 0x02000000
#define STATUS_BUSY           0x40000000

/* timeouts */
#define INIT_TIMEOUT      100
#define CMD_TIMEOUT       100
#define TRANSFER_TIMEOUT  20000

/* list of supported pcmcia devices */
static struct pcmcia_device_id pcmcia_ids[] = {
	/* vendor and device strings followed by their crc32 hashes */
	PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed,
				0xc3901202),
	PCMCIA_DEVICE_NULL,
};

MODULE_DEVICE_TABLE(pcmcia, pcmcia_ids);

/* mmc privdata */
struct sdricoh_host {
	struct mmc_host *mmc;	/* MMC structure */
	unsigned char __iomem *iobase;
	struct pci_dev *pci_dev;
};

/***************** register i/o helper functions *****************************/

static inline unsigned int sdricoh_readl(struct sdricoh_host *host,
					 unsigned int reg)
{
	unsigned int value = readl(host->iobase + reg);
	REGDBG("rl %x 0x%x\n", reg, value);
	return value;
}

static inline void sdricoh_writel(struct sdricoh_host *host, unsigned int reg,
				  unsigned int value)
{
	writel(value, host->iobase + reg);
	REGDBG("wl %x 0x%x\n", reg, value);

}

static inline unsigned int sdricoh_readw(struct sdricoh_host *host,
					 unsigned int reg)
{
	unsigned int value = readw(host->iobase + reg);
	REGDBG("rb %x 0x%x\n", reg, value);
	return value;
}

static inline unsigned int sdricoh_readb(struct sdricoh_host *host,
					 unsigned int reg)
{
	unsigned int value = readb(host->iobase + reg);
	REGDBG("rb %x 0x%x\n", reg, value);
	return value;
}

static int sdricoh_mmc_cmd(struct sdricoh_host *host, unsigned char opcode,
			   unsigned int arg)
{
	unsigned int status;
	int result = MMC_ERR_NONE;
	unsigned int loop = 0;
	/* reset status reg? */
	sdricoh_writel(host, R21C_STATUS, 0x18);
	/* fill parameters */
	sdricoh_writel(host, R204_CMD_ARG, arg);
	sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode);
	/* wait for command completion */
	if (opcode) {
		for (loop = 0; loop < CMD_TIMEOUT; loop++) {
			status = sdricoh_readl(host, R21C_STATUS);
			sdricoh_writel(host, R2E4_STATUS_RESP, status);
			if (status & STATUS_CMD_FINISHED)
				break;
			msleep(1);
		}
		if (loop == CMD_TIMEOUT || status & STATUS_CMD_TIMEOUT)
			result = MMC_ERR_TIMEOUT;
	}
	DBG("mmc_cmd opcode=%i arg=0x%x => %i (queries=%i)\n",
	    opcode, arg, result, loop);
	return result;

}

static int sdricoh_reset(struct sdricoh_host *host)
{
	unsigned int loop;
	DBG("reset\n");
	sdricoh_writel(host, R2F0_RESET, 0x10001);
	sdricoh_writel(host, R2E0_INIT, 0x10000);
	if (sdricoh_readl(host, R2E0_INIT) != 0x10000)
		return -EIO;
	sdricoh_writel(host, R2E0_INIT, 0x10007);

	/* status register ? */
	sdricoh_writel(host, R21C_STATUS, 0x18);

	/* clock or power register ? */
	sdricoh_writel(host, R224_CLOCK, 0x2000320);

	if (sdricoh_mmc_cmd(host, MMC_GO_IDLE_STATE, 0x0))
		return -EIO;

	/* what is this for ? */
	for (loop = 0; loop < INIT_TIMEOUT; loop++) {
		int result;
		if (sdricoh_mmc_cmd(host, MMC_APP_CMD, 0x0))
			return -EIO;
		result = sdricoh_mmc_cmd(host, 0x69, 0x100000);
		if (result) {
			if (result == MMC_ERR_TIMEOUT)
				continue;
			return -EIO;
		}
		if (sdricoh_readw(host, 0x20e) == 0x80ff)
			break;
	}

	if (loop == INIT_TIMEOUT) {
		DBG("timeout waiting for init to complete\n");
		return -EIO;
	}

	return 0;
}

static int sdricoh_read_block_pio(struct sdricoh_host *host, char *buffer)
{
	unsigned int *buf = (unsigned int *)buffer;
	unsigned int loop;
	int i;

	/* wait until the data is available */
	for (loop = 0; loop < CMD_TIMEOUT; loop++) {
		unsigned int status = sdricoh_readl(host, R21C_STATUS);
		sdricoh_writel(host, R2E4_STATUS_RESP, status);
		if (status & STATUS_READY_TO_READ)
			break;
	}
	sdricoh_writel(host, R21C_STATUS, 0x18);

	if (loop == CMD_TIMEOUT) {
		ERR("read_block: timeout waiting for data\n");
		return 0;
	}

	/* read data */
	for (i = 0; i < 512 / 4; i++) {
		buf[i] = sdricoh_readl(host, R230_DATA);
	}
	return 512;
}

static int sdricoh_write_block_pio(struct sdricoh_host *host, char *buffer)
{
	unsigned int *buf = (unsigned int *)buffer;
	unsigned int loop;
	int i;

	/* wait until the data is available */
	for (loop = 0; loop < CMD_TIMEOUT; loop++) {
		unsigned int status = sdricoh_readl(host, R21C_STATUS);
//              sdricoh_writel(host, R2E4_STATUS_RESP, status);
		if (status & STATUS_READY_TO_WRITE)
			break;
	}
	sdricoh_writel(host, R21C_STATUS, 0x18);

	if (loop == CMD_TIMEOUT) {
		ERR("write_block: timeout waiting for data\n");
		return 0;
	}

	/* write data */
	for (i = 0; i < 512 / 4; i++) {
		sdricoh_writel(host, R230_DATA, buf[i]);
	}
	return 512;
}

static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
	struct sdricoh_host *host = mmc_priv(mmc);
	struct mmc_command *cmd = mrq->cmd;
	struct mmc_data *data = cmd->data;

	DBG("=============================\n");
	DBG("sdricoh_request opcode=%i\n", cmd->opcode);

	/* read/write commands seem to require this */
	if (data) {
		sdricoh_writel(host, R208_DATAIO, 0);
	}

	cmd->error = sdricoh_mmc_cmd(host, cmd->opcode, cmd->arg);

	/* read response buffer */
	if (cmd->flags & MMC_RSP_PRESENT) {
		if (cmd->flags & MMC_RSP_136) {
			int i;
			/* CRC is stripped so we need to do some shifting. */
			for (i = 0; i < 4; i++) {
				cmd->resp[i] =
				    sdricoh_readl(host,
						  R20C_RESP + (3 - i) * 4) << 8;
				if (i != 3)
					cmd->resp[i] |=
					    sdricoh_readb(host,
							  R20C_RESP + (3 -
								       i) * 4 -
							  1);
			}
			DBG("resp[0]=0x%x\n", cmd->resp[0]);
			DBG("resp[1]=0x%x\n", cmd->resp[1]);
			DBG("resp[2]=0x%x\n", cmd->resp[2]);
			DBG("resp[2]=0x%x\n", cmd->resp[3]);
		} else {
			cmd->resp[0] = sdricoh_readl(host, R20C_RESP);
			DBG("resp[0]=0x%x\n", cmd->resp[0]);
		}
	}

	/* special command handling */
	if (cmd->opcode == MMC_SELECT_CARD) {
		sdricoh_mmc_cmd(host, MMC_APP_CMD, cmd->arg);	/* what is this for? set bus_width? */
		sdricoh_mmc_cmd(host, 0x46, 0x02);
	}

	/* transfer data */
	if (data && cmd->error == MMC_ERR_NONE
	    && cmd->opcode != SD_APP_SEND_SCR) {
		int i;
		char *mapped_sg = kmap_atomic(data->sg->page, KM_BIO_SRC_IRQ);
		DBG("read block: blksz %i blocks %i sg_len %i current length  %i\n", data->blksz, data->blocks, data->sg_len, data->sg->length);

		/* enter data reading mode */
		sdricoh_writel(host, R21C_STATUS, 0x837f031e);
		for (i = 0; i < data->blocks; i++) {
			if (data->flags & MMC_DATA_READ) {
				data->bytes_xfered +=
				    sdricoh_read_block_pio(host,
							   mapped_sg +
							   data->sg->offset +
							   (512 * i));
			} else {
				data->bytes_xfered +=
				    sdricoh_write_block_pio(host,
							    mapped_sg +
							    data->sg->offset +
							    (512 * i));
			}
		}
		kunmap_atomic(mapped_sg, KM_BIO_SRC_IRQ);

		sdricoh_writel(host, R208_DATAIO, 1);

		/* wait until the tranfer is finished */
		for (i = 0; i < TRANSFER_TIMEOUT; i++) {
			unsigned int status = sdricoh_readl(host, R21C_STATUS);
			sdricoh_writel(host, R2E4_STATUS_RESP, status);
			if (!(status & STATUS_BUSY))
				break;
		}
		if (i == TRANSFER_TIMEOUT) {
			ERR("timeout waiting for end of data cmd\n");
			cmd->error = MMC_ERR_TIMEOUT;
		}
		/* reset status register */
		sdricoh_writel(host, R21C_STATUS, 0x18);
	}

	mmc_request_done(mmc, mrq);
	DBG("=============================\n");
}

static void sdricoh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
	struct sdricoh_host *host = mmc_priv(mmc);
	DBG("set_ios\n");

	if (ios->power_mode == MMC_POWER_ON) {
		sdricoh_writel(host, R224_CLOCK, 0x2000300);
		sdricoh_writel(host, R228_POWER, 0x40e0);
	}
}

static int sdricoh_get_ro(struct mmc_host *mmc)
{
	struct sdricoh_host *host = mmc_priv(mmc);
	unsigned int status;

	if (!write)
		return 1;

	status = sdricoh_readl(host, R21C_STATUS);
	sdricoh_writel(host, R2E4_STATUS_RESP, status);
	return (status & STATUS_CARD_LOCKED);
}

static struct mmc_host_ops sdricoh_ops = {
	.request = sdricoh_request,
	.set_ios = sdricoh_set_ios,
	.get_ro = sdricoh_get_ro,
};

/* initialize the control and register it to the mmc framework */
static int sdricoh_init_mmc(struct pci_dev *pci_dev,
			    struct pcmcia_device *pcmcia_dev)
{
	int result = 0;
	void *iobase = NULL;
	struct mmc_host *mmc = NULL;
	struct sdricoh_host *host = NULL;
	/* map iomem */
	if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) !=
	    SDRICOH_PCI_REGION_SIZE) {
		DBG("unexpected pci resource len\n");
		return -ENODEV;
	}
	iobase =
	    pci_iomap(pci_dev, SDRICOH_PCI_REGION, SDRICOH_PCI_REGION_SIZE);
	if (!iobase) {
		DBG("unable to map iobase\n");
		return -ENODEV;
	}
	/* check version? */
	if (readl(iobase + R104_VERSION) != 0x4000) {
		DBG("no supported mmc controller found\n");
		result = -ENODEV;
		goto err;
	}
	/* allocate privdata */
	mmc = pcmcia_dev->priv =
	    mmc_alloc_host(sizeof(struct sdricoh_host), &pcmcia_dev->dev);
	if (!mmc) {
		result = -ENOMEM;
		goto err;
	}
	host = mmc_priv(mmc);

	host->iobase = iobase;

	mmc->ops = &sdricoh_ops;

	/* FIXME: the following values are probably not correct 
	   we don't know how to change ocr and frequency at all 
	   hopefully it is configured correctly by the controller
	 */
	mmc->f_min = 450000;
	mmc->f_max = 24000000;
	mmc->caps = MMC_CAP_4_BIT_DATA;
	mmc->ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;

	mmc->max_sectors = 1024;
	mmc->max_seg_size = mmc->max_sectors * 512;

	/* reset the controler */
	if (sdricoh_reset(host)) {
		ERR("could not reset\n");
		result = -EIO;
		goto err;

	}

	result = mmc_add_host(mmc);

	if (!result) {
		DBG("mmc host registered\n");
		return 0;
	}

      err:
	if (iobase)
		iounmap(iobase);
	if (mmc)
		mmc_free_host(mmc);

	return result;
}

/* search for supported mmc controllers */
static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev)
{
	struct pci_dev *pci_dev = NULL;

	DBG("found pcmcia device %s %s\n", pcmcia_dev->prod_id[0],
	    pcmcia_dev->prod_id[1]);
	DBG("searching mmc controler...\n");

	/* search pci cardbus bridge that contains the mmc controler */
	/* the io region is already claimed by yenta_socket... */
	while ((pci_dev =
		pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476,
			       pci_dev))) {
		/* try to init the device */
		if (!sdricoh_init_mmc(pci_dev, pcmcia_dev))
			return 0;

	}

	return -ENODEV;
}

static void sdricoh_pcmcia_detach(struct pcmcia_device *link)
{
	struct mmc_host *mmc = link->priv;

	DBG("detach\n");

	flush_scheduled_work();

	/* remove mmc host */
	if (mmc) {
		struct sdricoh_host *host = mmc_priv(mmc);
		mmc_remove_host(mmc);
		pci_iounmap(host->pci_dev, host->iobase);
		pci_dev_put(host->pci_dev);
		mmc_free_host(mmc);
	}

}

static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
{
        struct mmc_host *mmc = link->priv;
	DBG("suspend\n");
	mmc_suspend_host(mmc, PMSG_SUSPEND);
	return 0;
}

static int sdricoh_pcmcia_resume(struct pcmcia_device *link)
{
        struct mmc_host *mmc = link->priv;
	DBG("resume\n");
	mmc_resume_host(mmc);
	return 0;
}

static struct pcmcia_driver sdricoh_driver = {
	.drv = {
		.name = DRIVER_NAME,
		},
	.probe = sdricoh_pcmcia_probe,
	.remove = sdricoh_pcmcia_detach,
	.id_table = pcmcia_ids,
	.suspend = sdricoh_pcmcia_suspend,
	.resume = sdricoh_pcmcia_resume,
};

/*****************************************************************************\
 *                                                                           *
 * Driver init/exit                                                          *
 *                                                                           *
\*****************************************************************************/

static int __init sdricoh_drv_init(void)
{
	DBG("Ricoh RL5c476 II Secure Digital Interface driver\n");
	DBG("Copyright(c) Sascha Sommer\n");
	return pcmcia_register_driver(&sdricoh_driver);
}

static void __exit sdricoh_drv_exit(void)
{
	DBG("exiting\n");
	pcmcia_unregister_driver(&sdricoh_driver);

}

module_init(sdricoh_drv_init);
module_exit(sdricoh_drv_exit);

module_param(debug, uint, 0444);
module_param(write, uint, 0444);

MODULE_AUTHOR("Sascha Sommer <saschasommer@freenet.de>");
MODULE_DESCRIPTION("Ricoh RL5c476 II Secure Digital Interface driver");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");

MODULE_PARM_DESC(debug, "Enable debugging (default 0)");
MODULE_PARM_DESC(write,
		 "Dangerous: Enable writting. Might destroy the data on the sd card. (default 0)");

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-01-06 23:32 Sascha Sommer
  2007-01-07  9:56 ` Jiri Slaby
  2007-01-09 20:57 ` Samuel Thibault
@ 2007-01-10 20:10 ` Pierre Ossman
  2 siblings, 0 replies; 10+ messages in thread
From: Pierre Ossman @ 2007-01-10 20:10 UTC (permalink / raw)
  To: Sascha Sommer; +Cc: LKML, rmk+mmc

Sascha Sommer wrote:
> Hi,
> 
> Attached is a very experimental driver for a Ricoh SD Card reader that can be 
> found in some notebooks like the Samsung P35.
> 

Impressive. Keep up the good work. :)

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-01-06 23:32 Sascha Sommer
  2007-01-07  9:56 ` Jiri Slaby
@ 2007-01-09 20:57 ` Samuel Thibault
  2007-01-10 20:10 ` Pierre Ossman
  2 siblings, 0 replies; 10+ messages in thread
From: Samuel Thibault @ 2007-01-09 20:57 UTC (permalink / raw)
  To: Sascha Sommer; +Cc: LKML, rmk+mmc

[-- Attachment #1: Type: text/plain, Size: 1223 bytes --]

Hi,

Sascha Sommer, le Sun 07 Jan 2007 00:32:26 +0100, a écrit :
> Attached is a very experimental driver for a Ricoh SD Card reader that can be 
> found in some notebooks like the Samsung P35.

Yehaaaw! That reader can be found on DELL X300 too. It works almost fine
for me, see attached dmesg. These I/O errors didn't prevent me from
mounting a card, though.

> In order to write this driver I hacked qemu to have access to the cardbus 
> bridge containing this card. I then logged the register accesses of the 
> windows xp driver and tryed to analyse them.

Great to see people brave enough to do such tedious work :D

> - I only tested with a 128 MB SD card, no idea what would be needed to support
>   other card types

Unfortunately, I don't have other cards either.

> - only tested with kernel 2.6.18

Tested with 2.6.19 without source change.

> apart from all these problems reading an image from my sd card seems to have 
> worked ;) 

The IO errors make dd stop on my box. I tried to set TIMEOUT to 1000
(this is a slow card) without better results. Tell me if there are
things I can test.

I'm not subscribed to linux-kernel, so please remember to Cc me when
posting updates, etc. so I can test them.

Samuel

[-- Attachment #2: dmesg --]
[-- Type: text/plain, Size: 1993 bytes --]

pccard: PCMCIA card inserted into slot 0
pcmcia: registering new device pcmcia0.0
sdricoh_cs: no version for "struct_module" found: kernel tainted.
mmcblk0: mmc0:b370 SD128 123008KiB (ro)
 mmcblk0: p1
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
mmcblk0: error 1 sending read/write command
end_request: I/O error, dev mmcblk0, sector 32
Buffer I/O error on device mmcblk0, logical block 4
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
mmcblk0: error 1 sending read/write command
end_request: I/O error, dev mmcblk0, sector 56
Buffer I/O error on device mmcblk0, logical block 7
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
mmcblk0: error 1 sending read/write command
end_request: I/O error, dev mmcblk0, sector 80
Buffer I/O error on device mmcblk0, logical block 10
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
sdricoh_cs: timeout waiting for data
mmcblk0: error 1 sending read/write command
end_request: I/O error, dev mmcblk0, sector 112
Buffer I/O error on device mmcblk0, logical block 14
pccard: card ejected from slot 0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Experimental driver for Ricoh Bay1Controller SD Card readers
  2007-01-06 23:32 Sascha Sommer
@ 2007-01-07  9:56 ` Jiri Slaby
  2007-02-11 20:22   ` Sascha Sommer
  2007-01-09 20:57 ` Samuel Thibault
  2007-01-10 20:10 ` Pierre Ossman
  2 siblings, 1 reply; 10+ messages in thread
From: Jiri Slaby @ 2007-01-07  9:56 UTC (permalink / raw)
  To: Sascha Sommer; +Cc: LKML, rmk+mmc

Sascha Sommer wrote:
> Hi,
> 
> Attached is a very experimental driver for a Ricoh SD Card reader that can be 
> found in some notebooks like the Samsung P35.
> 
> Whenever a sd card is inserted into one of these notebooks, a virtual pcmcia 
> card will show up:
> 
> Socket 0:
>   product info: "RICOH", "Bay1Controller", "", ""
>   manfid: 0x0000, 0x0000
> 
> In order to write this driver I hacked qemu to have access to the cardbus 
> bridge containing this card. I then logged the register accesses of the 
> windows xp driver and tryed to analyse them.
> 
> As the meanings of most of the register are still unknown to me, I consider 
> this driver very experimental. It is possible that this driver might destroy 
> your data or your hardware. Use at your own risk! 
> 
> Other problems:
> - I only implemented reading support
> - I only tested with a 128 MB SD card, no idea what would be needed to support
>   other card types
> - irqs are not supported
> - dma is not supported
> - it is very slow
> - the registers can be found on the cardbus bridge and not on the virtual 
>   pcmcia card. The cardbus bridge is already claimed by yenta_socket. 
>   Therefore the driver currently uses pci_find_device to find the cardbus

- pci_find_device is no go today. Use pci_get_device (+ pci_dev_get, _put).
- ioremap->pci_iomap
- iobase should be __iomem.
- codingstyle (char* buffer, for(loop, if(data){, ...)

regards,
-- 
http://www.fi.muni.cz/~xslaby/            Jiri Slaby
faculty of informatics, masaryk university, brno, cz
e-mail: jirislaby gmail com, gpg pubkey fingerprint:
B674 9967 0407 CE62 ACC8  22A0 32CC 55C3 39D4 7A7E

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Experimental driver for Ricoh Bay1Controller SD Card readers
@ 2007-01-06 23:32 Sascha Sommer
  2007-01-07  9:56 ` Jiri Slaby
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Sascha Sommer @ 2007-01-06 23:32 UTC (permalink / raw)
  To: LKML; +Cc: rmk+mmc

[-- Attachment #1: Type: text/plain, Size: 1654 bytes --]

Hi,

Attached is a very experimental driver for a Ricoh SD Card reader that can be 
found in some notebooks like the Samsung P35.

Whenever a sd card is inserted into one of these notebooks, a virtual pcmcia 
card will show up:

Socket 0:
  product info: "RICOH", "Bay1Controller", "", ""
  manfid: 0x0000, 0x0000

In order to write this driver I hacked qemu to have access to the cardbus 
bridge containing this card. I then logged the register accesses of the 
windows xp driver and tryed to analyse them.

As the meanings of most of the register are still unknown to me, I consider 
this driver very experimental. It is possible that this driver might destroy 
your data or your hardware. Use at your own risk! 

Other problems:
- I only implemented reading support
- I only tested with a 128 MB SD card, no idea what would be needed to support
  other card types
- irqs are not supported
- dma is not supported
- it is very slow
- the registers can be found on the cardbus bridge and not on the virtual 
  pcmcia card. The cardbus bridge is already claimed by yenta_socket. 
  Therefore the driver currently uses pci_find_device to find the cardbus
  bridge containing the sd card reader registers.
- it will probably crash when you remove the sd card without unmounting first
- the ios stuff is not really understood
- there are a bunch of extra MMC_APP_CMDs inside the driver
- only tested with kernel 2.6.18

apart from all these problems reading an image from my sd card seems to have 
worked ;) 

If you are still brave enough to try it out make at least a backup of the data 
on your sd card.

Feedback is highly appreciated.

Regards

Sascha


[-- Attachment #2: Makefile --]
[-- Type: text/x-makefile, Size: 406 bytes --]

KERNEL_VERSION = $(shell uname -r)
KERNEL_DIR = /lib/modules/$(KERNEL_VERSION)/build
MDIR = /lib/modules/$(KERNEL_VERSION)/kernel/drivers/mmc

obj-m += sdricoh_cs.o

default:
	$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules

install:
	if test ! -d $(MDIR) ; then mkdir -p $(MDIR) ; fi
	install -D -m 644 *.ko $(MDIR)
	depmod -a

clean:
	rm -f *.o *.ko *.mod.c .*o.cmd .*o.d .*o.flags
	rm -rf .tmp_versions

[-- Attachment #3: sdricoh_cs.c.gz --]
[-- Type: application/x-gzip, Size: 4197 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2007-03-09 13:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-15 22:34 Experimental driver for Ricoh Bay1Controller SD Card readers Ivan Babkin
2007-03-09 13:23 ` James
  -- strict thread matches above, loose matches on Subject: below --
2007-01-06 23:32 Sascha Sommer
2007-01-07  9:56 ` Jiri Slaby
2007-02-11 20:22   ` Sascha Sommer
2007-02-13  5:47     ` Pierre Ossman
2007-02-13  9:48       ` Samuel Thibault
2007-02-13 11:42       ` Sascha Sommer
2007-01-09 20:57 ` Samuel Thibault
2007-01-10 20:10 ` Pierre Ossman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).