📄 sjcd.c
字号:
} if( sjcd_mode != SCMD_MODE_COOKED ){#if defined( SJCD_TRACE ) printk( "SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n" );#endif sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch; } } if( CURRENT_IS_VALID ){ struct sjcd_play_msf msf; sjcd_next_bn = CURRENT->sector / 4; hsg2msf( sjcd_next_bn, &msf.start ); msf.end.min = 0; msf.end.sec = 0; msf.end.frame = sjcd_read_count = SJCD_BUF_SIZ;#if defined( SJCD_TRACE ) printk( "SJCD: ---reading msf-address %x:%x:%x %x:%x:%x\n", msf.start.min, msf.start.sec, msf.start.frame, msf.end.min, msf.end.sec, msf.end.frame ); printk( "sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", \ sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, sjcd_buf_bn[ sjcd_buf_in ] );#endif sjcd_send_6_cmd( SCMD_DATA_READ, &msf ); sjcd_transfer_state = SJCD_S_DATA; sjcd_transfer_timeout = 500;#if defined( SJCD_TRACE ) printk( "SJCD_S_READ: go to SJCD_S_DATA mode\n" );#endif } else {#if defined( SJCD_TRACE ) printk( "SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n" );#endif sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch; } }#if defined( SJCD_GATHER_STAT ) else statistic.read_ticks++;#endif break; } case SJCD_S_DATA:{ unsigned char stat; sjcd_s_data: stat = inb( SJCDPORT( 1 ) );#if defined( SJCD_TRACE ) printk( "SJCD_S_DATA: status = 0x%02x\n", stat );#endif if( SJCD_STATUS_AVAILABLE( stat ) ){ /* * No data is waiting for us in the drive buffer. Status of operation * completion is available. Read and parse it. */ sjcd_load_status(); if( !sjcd_status_valid || sjcd_command_failed ){#if defined( SJCD_TRACE ) printk( "SJCD: read block %d failed, maybe audio disk? Giving up\n", sjcd_next_bn );#endif if( CURRENT_IS_VALID ) end_request( 0 );#if defined( SJCD_TRACE ) printk( "SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n" );#endif sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch; } if( !sjcd_media_is_available ){ printk( "SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n" ); sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch; } sjcd_transfer_state = SJCD_S_READ; goto ReSwitch; } else if( SJCD_DATA_AVAILABLE( stat ) ){ /* * One frame is read into device buffer. We must copy it to our memory. * Otherwise cdrom hangs up. Check to see if we have something to copy * to. */ if( !CURRENT_IS_VALID && sjcd_buf_in == sjcd_buf_out ){#if defined( SJCD_TRACE ) printk( "SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n" ); printk( " ... all the date would be discarded\n" );#endif sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch; } /* * Everything seems to be OK. Just read the frame and recalculate * indices. */ sjcd_buf_bn[ sjcd_buf_in ] = -1; /* ??? */ insb( SJCDPORT( 2 ), sjcd_buf + 2048 * sjcd_buf_in, 2048 );#if defined( SJCD_TRACE ) printk( "SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n", sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, sjcd_buf_bn[ sjcd_buf_in ] );#endif sjcd_buf_bn[ sjcd_buf_in ] = sjcd_next_bn++; if( sjcd_buf_out == -1 ) sjcd_buf_out = sjcd_buf_in; if( ++sjcd_buf_in == SJCD_BUF_SIZ ) sjcd_buf_in = 0; /* * Only one frame is ready at time. So we should turn over to wait for * another frame. If we need that, of course. */ if( --sjcd_read_count == 0 ){ /* * OK, request seems to be precessed. Continue transferring... */ if( !sjcd_transfer_is_active ){ while( CURRENT_IS_VALID ){ /* * Continue transferring. */ sjcd_transfer(); if( CURRENT->nr_sectors == 0 ) end_request( 1 ); else break; } } if( CURRENT_IS_VALID && ( CURRENT->sector / 4 < sjcd_next_bn || CURRENT->sector / 4 > sjcd_next_bn + SJCD_BUF_SIZ ) ){#if defined( SJCD_TRACE ) printk( "SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n" );#endif sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch; } } /* * Now we should turn around rather than wait for while. */ goto sjcd_s_data; }#if defined( SJCD_GATHER_STAT ) else statistic.data_ticks++;#endif break; } case SJCD_S_STOP:{ sjcd_read_count = 0; sjcd_send_cmd( SCMD_STOP ); sjcd_transfer_state = SJCD_S_STOPPING; sjcd_transfer_timeout = 500;#if defined( SJCD_GATHER_STAT ) statistic.stop_ticks++;#endif break; } case SJCD_S_STOPPING:{ unsigned char stat; stat = inb( SJCDPORT( 1 ) );#if defined( SJCD_TRACE ) printk( "SJCD_S_STOP: status = 0x%02x\n", stat );#endif if( SJCD_DATA_AVAILABLE( stat ) ){ int i;#if defined( SJCD_TRACE ) printk( "SJCD_S_STOP: discard data\n" );#endif /* * Discard all the data from the pipe. Foolish method. */ for( i = 2048; i--; ( void )inb( SJCDPORT( 2 ) ) ); sjcd_transfer_timeout = 500; } else if( SJCD_STATUS_AVAILABLE( stat ) ){ sjcd_load_status(); if( sjcd_status_valid && sjcd_media_is_changed ) { sjcd_toc_uptodate = 0; sjcd_invalidate_buffers(); } if( CURRENT_IS_VALID ){ if( sjcd_status_valid ) sjcd_transfer_state = SJCD_S_READ; else sjcd_transfer_state = SJCD_S_START; } else sjcd_transfer_state = SJCD_S_IDLE; goto ReSwitch; }#if defined( SJCD_GATHER_STAT ) else statistic.stopping_ticks++;#endif break; } default: printk( "SJCD: poll: invalid state %d\n", sjcd_transfer_state ); return; } if( --sjcd_transfer_timeout == 0 ){ printk( "SJCD: timeout in state %d\n", sjcd_transfer_state ); while( CURRENT_IS_VALID ) end_request( 0 ); sjcd_send_cmd( SCMD_STOP ); sjcd_transfer_state = SJCD_S_IDLE; goto ReSwitch; } /* * Get back in some time. 1 should be replaced with count variable to * avoid unnecessary testings. */ SJCD_SET_TIMER( sjcd_poll, 1 );}static void do_sjcd_request( request_queue_t * q ){#if defined( SJCD_TRACE ) printk( "SJCD: do_sjcd_request(%ld+%ld)\n", CURRENT->sector, CURRENT->nr_sectors );#endif sjcd_transfer_is_active = 1; while( CURRENT_IS_VALID ){ /* * Who of us are paranoiac? */ if( CURRENT->bh && !buffer_locked(CURRENT->bh) ) panic( DEVICE_NAME ": block not locked" ); sjcd_transfer(); if( CURRENT->nr_sectors == 0 ) end_request( 1 ); else { sjcd_buf_out = -1; /* Want to read a block not in buffer */ if( sjcd_transfer_state == SJCD_S_IDLE ){ if( !sjcd_toc_uptodate ){ if( sjcd_update_toc() < 0 ){ printk( "SJCD: transfer: discard\n" ); while( CURRENT_IS_VALID ) end_request( 0 ); break; } } sjcd_transfer_state = SJCD_S_START; SJCD_SET_TIMER( sjcd_poll, HZ/100 ); } break; } } sjcd_transfer_is_active = 0;#if defined( SJCD_TRACE ) printk( "sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n", sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, sjcd_buf_bn[ sjcd_buf_in ] ); printk( "do_sjcd_request ends\n" );#endif}/* * Open the device special file. Check disk is in. */int sjcd_open( struct inode *ip, struct file *fp ){ /* * Check the presence of device. */ if( !sjcd_present ) return( -ENXIO ); /* * Only read operations are allowed. Really? (:-) */ if( fp->f_mode & 2 ) return( -EROFS ); MOD_INC_USE_COUNT; if( sjcd_open_count == 0 ){ int s, sjcd_open_tries;/* We don't know that, do we? *//* sjcd_audio_status = CDROM_AUDIO_NO_STATUS;*/ sjcd_mode = 0; sjcd_door_was_open = 0; sjcd_transfer_state = SJCD_S_IDLE; sjcd_invalidate_buffers(); sjcd_status_valid = 0; /* * Strict status checking. */ for( sjcd_open_tries = 4; --sjcd_open_tries; ){ if( !sjcd_status_valid ) sjcd_get_status(); if( !sjcd_status_valid ){#if defined( SJCD_DIAGNOSTIC ) printk( "SJCD: open: timed out when check status.\n" );#endif goto err_out; } else if( !sjcd_media_is_available ){#if defined( SJCD_DIAGNOSTIC ) printk("SJCD: open: no disk in drive\n");#endif if( !sjcd_door_closed ){ sjcd_door_was_open = 1;#if defined( SJCD_TRACE ) printk("SJCD: open: close the tray\n");#endif s = sjcd_tray_close(); if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){#if defined( SJCD_DIAGNOSTIC ) printk("SJCD: open: tray close attempt failed\n");#endif goto err_out; } continue; } else goto err_out; } break; } s = sjcd_tray_lock(); if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){#if defined( SJCD_DIAGNOSTIC ) printk("SJCD: open: tray lock attempt failed\n");#endif goto err_out; }#if defined( SJCD_TRACE ) printk( "SJCD: open: done\n" );#endif } ++sjcd_open_count; return( 0 );err_out: MOD_DEC_USE_COUNT; return( -EIO );}/* * On close, we flush all sjcd blocks from the buffer cache. */static int sjcd_release( struct inode *inode, struct file *file ){ int s;#if defined( SJCD_TRACE ) printk( "SJCD: release\n" );#endif#ifdef MODULE MOD_DEC_USE_COUNT;#endif if( --sjcd_open_count == 0 ){ sjcd_invalidate_buffers(); s = sjcd_tray_unlock(); if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){#if defined( SJCD_DIAGNOSTIC ) printk("SJCD: release: tray unlock attempt failed.\n");#endif } if( sjcd_door_was_open ){ s = sjcd_tray_open(); if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){#if defined( SJCD_DIAGNOSTIC ) printk("SJCD: release: tray unload attempt failed.\n");#endif } } } return 0;}/* * A list of file operations allowed for this cdrom. */static struct block_device_operations sjcd_fops = { open: sjcd_open, release: sjcd_release, ioctl: sjcd_ioctl, check_media_change: sjcd_disk_change,};static int blksize = 2048;static int secsize = 2048;/* * Following stuff is intended for initialization of the cdrom. It * first looks for presence of device. If the device is present, it * will be reset. Then read the version of the drive and load status. * The version is two BCD-coded bytes. */static struct { unsigned char major, minor;} sjcd_version;/* * Test for presence of drive and initialize it. Called at boot time. * Probe cdrom, find out version and status. */int __init sjcd_init( void ){ int i; printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR);#if defined( SJCD_TRACE ) printk("SJCD: sjcd=0x%x: ", sjcd_base);#endif hardsect_size[MAJOR_NR] = &secsize; blksize_size[MAJOR_NR] = &blksize; if( devfs_register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){ printk( "SJCD: Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR ); return( -EIO ); } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); read_ahead[ MAJOR_NR ] = 4; register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &sjcd_fops, 0); if( check_region( sjcd_base, 4 ) ){ printk( "SJCD: Init failed, I/O port (%X) is already in use\n", sjcd_base ); sjcd_cleanup(); return( -EIO ); } /* * Check for card. Since we are booting now, we can't use standard * wait algorithm. */ printk(KERN_INFO "SJCD: Resetting: " ); sjcd_send_cmd( SCMD_RESET ); for( i = 1000; i > 0 && !sjcd_status_valid; --i ){ unsigned long timer; /* * Wait 10ms approx. */ for( timer = jiffies; time_before_eq(jiffies, timer); ); if ( (i % 100) == 0 ) printk( "." ); ( void )sjcd_check_status(); } if( i == 0 || sjcd_command_failed ){ printk( " reset failed, no drive found.\n" ); sjcd_cleanup(); return( -EIO ); } else printk( "\n" ); /* * Get and print out cdrom version. */ printk(KERN_INFO "SJCD: Getting version: " ); sjcd_send_cmd( SCMD_GET_VERSION ); for( i = 1000; i > 0 && !sjcd_status_valid; --i ){ unsigned long timer; /* * Wait 10ms approx. */ for( timer = jiffies; time_before_eq(jiffies, timer); ); if ( (i % 100) == 0 ) printk( "." ); ( void )sjcd_check_status(); } if( i == 0 || sjcd_command_failed ){ printk( " get version failed, no drive found.\n" ); sjcd_cleanup(); return( -EIO ); } if( sjcd_load_response( &sjcd_version, sizeof( sjcd_version ) ) == 0 ){ printk( " %1x.%02x\n", ( int )sjcd_version.major, ( int )sjcd_version.minor ); } else { printk( " read version failed, no drive found.\n" ); sjcd_cleanup(); return( -EIO ); } /* * Check and print out the tray state. (if it is needed?). */ if( !sjcd_status_valid ){ printk(KERN_INFO "SJCD: Getting status: " ); sjcd_send_cmd( SCMD_GET_STATUS ); for( i = 1000; i > 0 && !sjcd_status_valid; --i ){ unsigned long timer; /* * Wait 10ms approx. */ for( timer = jiffies; time_before_eq(jiffies, timer); ); if ( (i % 100) == 0 ) printk( "." ); ( void )sjcd_check_status(); } if( i == 0 || sjcd_command_failed ){ printk( " get status failed, no drive found.\n" ); sjcd_cleanup(); return( -EIO ); } else printk( "\n" ); } printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); devfs_register (NULL, "sjcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &sjcd_fops, NULL); sjcd_present++; return( 0 );}static intsjcd_cleanup(void){ if( (devfs_unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL) ) printk( "SJCD: cannot unregister device.\n" ); else { release_region( sjcd_base, 4 ); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); } return(0);}void __exit sjcd_exit(void){ devfs_unregister(devfs_find_handle(NULL, "sjcd", 0, 0, DEVFS_SPECIAL_BLK,0)); if ( sjcd_cleanup() ) printk( "SJCD: module: cannot be removed.\n" ); else printk(KERN_INFO "SJCD: module: removed.\n");}#ifdef MODULEmodule_init(sjcd_init);#endifmodule_exit(sjcd_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -