📄 mmc_block.c
字号:
goto out; } else { card = mmc_get_card( host, slot ); if ( !card ) { MMC_DEBUG( MMC_DEBUG_LEVEL2, "failed to get card: " "host=%d, slot=%d\n", host, slot ); __mmc_block_wrunlock_devices(); goto error; } dev->card = card; } __mmc_block_wrunlock_devices(); /* FIXME */ __mmc_block_rdlock_devices(); /* handle the request for sector 0 */ grok_partitions( &mmc_block_gendisk, MINOR( start ), mmc_block_gendisk.max_p, card->info.capacity>>9 /* sectors */ ); __mmc_block_rdunlock_devices(); /* FIXME */ __mmc_block_wrlock_devices(); for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) { int minor = MINOR( i ); dev = &mmc_block_device[minor]; if ( mmc_block_gendisk.part[minor].nr_sects > 0 ) dev->card = card; } __mmc_block_wrunlock_devices();out:error: __LEAVE( "ret=%d", ret ); return ret;}static void mmc_block_handle_request( void ){ struct request *request; mmc_block_device_t dev; mmc_card_t card; char *buf; loff_t pos; unsigned int result = 0; for (;;) { int minor; INIT_REQUEST; request = CURRENT; spin_unlock_irq( &io_request_lock ); minor = MINOR( request->rq_dev ); dev = __mmc_block_get_device( request->rq_dev ); if ( !dev ) { MMC_DEBUG( MMC_DEBUG_LEVEL2, "invalid device (%x:%x)\n", MAJOR( request->rq_dev ), minor ); goto end_req; } card = dev->card; (void)__mmc_block_put_device( dev ); MMC_DEBUG( MMC_DEBUG_LEVEL2, // printk( KERN_INFO __FUNCTION__"(): " "request %p: cmd %i sec %li (nr. %li)\n", CURRENT, CURRENT->cmd, CURRENT->sector, CURRENT->current_nr_sectors ); if ( request->current_nr_sectors > mmc_block_gendisk.part[minor].nr_sects ) goto end_req; // Handle the request // TODO: handle clusterred requests in multiple block transfer mode buf = request->buffer; pos = (mmc_block_gendisk.part[minor].start_sect + request->sector) * MMC_BLOCK_SECT_SIZE; switch ( request->cmd ) { int i, ret; case READ:#if 0 ret = mmc_read( card, (request->current_nr_sectors > 1) ? MMC_TRANSFER_MODE_BLOCK_MULTIPLE : MMC_TRANSFER_MODE_BLOCK_SINGLE, buf, request->current_nr_sectors * MMC_BLOCK_SECT_SIZE, /* FIXME */ &pos ); if ( ret < 0 ) goto end_req; #else for ( i = 0; i < request->current_nr_sectors; i++ ) { ret = mmc_read( card, MMC_TRANSFER_MODE_BLOCK_SINGLE, buf, MMC_BLOCK_SECT_SIZE, /* FIXME */ &pos ); if ( ret < 0 ) goto end_req; else buf += ret; }#endif result = 1; break; case WRITE: // TODO: Read only device#if 0 ret = mmc_write( card, (request->current_nr_sectors > 1) ? MMC_TRANSFER_MODE_BLOCK_MULTIPLE : MMC_TRANSFER_MODE_BLOCK_SINGLE, buf, request->current_nr_sectors * MMC_BLOCK_SECT_SIZE, /* FIXME */ &pos ); if ( ret < 0 ) goto end_req; #else for ( i = 0; i < request->current_nr_sectors; i++ ) { ret = mmc_write( card, MMC_TRANSFER_MODE_BLOCK_SINGLE, buf, MMC_BLOCK_SECT_SIZE, /* FIXME */ &pos ); if ( ret < 0 ) goto end_req; else buf += ret; }#endif result = 1; break; }end_req: __LEAVE( "result=%d", result ); spin_lock_irq( &io_request_lock ); end_request( result ); }}static volatile int leaving = 0;static DECLARE_MUTEX_LOCKED( thread_sem );static DECLARE_WAIT_QUEUE_HEAD( thr_wq );static pid_t thr_id = -1;int mmc_block_thread( void *arg ){ struct task_struct *task = current; DECLARE_WAITQUEUE(wait, task); __ENTER0(); task->session = 1; task->pgrp = 1; task->flags |= PF_MEMALLOC; strcpy( task->comm, "mmcblockd" ); task->tty = NULL; spin_lock_irq( &task->sigmask_lock ); sigfillset( &task->blocked ); recalc_sigpending( task ); spin_unlock_irq( &task->sigmask_lock ); exit_mm( task ); exit_files( task ); exit_sighand( task ); exit_fs( task ); while ( !leaving ) { add_wait_queue( &thr_wq, &wait); set_current_state( TASK_INTERRUPTIBLE ); spin_lock_irq( &io_request_lock ); if ( QUEUE_EMPTY || QUEUE_PLUGGED ) { spin_unlock_irq( &io_request_lock ); schedule(); remove_wait_queue( &thr_wq, &wait ); } else { remove_wait_queue( &thr_wq, &wait ); set_current_state( TASK_RUNNING ); mmc_block_handle_request(); /* handle the request */ spin_unlock_irq( &io_request_lock ); } } up( &thread_sem ); __LEAVE0(); return 0;}#if LINUX_VERSION_CODE < 0x20300#define RQFUNC_ARG void#else#define RQFUNC_ARG request_queue_t *q#endifstatic void mmc_block_request( RQFUNC_ARG ){ wake_up( &thr_wq );}static int mmc_block_ioctl( struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ){ int ret = -ENODEV; mmc_block_device_t dev; mmc_card_t card; int minor; __ENTER0(); if ( !inode || !file ) { ret = -EINVAL; goto error; } minor = MINOR( inode->i_rdev ); dev = __mmc_block_get_device( inode->i_rdev ); if ( !dev ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" ); goto error; } card = dev->card; __mmc_block_put_device( dev ); switch ( cmd ) { case BLKGETSIZE: /* Return device size */ { unsigned long value; __mmc_block_rdlock_devices(); value = mmc_block_gendisk.part[minor].nr_sects; __mmc_block_rdunlock_devices(); if ( put_user( value, (unsigned long *) arg) ) { ret = -EFAULT; goto error; } } break;#ifdef BLKGETSIZE64 case BLKGETSIZE64: { unsigned long value; __mmc_block_rdlock_devices(); value = mmc_block_gendisk.part[minor].nr_sects; __mmc_block_rdunlock_devices(); if ( put_user( (u64)value, (u64 *) arg) ) { ret = -EFAULT; goto error; } } break;#endif case HDIO_GETGEO: { struct hd_geometry geo; ret = !access_ok( VERIFY_WRITE, arg, sizeof( geo ) ); if ( ret ) { ret = -EFAULT; goto error; } geo.heads = 1; geo.sectors = 1; __mmc_block_rdlock_devices(); geo.cylinders = mmc_block_gendisk.part[minor].nr_sects; geo.start = mmc_block_gendisk.part[minor].start_sect; __mmc_block_rdunlock_devices(); if ( copy_to_user( (int *)arg, &geo, sizeof( geo ) ) ) { ret = -EFAULT; goto error; } } break; case BLKRRPART: if ( !capable( CAP_SYS_ADMIN ) ) { ret = -EACCES; goto error; } (void)mmc_block_revalidate( inode->i_rdev ); break; default: ret = blk_ioctl( inode->i_rdev, cmd, arg ); goto out; } ret = 0;error: out: __LEAVE( "ret=%d", ret ); return ret;}#if LINUX_VERSION_CODE < 0x20326static struct file_operations mmc_block_fops ={ open: mmc_block_open, ioctl: mmc_block_ioctl, release: mmc_block_release, check_media_change: mmc_block_check_disk_change, revalidate: mmc_block_revalidate, read: block_read, write: block_write};#elsestatic struct block_device_operations mmc_block_fops = {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) owner: THIS_MODULE,#endif open: mmc_block_open, release: mmc_block_release, ioctl: mmc_block_ioctl, check_media_change: mmc_block_check_disk_change, revalidate: mmc_block_revalidate};#endifstatic int mmc_block_notify_add( mmc_card_t card ){ int ret = -1; mmc_block_device_t dev; kdev_t start; int minor; __ENTER0(); // printk("%s::%s",__FILE__, __FUNCTION__); if ( !card || !card->ctrlr ) goto error; start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot ); dev = &mmc_block_device[MINOR( start )]; __mmc_block_wrlock_devices(); if ( !dev->card ) { dev->card = card; ret = 0; } __mmc_block_wrunlock_devices(); if ( !ret ) { int i; /* allow to read partition table */ __mmc_block_rdlock_devices(); grok_partitions( &mmc_block_gendisk, MINOR( start ), mmc_block_gendisk.max_p, card->info.capacity>>9 /* sectors */ ); __mmc_block_rdunlock_devices(); __mmc_block_wrlock_devices(); for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) { minor = MINOR( i ); dev = &mmc_block_device[minor]; if ( mmc_block_gendisk.part[minor].nr_sects > 0 ) dev->card = card; } __mmc_block_wrunlock_devices(); }error: __LEAVE( "ret=%d", ret ); return ret;}static int mmc_block_notify_remove( mmc_card_t card ){ int ret = -1; __ENTER( "card=0x%p", card ); if ( card && card->ctrlr ) ret = __mmc_block_invalidate_card( card, FALSE ); __LEAVE( "ret=%d", ret ); return ret;}static mmc_notifier_rec_t mmc_block_notifier = { add: mmc_block_notify_add, remove: mmc_block_notify_remove};static int __init mmc_block_module_init( void ){ int ret = -ENODEV; int i; __ENTER0(); init_rwsem( &mmc_block_device_sem ); if ( devfs_register_blkdev( MAJOR_NR, MAJOR_NAME, &mmc_block_fops ) ) { MMC_ERROR( "Can't allocate major number %d for MMC block devices.\n", MMC_BLOCK_MAJOR ); ret = -EAGAIN; goto error; } for ( i = 0; i < (1<<MINORBITS); i++ ) { __mmc_block_device_init( i ); init_MUTEX( &mmc_block_device[i].sem ); /* We fill it in at open() time. */ mmc_block_blk_sizes[i] = 0; mmc_block_blk_blksizes[i] = BLOCK_SIZE; mmc_block_hardsect_sizes[i] = 0; } init_waitqueue_head( &thr_wq ); /* Allow the block size to default to BLOCK_SIZE. */ blksize_size[MAJOR_NR] = mmc_block_blk_blksizes; hardsect_size[MAJOR_NR] = mmc_block_hardsect_sizes; /* Gendisk stuff */ memset( mmc_block_partitions, 0, sizeof( mmc_block_partitions ) ); add_gendisk( &mmc_block_gendisk );/* FIXME: per controller request queue, I/O and card stack update threads */ blk_init_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ), &mmc_block_request ); thr_id = kernel_thread( mmc_block_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND ); if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_block_notifier, 0 ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" ); goto error; } ret = 0; goto out;error: if ( thr_id != -1 ) {/* quit the thread */ leaving = 1; wake_up(&thr_wq); down(&thread_sem); } blksize_size[MAJOR_NR] = NULL; blk_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL;out: __LEAVE0(); return ret;}static void __exit mmc_block_module_cleanup( void ){/* quit the thread */ leaving = 1; wake_up(&thr_wq); down(&thread_sem); mmc_unregister( MMC_REG_TYPE_USER, &mmc_block_notifier ); del_gendisk( &mmc_block_gendisk ); devfs_unregister_blkdev( MAJOR_NR, MAJOR_NAME ); blk_cleanup_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ) ); blksize_size[MAJOR_NR] = NULL; blk_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL;}EXPORT_NO_SYMBOLS;module_init( mmc_block_module_init );module_exit( mmc_block_module_cleanup );MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -