📄 flash.c
字号:
if(!chip) { printk("Flash: illegal ptr 0x%p in flash_write.\n", ptr); return -EINVAL; } flashStart = (flashptr)chip->start; programAddress = (flashptr)ptr; /* if the block doesn't fit in this flash chip, clamp the size */ fsize = (ptr + size) > (chip->start + chip->size) ? (chip->start + chip->size - ptr) : size; ptr += fsize; size -= fsize; odd_size = fsize & 1; fsize >>= 1; /* We write one word at a time. */ FDEBUG(printk("flash_write (flash start 0x%p) %d words to 0x%p\n", flashStart, fsize, programAddress)); for (i = 0; i < fsize; i++) { int retries = 0; do { int timeout; /* Start programming sequence. */#ifdef IRQ_LOCKS unsigned long flags; save_flags(flags); cli();#endif flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = programUnlockData; *programAddress = *theData; /* give the busy signal time to activate (tBusy, 90 ns) */ nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); /* Wait for programming to finish. */ timeout = 500000; while(timeout-- && (*programAddress & D8_MASK) != (*theData & D8_MASK)) { if (*programAddress & D5_MASK) break; } /* nothing */;#ifdef IRQ_LOCKS restore_flags(flags);#endif if(timeout <= 0) printk("flash: write timeout 0x%p\n", programAddress); if (*programAddress == *theData) break; printk("Flash: verify error 0x%p. " "(flash_write() 1)\n", programAddress); printk("*programAddress = 0x%04x, " "*theData = 0x%04x\n", *programAddress, *theData); } while(++retries < 5); if(retries >= 5) { printk("FATAL FLASH ERROR (1)\n"); return -EIO; /* we failed... */ } programAddress++; theData++; } /* We should write one extra byte to the flash. */ if (odd_size) { unsigned char last_byte[2]; int retries = 0; last_byte[0] = *(unsigned char *)theData; last_byte[1] = ((unsigned char *)programAddress)[1]; do { int timeout = 500000;#ifdef IRQ_LOCKS unsigned long flags; save_flags(flags); cli();#endif flashStart[unlockAddress1] = unlockData1; flashStart[unlockAddress2] = unlockData2; flashStart[unlockAddress1] = programUnlockData; *programAddress = *(flashptr) last_byte; /* give the busy signal time enough to activate (tBusy, 90 ns) */ nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); /* Wait for programming to finish */ while(timeout-- && (*programAddress & D8_MASK) != ((* (flashptr) last_byte) & D8_MASK)) { if (*programAddress & D5_MASK) break; }#ifdef IRQ_LOCKS restore_flags(flags);#endif if(timeout <= 0) printk("flash: write timeout 0x%p\n", programAddress); if (*programAddress == * (flashptr) last_byte) break; printk("Flash: verify error 0x%p. " "(flash_write() 2)\n", programAddress); } while(++retries < 5); if(retries >= 5) { printk("FATAL FLASH ERROR (2)\n"); return -EIO; /* we failed... */ } } }#else /* in the simulator we simulate flash as ram, so we can use a simple memcpy */ printk("flash write, source %p dest %p size %d\n", source, ptr, size); memcpy(ptr, source, size);#endif return 0;}/* "Memset" a chunk of memory on the flash. * do this by flash_write()'ing a pattern chunk. */intflash_memset(unsigned char *ptr, const __u8 c, unsigned long size){#ifndef CONFIG_SVINTO_SIM static unsigned char pattern[16]; int i; /* fill up pattern */ for(i = 0; i < 16; i++) pattern[i] = c; /* write as many 16-byte chunks as we can */ while(size >= 16) { flash_write(ptr, pattern, 16); size -= 16; ptr += 16; } /* and the rest */ if(size) flash_write(ptr, pattern, size);#else /* In the simulator, we simulate flash as ram, so we can use a simple memset. */ printk("flash memset, byte 0x%x dest %p size %d\n", c, ptr, size); memset(ptr, c, size);#endif return 0;}#ifdef CONFIG_BLK_DEV_FLASH/* the operations supported by the block device */static struct file_operations flash_block_fops ={ NULL, /* lseek - default */ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ NULL, /* poll */ flash_ioctl, /* ioctl */ NULL, /* mmap */ flash_open, /* open */ flash_release, /* release */ block_fsync, /* fsync */ NULL, /* fasync */ NULL, /* check media change */ NULL /* revalidate */};#endif#ifdef CONFIG_CHR_DEV_FLASH/* the operations supported by the char device */static struct file_operations flash_char_fops ={ NULL, /* lseek - default */ flash_char_read, /* read */ flash_char_write, /* write */ NULL, /* readdir - bad */ NULL, /* poll */ flash_ioctl, /* ioctl */ NULL, /* mmap */ flash_open, /* open */ flash_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check media change */ NULL /* revalidate */};#endif/* Initialize the flash_partitions array, by reading the partition information from the * partition table (if there is any). Otherwise use a default partition set. * * The first partition is always sector 0 on the first chip, so start by initializing that. * TODO: partitions only reside on chip[0] now. check that. */static voidflash_init_partitions(){ struct partitiontable_head *ptable_head; struct partitiontable_entry *ptable; int use_default_ptable = 1; /* Until proven otherwise */ int pidx = 0; int pidx_before_probe = 0; const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n"; /* if there is no chip 0, there is no bootblock => no partitions at all */ if (chips[0].isValid) { printk("Checking flash partitions:\n"); /* First sector in the flash is partition 0, regardless of if it's a real flash "bootblock" or not. */ partitions[0].chip = &chips[0]; partitions[0].start = chips[0].start; partitions[0].size = chips[0].sectorsize; partitions[0].flags = 0; /* FIXME */ flash_sizes[FLASH_MINOR] = partitions[0].size >> BLOCK_SIZE_BITS; FDEBUG(printk(pmsg, 0, partitions[0].start, partitions[0].size)); pidx++; ptable_head = (struct partitiontable_head *) (partitions[0].start + partitions[0].size + PARTITION_TABLE_OFFSET);#ifdef CONFIG_SVINTO_SIM /* If running in the simulator, do not scan nonexistent memory. Behave as when the bootblock is "broken". ??? FIXME: Maybe there's something better to do. */ partitions[pidx].chip = &chips[0]; partitions[pidx].start = chips[0].start; partitions[pidx].size = chips[0].size; partitions[pidx].flags = 0; /* FIXME */ flash_sizes[FLASH_MINOR + pidx] = partitions[pidx].size >> BLOCK_SIZE_BITS; printk(pmsg, pidx, partitions[pidx].start, partitions[pidx].size); pidx++;#else /* ! defined CONFIG_SVINTO_SIM */ pidx_before_probe = pidx; /* TODO: until we've defined a better partition table, * always do the default flash1 and flash2 partitions. */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) && (ptable_head->size < (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4)) && (*(unsigned long*) ((void*)ptable_head + sizeof(*ptable_head) + ptable_head->size - 4) == PARTITIONTABLE_END_MARKER)) { /* Looks like a start, sane length and end of a * partition table, lets check csum etc. */ int ptable_ok = 0; struct partitiontable_entry *max_addr = (struct partitiontable_entry *) ((unsigned long)ptable_head + sizeof(*ptable_head) + ptable_head->size); unsigned long offset = chips[0].sectorsize; unsigned char *p; unsigned long csum = 0; ptable = (struct partitiontable_entry *) ((unsigned long)ptable_head + sizeof(*ptable_head)); /* Lets be PARANOID, and check the checksum. */ p = (unsigned char*) ptable; while (p <= (unsigned char*)max_addr) { csum += *p++; csum += *p++; csum += *p++; csum += *p++; } printk(" total csum: 0x%08X 0x%08X\n", csum, ptable_head->checksum); ptable_ok = (csum == ptable_head->checksum); /* Read the entries and use/show the info. */ ptable = (struct partitiontable_entry *) ((unsigned long)ptable_head + sizeof(*ptable_head)); printk(" Found %s partition table at 0x%08lX-0x%08lX.\n", (ptable_ok ? "valid" : "invalid"), (unsigned long)ptable_head, (unsigned long)max_addr); /* We have found a working bootblock. Now read the partition table. Scan the table. It ends when there is 0xffffffff, that is, empty flash. */ while (ptable_ok && ptable->offset != 0xffffffff && ptable < max_addr && pidx < MAX_PARTITIONS) { partitions[pidx].chip = &chips[0]; if ((offset + ptable->offset) >= chips[0].size) { partitions[pidx].start = offset + chips[1].start + ptable->offset - chips[0].size; } else { partitions[pidx].start = offset + chips[0].start + ptable->offset; } partitions[pidx].size = ptable->size; partitions[pidx].flags = ptable->flags; partitions[pidx].type = ptable->type; flash_sizes[FLASH_MINOR + pidx] = partitions[pidx].size >> BLOCK_SIZE_BITS; printk(pmsg, pidx, partitions[pidx].start, partitions[pidx].size); pidx++; ptable++; }#ifdef CONFIG_USE_FLASH_PARTITION_TABLE use_default_ptable = !ptable_ok;#endif }printk("Checking flash partitions:\n"); if (use_default_ptable) { /* the flash is split into flash1, flash2 and bootblock * (flash0) */ pidx = pidx_before_probe; FDEBUG(printk(" Using default flash1 and flash2.\n")); printk(" Using default flash1:.\n"); /* flash1 starts after the first sector */ partitions[pidx].chip = &chips[0]; partitions[pidx].start = chips[0].start + chips[0].sectorsize; partitions[pidx].size = chips[0].size - (DEF_FLASH2_SIZE + partitions[0].size); partitions[pidx].flags = 0; /* FIXME */ flash_sizes[FLASH_MINOR + pidx] = partitions[pidx].size >> BLOCK_SIZE_BITS; printk(pmsg, pidx, partitions[pidx].start, partitions[pidx].size); pidx++; /* flash2 starts after flash1. */ partitions[pidx].chip = &chips[0]; partitions[pidx].start = partitions[pidx - 1].start + partitions[pidx - 1].size; partitions[pidx].size = DEF_FLASH2_SIZE; partitions[pidx].flags = 0; /* FIXME */ flash_sizes[FLASH_MINOR + pidx] = partitions[pidx].size >> BLOCK_SIZE_BITS; FDEBUG(printk(pmsg, pidx, partitions[pidx].start, partitions[pidx].size)); pidx++; }#endif /* ! defined CONFIG_SVINTO_SIM */ } /* fill in the rest of the table as well */ while (pidx < MAX_PARTITIONS) { partitions[pidx].start = 0; partitions[pidx].size = 0; partitions[pidx].chip = 0; pidx++; } /*flash_blk_sizes[FLASH_MINOR + i] = 1024; TODO this should be 512.. */}#ifdef LISAHACKstatic voidmove_around_bootparams(){ unsigned long *newp = (unsigned long *)0x8000c000; /* new bootsector */ unsigned long *oldp = (unsigned long *)0x801fc000; /* old bootsector */ unsigned long *buf; unsigned long magic = 0xbeefcace; printk("Checking if we need to move bootparams..."); /* First check if they are already moved. */ if(*newp == magic) { printk(" no\n"); return; } printk(" yes. Moving..."); buf = (unsigned long *)kmalloc(0x4000, GFP_KERNEL); memcpy(buf, oldp, 0x4000); flash_write((unsigned char *)newp, (unsigned char *)&magic, 4); flash_write((unsigned char *)(newp + 1), (unsigned char *)buf, 0x4000 - 4); /* Erase old boot block, so JFFS can expand into it. */ flash_init_erase((unsigned char *)0x801f0000, chips[0].sectorsize); flash_busy_wait_erase(chips[0].start); printk(" done.\n"); kfree(buf);}#endif/* register the device into the kernel - called at boot */intflash_init(){#ifdef CONFIG_BLK_DEV_FLASH /* register the block device major */ if(register_blkdev(MAJOR_NR, DEVICE_NAME, &flash_block_fops )) { printk(KERN_ERR DEVICE_NAME ": Unable to get major %d\n", MAJOR_NR); return -EBUSY; } /* register the actual block I/O function - do_flash_request - and the * tables containing the device sizes (in 1kb units) and block sizes */ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; blk_size[MAJOR_NR] = flash_sizes; blksize_size[MAJOR_NR] = flash_blk_sizes; read_ahead[MAJOR_NR] = 1; /* fast device, so small read ahead */ printk("Flash/ROM block device v2.1, (c) 1999 Axis Communications AB\n"); printk("Driver for SST39VF160 Flash block device v1.0, (c) 2001 Zhihui Li,Wanhe Corp.,Ltd.\n");#endif#ifdef CONFIG_CHR_DEV_FLASH /* register the char device major */ if(register_chrdev(MAJOR_NR, DEVICE_NAME, &flash_char_fops )) { printk(KERN_ERR DEVICE_NAME ": Unable to get major %d\n", MAJOR_NR); return -EBUSY; } printk("Flash/ROM char device v2.1, (c) 1999 Axis Communications AB\n");#endif /* initialize partition table */ flash_init_partitions();#ifdef LISAHACK /* nasty hack to "upgrade" older beta units of Lisa into newer by * moving the boot block parameters. will go away as soon as this * build is done. */ move_around_bootparams();#endif return 0;}/* check if it's possible to erase the wanted range, and if not, return * the range that IS erasable, or a negative error code. */longflash_erasable_size(void *_part, __u32 offset, __u32 size){ struct flashpartition *part = (struct flashpartition *)_part; int ssize; if (!part->start) { return -EINVAL; } /* assume that sector size for a partition is constant even * if it spans more than one chip (you usually put the same * type of chips in a system) */ ssize = part->chip->sectorsize; if (offset % ssize) { /* The offset is not sector size aligned. */ return -1; } else if (offset > part->size) { return -2; } else if (offset + size > part->size) { return -3; } return (size / ssize) * ssize;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -