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

📄 alauda.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
}static int popcount8(u8 c){	int ret = 0;	for ( ; c; c>>=1)		ret += c & 1;	return ret;}static int alauda_isbad(struct mtd_info *mtd, loff_t ofs){	u8 oob[16];	int err;	err = alauda_read_oob(mtd, ofs, oob);	if (err)		return err;	/* A block is marked bad if two or more bits are zero */	return popcount8(oob[5]) >= 7 ? 0 : 1;}static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,		size_t *retlen, u_char *buf){	struct alauda *al = mtd->priv;	void *bounce_buf;	int err, corrected=0, uncorrected=0;	bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);	if (!bounce_buf)		return -ENOMEM;	*retlen = len;	while (len) {		u8 oob[16];		size_t byte = from & al->bytemask;		size_t cplen = min(len, mtd->writesize - byte);		err = alauda_read_page(mtd, from, bounce_buf, oob,				&corrected, &uncorrected);		if (err)			goto out;		memcpy(buf, bounce_buf + byte, cplen);		buf += cplen;		from += cplen;		len -= cplen;	}	err = 0;	if (corrected)		err = -EUCLEAN;	if (uncorrected)		err = -EBADMSG;out:	kfree(bounce_buf);	return err;}static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,		size_t *retlen, u_char *buf){	struct alauda *al = mtd->priv;	int err, corrected=0, uncorrected=0;	if ((from & al->bytemask) || (len & al->bytemask))		return alauda_bounce_read(mtd, from, len, retlen, buf);	*retlen = len;	while (len) {		u8 oob[16];		err = alauda_read_page(mtd, from, buf, oob,				&corrected, &uncorrected);		if (err)			return err;		buf += mtd->writesize;		from += mtd->writesize;		len -= mtd->writesize;	}	err = 0;	if (corrected)		err = -EUCLEAN;	if (uncorrected)		err = -EBADMSG;	return err;}static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,		size_t *retlen, const u_char *buf){	struct alauda *al = mtd->priv;	int err;	if ((to & al->bytemask) || (len & al->bytemask))		return -EINVAL;	*retlen = len;	while (len) {		u32 page = (to >> al->card->pageshift) & al->pagemask;		u8 oob[16] = {	'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};		/* don't write to bad blocks */		if (page == 0) {			err = alauda_isbad(mtd, to);			if (err) {				return -EIO;			}		}		nand_calculate_ecc(mtd, buf, &oob[13]);		nand_calculate_ecc(mtd, buf+256, &oob[8]);		err = alauda_write_page(mtd, to, (void*)buf, oob);		if (err)			return err;		buf += mtd->writesize;		to += mtd->writesize;		len -= mtd->writesize;	}	return 0;}static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr){	struct alauda *al = mtd->priv;	u32 ofs = instr->addr;	u32 len = instr->len;	int err;	if ((ofs & al->blockmask) || (len & al->blockmask))		return -EINVAL;	while (len) {		/* don't erase bad blocks */		err = alauda_isbad(mtd, ofs);		if (err > 0)			err = -EIO;		if (err < 0)			return err;		err = alauda_erase_block(mtd, ofs);		if (err < 0)			return err;		ofs += mtd->erasesize;		len -= mtd->erasesize;	}	return 0;}static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr){	int err;	err = __alauda_erase(mtd, instr);	instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;	mtd_erase_callback(instr);	return err;}static int alauda_init_media(struct alauda *al){	u8 buf[4], *b0=buf, *b1=buf+1;	struct alauda_card *card;	struct mtd_info *mtd;	int err;	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);	if (!mtd)		return -ENOMEM;	for (;;) {		err = alauda_get_media_status(al, buf);		if (err < 0)			goto error;		if (*b0 & 0x10)			break;		msleep(20);	}	err = alauda_ack_media(al);	if (err)		goto error;	msleep(10);	err = alauda_get_media_status(al, buf);	if (err < 0)		goto error;	if (*b0 != 0x14) {		/* media not ready */		err = -EIO;		goto error;	}	err = alauda_get_media_signatures(al, buf);	if (err < 0)		goto error;	card = get_card(*b1);	if (!card) {		printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);		err = -EIO;		goto error;	}	printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",			1<<card->pageshift, 1<<card->blockshift,			1<<(card->chipshift-20));	al->card = card;	al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;	al->bytemask = (1 << card->pageshift) - 1;	al->blockmask = (1 << card->blockshift) - 1;	mtd->name = "alauda";	mtd->size = 1<<card->chipshift;	mtd->erasesize = 1<<card->blockshift;	mtd->writesize = 1<<card->pageshift;	mtd->type = MTD_NANDFLASH;	mtd->flags = MTD_CAP_NANDFLASH;	mtd->read = alauda_read;	mtd->write = alauda_write;	mtd->erase = alauda_erase;	mtd->block_isbad = alauda_isbad;	mtd->priv = al;	mtd->owner = THIS_MODULE;	err = add_mtd_device(mtd);	if (err) {		err = -ENFILE;		goto error;	}	al->mtd = mtd;	alauda_reset(al); /* no clue whether this is necessary */	return 0;error:	kfree(mtd);	return err;}static int alauda_check_media(struct alauda *al){	u8 buf[2], *b0 = buf, *b1 = buf+1;	int err;	err = alauda_get_media_status(al, buf);	if (err < 0)		return err;	if ((*b1 & 0x01) == 0) {		/* door open */		return -EIO;	}	if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {		/* no media ? */		return -EIO;	}	if (*b0 & 0x08) {		/* media change ? */		return alauda_init_media(al);	}	return 0;}static int alauda_probe(struct usb_interface *interface,		const struct usb_device_id *id){	struct alauda *al;	struct usb_host_interface *iface;	struct usb_endpoint_descriptor *ep,			*ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;	int i, err = -ENOMEM;	al = kzalloc(2*sizeof(*al), GFP_KERNEL);	if (!al)		goto error;	kref_init(&al->kref);	usb_set_intfdata(interface, al);	al->dev = usb_get_dev(interface_to_usbdev(interface));	al->interface = interface;	iface = interface->cur_altsetting;	for (i = 0; i < iface->desc.bNumEndpoints; ++i) {		ep = &iface->endpoint[i].desc;		if (usb_endpoint_is_bulk_in(ep)) {			ep_in = ep;		} else if (usb_endpoint_is_bulk_out(ep)) {			if (i==0)				ep_wr = ep;			else				ep_out = ep;		}	}	err = -EIO;	if (!ep_wr || !ep_in || !ep_out)		goto error;	al->write_out = usb_sndbulkpipe(al->dev,			ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);	al->bulk_in = usb_rcvbulkpipe(al->dev,			ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);	al->bulk_out = usb_sndbulkpipe(al->dev,			ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);	/* second device is identical up to now */	memcpy(al+1, al, sizeof(*al));	mutex_init(&al[0].card_mutex);	mutex_init(&al[1].card_mutex);	al[0].port = ALAUDA_PORT_XD;	al[1].port = ALAUDA_PORT_SM;	dev_info(&interface->dev, "alauda probed\n");	alauda_check_media(al);	alauda_check_media(al+1);	return 0;error:	if (al)		kref_put(&al->kref, alauda_delete);	return err;}static void alauda_disconnect(struct usb_interface *interface){	struct alauda *al;	al = usb_get_intfdata(interface);	usb_set_intfdata(interface, NULL);	/* FIXME: prevent more I/O from starting */	/* decrement our usage count */	if (al)		kref_put(&al->kref, alauda_delete);	dev_info(&interface->dev, "alauda gone");}static struct usb_driver alauda_driver = {	.name =		"alauda",	.probe =	alauda_probe,	.disconnect =	alauda_disconnect,	.id_table =	alauda_table,};static int __init alauda_init(void){	return usb_register(&alauda_driver);}static void __exit alauda_exit(void){	usb_deregister(&alauda_driver);}module_init(alauda_init);module_exit(alauda_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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