📄 nandsys.c
字号:
FlashInitRoutine, do_nothing, Flash1_ChipSelect, FlashReadByte, FlashWriteByte, FlashBlockRead, FlashBlockWrite, FlashCoreLeds, mk_delay }, { FlashInitRoutine, do_nothing, Flash2_ChipSelect, FlashReadByte, FlashWriteByte, FlashBlockRead, FlashBlockWrite, FlashCoreLeds, mk_delay }};/* nand_flash_init: register the block device number and set up pointer tables */int __init nand_flash_init (void){ int i, flash_id; printk ("Nand Flash disk driver for CompuLab 786Core\r\nInterrupt disabling: %s\r\n", flashdisableintr?"Enabled":"Disabled"); // Validate that ATA DMA is not enabled if(!ignore_ata_var){ if (PciReadRegisterDWord (0x48, 0, 31, 1) & 0x0F) { printk ("Error: DMA is enabled for ATA.\r\nPlease build your kernel.\r\n"); return -1; } } for (flash_id = 0; flash_id < MAX_FLASHN; flash_id++) { if (format) printk ("Formatting Nand flash %d . . .\n", flash_id); flogic[flash_id] = cl_logic_create (&cl_nand_linux[flash_id], 128, format); if (!flogic[flash_id]) { cl_error_log ("Flash %d initialization failed.\n", flash_id); if(!flash_id) return -1; } } memset (flash_struct, 0, sizeof (flash_struct)); if (devfs_register_blkdev (MAJOR_NR, DEVICE_NAME, &flash_fops)) { printk("flash: Unable to get major number %d\n",MAJOR_NR); return -1; } devfs_handle = devfs_mk_dir (NULL, flash_gendisk.major_name, NULL); blk_init_queue (BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ /* Insert this disk into linked list of disks */ flash_gendisk.next = gendisk_head; gendisk_head = &flash_gendisk; /* Sizes initialization */ for (i = 0; i < (MAX_FLASHN << 6); i++) flash_blocksizes[i] = 1024; /* Blocks' sizes must be 1 KB */ blksize_size[MAJOR_NR] = flash_blocksizes; for (flash_id = 0; flash_id < MAX_FLASHN; flash_id++) if (flogic[flash_id]) { cl_trace_log (("Registering flash disk %d\r\n", flash_id)); register_disk (&flash_gendisk, MKDEV(MAJOR_NR, (flash_id << 6)), (1 << 6), &flash_fops, cl_logic_get_param (flogic[flash_id], CL_FLASH_TOTAL_SIZE, 0) / 512); } /* Starting flush timer: the cl_timer_proc will be executed on each timer interrupt */ cl_trace_log (("Starting timer task\r\n", flash_id)); queue_task(&timerTask, &tq_timer); return 0;}/* flash_open: open a device */static int flash_open (struct inode *inode, struct file *file){ int dev = DEVICE_NR(inode->i_rdev); MOD_INC_USE_COUNT; if ((dev >= 0) && (dev < MAX_FLASHN) && flogic[dev]) { cl_trace_log (("Flash device %d opened.\n", dev)); return 0; /* The device is valid */ } cl_trace_log (("Opening flash device %d failed.\n", dev)); MOD_DEC_USE_COUNT; return -ENXIO;}static int flash_check_media_change (kdev_t dev){ return 0; /* Disk not changed */}static void cl_timer_proc (void* unused){ static int cnt = 0; if (!(cnt++ & 3) && !StopLaunchTimer) { /* Timer is 18 times a second. We take only 1/4 */ /* Flush all cached data if ~100ms has elapsed since last write */ if (last_end_write_cmd && (jiffies - last_end_write_cmd > HZ / 10)) { queue_task (&flushTask, &tq_disk); } } /* Reschedule timer */ /* If cleanup wants us to die */ if (StopLaunchTimer) queue_task (&flushTask, &tq_disk); else queue_task (&timerTask, &tq_timer); }/* This function is called by scheduler and it doesn't run in interrupts */static void cl_flush_proc (void* unused){ int flash_id; cl_trace_log (("cl_flush_proc called\r\n")); down (&flash_sem); for (flash_id = 0; flash_id < MAX_FLASHN; flash_id++) if (flogic[flash_id]) cl_logic_sync (flogic[flash_id]); cl_trace_log (("Data synced\r\n")); last_end_write_cmd = 0; up (&flash_sem); if (StopLaunchTimer) wake_up (&WaitQ); /* Now cleanup_module can return */}/* do_flash_request: handle an incoming request */static void do_flash_request (request_queue_t * q){ u_int block, count; int code, i; sti(); while (code = 0, !QUEUE_EMPTY) { INIT_REQUEST; /* do some checking on the request structure */ if ((CURRENT_DEV < MAX_FLASHN) && flogic[CURRENT_DEV]) { block = CURRENT->sector + flash_struct[MINOR(CURRENT->rq_dev)].start_sect; count = CURRENT->current_nr_sectors; /* printk ("Flash %d %s, start_sect = %d, total = %d, nr_sectors = %d, part_start = %d\r\n", CURRENT_DEV, ((CURRENT->cmd == READ) ? "read" : "write"), (int)block, (int)count, (int)CURRENT->nr_sectors, (int)flash_struct[MINOR(CURRENT->rq_dev)].start_sect);*/ /* Catch semaphore to disable simultaneous flash access from different places */ down (&flash_sem); switch (CURRENT->cmd) { case READ: for (i = 0, code = 1; i < count; i++) { if (!cl_logic_read_sector (flogic[CURRENT_DEV], block + i, (char*)CURRENT->buffer + i * 512)) { code = 0; /* failure */ break; } } break; case WRITE: for (i = 0, code = 1; i < count; i++) { if (!cl_logic_write_sector (flogic[CURRENT_DEV], block + i, (char*)CURRENT->buffer + i * 512)) { code = 0; /* failure */ break; } } last_end_write_cmd = jiffies; break; default: printk("do_flash_request: unknown request\n"); break; } /* Release semaphore */ up (&flash_sem); } else cl_trace_log (("'IF' in request failed.\n")); end_request (code); /* wrap up, 0 = fail, 1 = success */ }}/* flash_ioctl: handle device ioctl's */static int flash_ioctl (struct inode *inode, struct file *file, u_int cmd, u_long arg){ int dev; cl_trace_log (("flash_ioctl called.\n")); if ((!inode) || !(inode->i_rdev)) return -EINVAL; dev = DEVICE_NR(inode->i_rdev); /* Bad flash index */ if ((dev < 0) || (dev >= MAX_FLASHN) || !flogic[dev]) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry *geometry = (struct hd_geometry*)arg; if (!geometry) return -EINVAL; /* Bad arguments to ioctl */ put_user(cl_logic_get_param (flogic[dev], CL_FLASH_CYLINDERS_NUM, 0), &geometry->cylinders); put_user(cl_logic_get_param (flogic[dev], CL_FLASH_HEADS_NUM, 0), &geometry->heads); put_user(cl_logic_get_param (flogic[dev], CL_FLASH_SECTS_NUM, 0), &geometry->sectors); put_user(0, &geometry->start); return 0; } case BLKGETSIZE: if (!arg) return -EINVAL; return put_user (cl_logic_get_param (flogic[dev], CL_FLASH_TOTAL_SIZE, 0) / 512, (long *) arg); case HDIO_SET_DMA: /* We don't use DMA for flash. This has no meaning */ if (!capable (CAP_SYS_ADMIN)) return -EACCES; return 0; case HDIO_GET_DMA: return put_user( 0, (long *) arg); /* No DMA */ case HDIO_GET_MULTCOUNT: /* We don't have a limitation of number of sectors in op. */ return put_user (128, (long *) arg); case BLKRRPART: { int partition; int start = (DEVICE_NR(dev)) << flash_gendisk.minor_shift; if (!capable(CAP_SYS_ADMIN)) return -EACCES; for (partition = flash_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); kdev_t devp = MKDEV(MAJOR_NR, minor); struct super_block* sb = get_super(devp); sync_dev(devp); if (sb) invalidate_inodes(sb); invalidate_buffers(devp); flash_gendisk.part[start + partition].start_sect = 0; flash_gendisk.part[start + partition].nr_sects = 0; } grok_partitions(&flash_gendisk, dev, (1 << 6), cl_logic_get_param (flogic[dev], CL_FLASH_TOTAL_SIZE, 0) / 512); return 0; } case BLKFLSBUF: case BLKROSET: case BLKROGET: case BLKRASET: case BLKRAGET: case BLKPG: return blk_ioctl(inode->i_rdev, cmd, arg); case CL_FLASH_IO_GET_PARAM: { int err; long* prm = (long*)arg; err = verify_area (VERIFY_READ, prm, sizeof(long) * 2); if(err) return err; err = verify_area (VERIFY_WRITE, prm, sizeof (long)); if(err) return err; prm[0] = cl_logic_get_param (flogic[dev], prm[0], prm[1]); return 0; } case CL_FLASH_IO_DIRECT_ACCESS: { int err; long* prm = (long*)arg; err = verify_area (VERIFY_READ, prm, sizeof(long) * 3); if(err) return err; err = verify_area (VERIFY_WRITE, prm, CL_FLASH_SECTOR_SIZE); if(err) return err; return cl_logic_direct_access (flogic[dev], (cl_nand_direct_access_type)prm[0], (unsigned short)prm[1], (unsigned short)prm[2], (unsigned char*)(prm + 3)); } default: return -EINVAL; }}static int flash_revalidate (kdev_t dev){ return 0;}/* flash_release: release the device */static int flash_release (struct inode *inode, struct file *file){ int dev = DEVICE_NR(inode->i_rdev); int flash_id; cl_trace_log (("flash_release called for device %d.\n", dev)); down (&flash_sem); for (flash_id = 0; flash_id < MAX_FLASHN; flash_id++) if (flogic[flash_id]) cl_logic_sync (flogic[flash_id]); cl_trace_log (("Data synced after RELEASE command\r\n")); last_end_write_cmd = 0; up (&flash_sem); if ((dev >= 0) && (dev < MAX_FLASHN) && flogic[dev]) {#ifdef MODULE MOD_DEC_USE_COUNT;#endif /* MODULE */ } return 0;}#ifdef MODULEstatic void flash_done (void){ struct gendisk ** gdp; int flash_id; blksize_size[MAJOR_NR] = NULL; blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); blk_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; /* Remove this disk from linked lisk */ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) if (*gdp == &flash_gendisk) break; if (*gdp) *gdp = (*gdp)->next; /* Free memory allocated by flash module */ for (flash_id = 0; flash_id < MAX_FLASHN; flash_id++) if (flogic[flash_id]) { cl_logic_free (flogic[flash_id]); flogic[flash_id] = NULL; }}int init_module(void){ int error; error = nand_flash_init(); if (error) return error; return 0;}void cleanup_module(void){ int partition, dev, start; /* Stop launching timers */ cl_trace_log (("Stopping launching timers.\n")); StopLaunchTimer = 1; sleep_on (&WaitQ); cl_trace_log (("Done stopping launching timers.\n")); devfs_unregister_blkdev (MAJOR_NR, DEVICE_NAME); for (dev = 0; dev < MAX_FLASHN; dev++) { if (!flogic[dev]) continue; start = (dev << flash_gendisk.minor_shift); for (partition = flash_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); kdev_t devp = MKDEV(MAJOR_NR, minor); start = dev << flash_gendisk.minor_shift; sync_dev(devp); invalidate_buffers(devp); } devfs_unregister (devfs_handle); } flash_done();}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -