⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alauda.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * MTD driver for Alauda chips * * Copyright (C) 2007 Joern Engel <joern@logfs.org> * * Based on drivers/usb/usb-skeleton.c which is: * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * and on drivers/usb/storage/alauda.c, which is: *   (c) 2005 Daniel Drake <dsd@gentoo.org> * * Idea and initial work by Arnd Bergmann <arnd@arndb.de> */#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/kref.h>#include <linux/usb.h>#include <linux/mutex.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand_ecc.h>/* Control commands */#define ALAUDA_GET_XD_MEDIA_STATUS	0x08#define ALAUDA_ACK_XD_MEDIA_CHANGE	0x0a#define ALAUDA_GET_XD_MEDIA_SIG		0x86/* Common prefix */#define ALAUDA_BULK_CMD			0x40/* The two ports */#define ALAUDA_PORT_XD			0x00#define ALAUDA_PORT_SM			0x01/* Bulk commands */#define ALAUDA_BULK_READ_PAGE		0x84#define ALAUDA_BULK_READ_OOB		0x85 /* don't use, there's a chip bug */#define ALAUDA_BULK_READ_BLOCK		0x94#define ALAUDA_BULK_ERASE_BLOCK		0xa3#define ALAUDA_BULK_WRITE_PAGE		0xa4#define ALAUDA_BULK_WRITE_BLOCK		0xb4#define ALAUDA_BULK_RESET_MEDIA		0xe0/* Address shifting */#define PBA_LO(pba) ((pba & 0xF) << 5)#define PBA_HI(pba) (pba >> 3)#define PBA_ZONE(pba) (pba >> 11)#define TIMEOUT HZstatic struct usb_device_id alauda_table [] = {	{ USB_DEVICE(0x0584, 0x0008) },	/* Fujifilm DPC-R1 */	{ USB_DEVICE(0x07b4, 0x010a) },	/* Olympus MAUSB-10 */	{ }};MODULE_DEVICE_TABLE(usb, alauda_table);struct alauda_card {	u8	id;		/* id byte */	u8	chipshift;	/* 1<<chipshift total size */	u8	pageshift;	/* 1<<pageshift page size */	u8	blockshift;	/* 1<<blockshift block size */};struct alauda {	struct usb_device	*dev;	struct usb_interface	*interface;	struct mtd_info		*mtd;	struct alauda_card	*card;	struct mutex		card_mutex;	u32			pagemask;	u32			bytemask;	u32			blockmask;	unsigned int		write_out;	unsigned int		bulk_in;	unsigned int		bulk_out;	u8			port;	struct kref		kref;};static struct alauda_card alauda_card_ids[] = {	/* NAND flash */	{ 0x6e, 20, 8, 12},	/* 1 MB */	{ 0xe8, 20, 8, 12},	/* 1 MB */	{ 0xec, 20, 8, 12},	/* 1 MB */	{ 0x64, 21, 8, 12},	/* 2 MB */	{ 0xea, 21, 8, 12},	/* 2 MB */	{ 0x6b, 22, 9, 13},	/* 4 MB */	{ 0xe3, 22, 9, 13},	/* 4 MB */	{ 0xe5, 22, 9, 13},	/* 4 MB */	{ 0xe6, 23, 9, 13},	/* 8 MB */	{ 0x73, 24, 9, 14},	/* 16 MB */	{ 0x75, 25, 9, 14},	/* 32 MB */	{ 0x76, 26, 9, 14},	/* 64 MB */	{ 0x79, 27, 9, 14},	/* 128 MB */	{ 0x71, 28, 9, 14},	/* 256 MB */	/* MASK ROM */	{ 0x5d, 21, 9, 13},	/* 2 MB */	{ 0xd5, 22, 9, 13},	/* 4 MB */	{ 0xd6, 23, 9, 13},	/* 8 MB */	{ 0x57, 24, 9, 13},	/* 16 MB */	{ 0x58, 25, 9, 13},	/* 32 MB */	{ }};static struct alauda_card *get_card(u8 id){	struct alauda_card *card;	for (card = alauda_card_ids; card->id; card++)		if (card->id == id)			return card;	return NULL;}static void alauda_delete(struct kref *kref){	struct alauda *al = container_of(kref, struct alauda, kref);	if (al->mtd) {		del_mtd_device(al->mtd);		kfree(al->mtd);	}	usb_put_dev(al->dev);	kfree(al);}static int alauda_get_media_status(struct alauda *al, void *buf){	int ret;	mutex_lock(&al->card_mutex);	ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),			ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);	mutex_unlock(&al->card_mutex);	return ret;}static int alauda_ack_media(struct alauda *al){	int ret;	mutex_lock(&al->card_mutex);	ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),			ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);	mutex_unlock(&al->card_mutex);	return ret;}static int alauda_get_media_signatures(struct alauda *al, void *buf){	int ret;	mutex_lock(&al->card_mutex);	ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),			ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);	mutex_unlock(&al->card_mutex);	return ret;}static void alauda_reset(struct alauda *al){	u8 command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,		0, 0, 0, 0, al->port	};	mutex_lock(&al->card_mutex);	usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);	mutex_unlock(&al->card_mutex);}static void correct_data(void *buf, void *read_ecc,		int *corrected, int *uncorrected){	u8 calc_ecc[3];	int err;	nand_calculate_ecc(NULL, buf, calc_ecc);	err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);	if (err) {		if (err > 0)			(*corrected)++;		else			(*uncorrected)++;	}}struct alauda_sg_request {	struct urb *urb[3];	struct completion comp;};static void alauda_complete(struct urb *urb){	struct completion *comp = urb->context;	if (comp)		complete(comp);}static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,		void *oob){	struct alauda_sg_request sg;	struct alauda *al = mtd->priv;	u32 pba = from >> al->card->blockshift;	u32 page = (from >> al->card->pageshift) & al->pagemask;	u8 command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),		PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port	};	int i, err;	for (i=0; i<3; i++)		sg.urb[i] = NULL;	err = -ENOMEM;	for (i=0; i<3; i++) {		sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);		if (!sg.urb[i])			goto out;	}	init_completion(&sg.comp);	usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,			alauda_complete, NULL);	usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,			alauda_complete, NULL);	usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,			alauda_complete, &sg.comp);	mutex_lock(&al->card_mutex);	for (i=0; i<3; i++) {		err = usb_submit_urb(sg.urb[i], GFP_NOIO);		if (err)			goto cancel;	}	if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {		err = -ETIMEDOUT;cancel:		for (i=0; i<3; i++) {			usb_kill_urb(sg.urb[i]);		}	}	mutex_unlock(&al->card_mutex);out:	usb_free_urb(sg.urb[0]);	usb_free_urb(sg.urb[1]);	usb_free_urb(sg.urb[2]);	return err;}static int alauda_read_page(struct mtd_info *mtd, loff_t from,		void *buf, u8 *oob, int *corrected, int *uncorrected){	int err;	err = __alauda_read_page(mtd, from, buf, oob);	if (err)		return err;	correct_data(buf, oob+13, corrected, uncorrected);	correct_data(buf+256, oob+8, corrected, uncorrected);	return 0;}static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,		void *oob){	struct alauda_sg_request sg;	struct alauda *al = mtd->priv;	u32 pba = to >> al->card->blockshift;	u32 page = (to >> al->card->pageshift) & al->pagemask;	u8 command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),		PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port	};	int i, err;	for (i=0; i<3; i++)		sg.urb[i] = NULL;	err = -ENOMEM;	for (i=0; i<3; i++) {		sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);		if (!sg.urb[i])			goto out;	}	init_completion(&sg.comp);	usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,			alauda_complete, NULL);	usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,			alauda_complete, NULL);	usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,			alauda_complete, &sg.comp);	mutex_lock(&al->card_mutex);	for (i=0; i<3; i++) {		err = usb_submit_urb(sg.urb[i], GFP_NOIO);		if (err)			goto cancel;	}	if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {		err = -ETIMEDOUT;cancel:		for (i=0; i<3; i++) {			usb_kill_urb(sg.urb[i]);		}	}	mutex_unlock(&al->card_mutex);out:	usb_free_urb(sg.urb[0]);	usb_free_urb(sg.urb[1]);	usb_free_urb(sg.urb[2]);	return err;}static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs){	struct alauda_sg_request sg;	struct alauda *al = mtd->priv;	u32 pba = ofs >> al->card->blockshift;	u8 command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),		PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port	};	u8 buf[2];	int i, err;	for (i=0; i<2; i++)		sg.urb[i] = NULL;	err = -ENOMEM;	for (i=0; i<2; i++) {		sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);		if (!sg.urb[i])			goto out;	}	init_completion(&sg.comp);	usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,			alauda_complete, NULL);	usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,			alauda_complete, &sg.comp);	mutex_lock(&al->card_mutex);	for (i=0; i<2; i++) {		err = usb_submit_urb(sg.urb[i], GFP_NOIO);		if (err)			goto cancel;	}	if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {		err = -ETIMEDOUT;cancel:		for (i=0; i<2; i++) {			usb_kill_urb(sg.urb[i]);		}	}	mutex_unlock(&al->card_mutex);out:	usb_free_urb(sg.urb[0]);	usb_free_urb(sg.urb[1]);	return err;}static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob){	static u8 ignore_buf[512]; /* write only */	return __alauda_read_page(mtd, from, ignore_buf, oob);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -