cfi_cmdset_0001.c

来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 872 行 · 第 1/2 页

C
872
字号
		if (ret)			break;		*retlen += thislen;		len -= thislen;		buf += thislen;				ofs = 0;		chipnum++;	}	return ret;}static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp=cfi->cmdset_priv;	int ofs_factor = cfi->interleave * cfi->device_type;	int   count=len;	struct flchip *chip;	int chip_num,offst;	unsigned long timeo;	DECLARE_WAITQUEUE(wait, current);	chip=0;	/* Calculate which chip & protection register offset we need */	chip_num=((unsigned int)from/reg_sz);	offst=from-(reg_sz*chip_num)+base_offst;	while(count){				if(chip_num>=cfi->numchips)			goto out;		/* Make sure that the chip is in the right state */		timeo = jiffies + HZ;		chip=&cfi->chips[chip_num];	retry:				spin_lock_bh(chip->mutex);			switch (chip->state) {		case FL_READY:		case FL_STATUS:		case FL_CFI_QUERY:		case FL_JEDEC_QUERY:			break;				default:				/* Stick ourselves on a wait queue to be woken when				   someone changes the status */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock_bh(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + HZ;			goto retry;		}					/* Now read the data required from this flash */       		cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL);		while(count && ((offst-base_offst)<reg_sz)){			*buf=map->read8(map,(chip->start+(extp->ProtRegAddr*ofs_factor)+offst));			buf++;			offst++;			count--;		}	       		chip->state=FL_CFI_QUERY;		spin_unlock_bh(chip->mutex);		/* Move on to the next chip */		chip_num++;		offst=base_offst;		}	 out:		wake_up(&chip->wq);	return len-count;}	static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp=cfi->cmdset_priv;	int base_offst,reg_sz;		/* Check that we actually have some protection registers */	if(!(extp->FeatureSupport&64)){		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);		return 0;	}	base_offst=(1<<extp->FactProtRegSize);	reg_sz=(1<<extp->UserProtRegSize);	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);}static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp=cfi->cmdset_priv;	int base_offst,reg_sz;		/* Check that we actually have some protection registers */	if(!(extp->FeatureSupport&64)){		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);		return 0;	}	base_offst=0;	reg_sz=(1<<extp->FactProtRegSize);	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);}static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum){	struct cfi_private *cfi = map->fldrv_priv;	cfi_word status, status_OK;	unsigned long timeo;	DECLARE_WAITQUEUE(wait, current);	int z;	adr += chip->start;	/* Let's determine this according to the interleave only once */	status_OK = CMD(0x80);	timeo = jiffies + HZ; retry:	spin_lock_bh(chip->mutex);	/* Check that the chip's ready to talk to us.	 * Later, we can actually think about interrupting it	 * if it's in FL_ERASING state.	 * Not just yet, though.	 */	switch (chip->state) {	case FL_READY:		break;			case FL_CFI_QUERY:	case FL_JEDEC_QUERY:		cfi_write(map, CMD(0x70), adr);		chip->state = FL_STATUS;	case FL_STATUS:		status = cfi_read(map, adr);		if ((status & status_OK) == status_OK)			break;				/* Urgh. Chip not yet ready to talk to us. */		if (time_after(jiffies, timeo)) {			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in read\n");			return -EIO;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		goto retry;	default:		/* Stick ourselves on a wait queue to be woken when		   someone changes the status */		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);		spin_unlock_bh(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);		timeo = jiffies + HZ;		goto retry;	}	ENABLE_VPP(map);	cfi_write(map, CMD(0x40), adr);	cfi_write(map, datum, adr);	chip->state = FL_WRITING;	spin_unlock_bh(chip->mutex);	cfi_udelay(chip->word_write_time);	spin_lock_bh(chip->mutex);	timeo = jiffies + (HZ/2);	z = 0;	for (;;) {		if (chip->state != FL_WRITING) {			/* Someone's suspended the write. Sleep */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock_bh(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + (HZ / 2); /* FIXME */			spin_lock_bh(chip->mutex);			continue;		}		status = cfi_read(map, adr);		if ((status & status_OK) == status_OK)			break;				/* OK Still waiting */		if (time_after(jiffies, timeo)) {			chip->state = FL_STATUS;			DISABLE_VPP(map);			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");			return -EIO;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		z++;		cfi_udelay(1);		spin_lock_bh(chip->mutex);	}	if (!z) {		chip->word_write_time--;		if (!chip->word_write_time)			chip->word_write_time++;	}	if (z > 1) 		chip->word_write_time++;	/* Done and happy. */	DISABLE_VPP(map);	chip->state = FL_STATUS;	/* check for lock bit */	if (status & CMD(0x02)) {		/* clear status */		cfi_write(map, CMD(0x50), adr);		/* put back into read status register mode */		cfi_write(map, CMD(0x70), adr);		wake_up(&chip->wq);		spin_unlock_bh(chip->mutex);		return -EROFS;	}	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return 0;}static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int ret = 0;	int chipnum;	unsigned long ofs;	*retlen = 0;	if (!len)		return 0;	chipnum = to >> cfi->chipshift;	ofs = to  - (chipnum << cfi->chipshift);	/* If it's not bus-aligned, do the first byte write */	if (ofs & (CFIDEV_BUSWIDTH-1)) {		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);		int gap = ofs - bus_ofs;		int i = 0, n = 0;		u_char tmp_buf[8];		cfi_word datum;		while (gap--)			tmp_buf[i++] = 0xff;		while (len && i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = buf[n++], len--;		while (i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = 0xff;		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum],					       bus_ofs, datum);		if (ret) 			return ret;				ofs += n;		buf += n;		(*retlen) += n;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}		while(len >= CFIDEV_BUSWIDTH) {		cfi_word datum;		if (cfi_buswidth_is_1()) {			datum = *(__u8*)buf;		} else if (cfi_buswidth_is_2()) {			datum = *(__u16*)buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)buf;		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)buf;		} else {			return -EINVAL;		}		ret = do_write_oneword(map, &cfi->chips[chipnum],				ofs, datum);		if (ret)			return ret;		ofs += CFIDEV_BUSWIDTH;		buf += CFIDEV_BUSWIDTH;		(*retlen) += CFIDEV_BUSWIDTH;		len -= CFIDEV_BUSWIDTH;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	if (len & (CFIDEV_BUSWIDTH-1)) {		int i = 0, n = 0;		u_char tmp_buf[8];		cfi_word datum;		while (len--)			tmp_buf[i++] = buf[n++];		while (i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = 0xff;		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum],					       ofs, datum);		if (ret) 			return ret;				(*retlen) += n;	}	return 0;}static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 				  unsigned long adr, const u_char *buf, int len){	struct cfi_private *cfi = map->fldrv_priv;	cfi_word status, status_OK;	unsigned long cmd_adr, timeo;	DECLARE_WAITQUEUE(wait, current);	int wbufsize, z;	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;	adr += chip->start;	cmd_adr = adr & ~(wbufsize-1);		/* Let's determine this according to the interleave only once */	status_OK = CMD(0x80);	timeo = jiffies + HZ; retry:	spin_lock_bh(chip->mutex);	/* Check that the chip's ready to talk to us.	 * Later, we can actually think about interrupting it	 * if it's in FL_ERASING state.	 * Not just yet, though.	 */	switch (chip->state) {	case FL_READY:	case FL_CFI_QUERY:	case FL_JEDEC_QUERY:		cfi_write(map, CMD(0x70), cmd_adr);		chip->state = FL_STATUS;	case FL_STATUS:		status = cfi_read(map, cmd_adr);		if ((status & status_OK) == status_OK)			break;		/* Urgh. Chip not yet ready to talk to us. */		if (time_after(jiffies, timeo)) {			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");			return -EIO;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		goto retry;	default:		/* Stick ourselves on a wait queue to be woken when		   someone changes the status */		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);		spin_unlock_bh(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);		timeo = jiffies + HZ;		goto retry;	}	/* We know we're now in FL_STATUS mode, and 'status' is current */	/* 

⌨️ 快捷键说明

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