📄 optcd.c
字号:
S_READ, /* 2 */ S_DATA, /* 3 */ S_STOP, /* 4 */ S_STOPPING /* 5 */};static volatile enum state_e state = S_IDLE;#if DEBUG_STATEstatic volatile enum state_e state_old = S_STOP;static volatile int flags_old = 0;static volatile long state_n = 0;#endif/* Used as mutex to keep do_optcd_request (and other processes calling ioctl) out while some process is inside a VFS call. Reverse is accomplished by checking if state = S_IDLE upon entry of opt_ioctl and opt_media_change. */static int in_vfs = 0;static volatile int transfer_is_active = 0;static volatile int error = 0; /* %% do something with this?? */static int tries; /* ibid?? */static int timeout = 0;static void poll(unsigned long data);static struct timer_list req_timer = {function: poll};static void poll(unsigned long data){ static volatile int read_count = 1; int flags; int loop_again = 1; int status = 0; int skip = 0; if (error) { printk(KERN_ERR "optcd: I/O error 0x%02x\n", error); opt_invalidate_buffers(); if (!tries--) { printk(KERN_ERR "optcd: read block %d failed;" " Giving up\n", next_bn); if (transfer_is_active) loop_again = 0; if (CURRENT_VALID) end_request(0); tries = 5; } error = 0; state = S_STOP; } while (loop_again) { loop_again = 0; /* each case must flip this back to 1 if we want to come back up here */#if DEBUG_STATE if (state == state_old) state_n++; else { state_old = state; if (++state_n > 1) printk(KERN_DEBUG "optcd: %ld times " "in previous state\n", state_n); printk(KERN_DEBUG "optcd: state %d\n", state); state_n = 0; }#endif switch (state) { case S_IDLE: return; case S_START: if (in_vfs) break; if (send_cmd(COMDRVST)) { state = S_IDLE; while (CURRENT_VALID) end_request(0); return; } state = S_READ; timeout = READ_TIMEOUT; break; case S_READ: { struct cdrom_msf msf; if (!skip) { status = fetch_status(); if (status < 0) break; if (status & ST_DSK_CHG) { toc_uptodate = 0; opt_invalidate_buffers(); } } skip = 0; if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { toc_uptodate = 0; opt_invalidate_buffers(); printk(KERN_WARNING "optcd: %s\n", (status & ST_DOOR_OPEN) ? "door open" : "disk removed"); state = S_IDLE; while (CURRENT_VALID) end_request(0); return; } if (!CURRENT_VALID) { state = S_STOP; loop_again = 1; break; } next_bn = CURRENT -> sector / 4; lba2msf(next_bn, &msf); read_count = N_BUFS; msf.cdmsf_frame1 = read_count; /* Not BCD! */ DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x", msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0, msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1)); DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d" " buf_out:%d buf_bn:%d", next_bn, buf_in, buf_out, buf_bn[buf_in])); exec_read_cmd(COMREAD, &msf); state = S_DATA; timeout = READ_TIMEOUT; break; } case S_DATA: flags = stdt_flags() & (FL_STEN|FL_DTEN);#if DEBUG_STATE if (flags != flags_old) { flags_old = flags; printk(KERN_DEBUG "optcd: flags:%x\n", flags); } if (flags == FL_STEN) printk(KERN_DEBUG "timeout cnt: %d\n", timeout);#endif switch (flags) { case FL_DTEN: /* only STEN low */ if (!tries--) { printk(KERN_ERR "optcd: read block %d failed; " "Giving up\n", next_bn); if (transfer_is_active) { tries = 0; break; } if (CURRENT_VALID) end_request(0); tries = 5; } state = S_START; timeout = READ_TIMEOUT; loop_again = 1; case (FL_STEN|FL_DTEN): /* both high */ break; default: /* DTEN low */ tries = 5; if (!CURRENT_VALID && buf_in == buf_out) { state = S_STOP; loop_again = 1; break; } if (read_count<=0) printk(KERN_WARNING "optcd: warning - try to read" " 0 frames\n"); while (read_count) { buf_bn[buf_in] = NOBUF; if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) { /* should be no waiting here!?? */ printk(KERN_ERR "read_count:%d " "CURRENT->nr_sectors:%ld " "buf_in:%d\n", read_count, CURRENT->nr_sectors, buf_in); printk(KERN_ERR "transfer active: %x\n", transfer_is_active); read_count = 0; state = S_STOP; loop_again = 1; end_request(0); break; } fetch_data(buf+ CD_FRAMESIZE*buf_in, CD_FRAMESIZE); read_count--; DEBUG((DEBUG_REQUEST, "S_DATA; ---I've read data- " "read_count: %d", read_count)); DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d " "buf_out:%d buf_bn:%d", next_bn, buf_in, buf_out, buf_bn[buf_in])); buf_bn[buf_in] = next_bn++; if (buf_out == NOBUF) buf_out = buf_in; buf_in = buf_in + 1 == N_BUFS ? 0 : buf_in + 1; } if (!transfer_is_active) { while (CURRENT_VALID) { transfer(); if (CURRENT -> nr_sectors == 0) end_request(1); else break; } } if (CURRENT_VALID && (CURRENT -> sector / 4 < next_bn || CURRENT -> sector / 4 > next_bn + N_BUFS)) { state = S_STOP; loop_again = 1; break; } timeout = READ_TIMEOUT; if (read_count == 0) { state = S_STOP; loop_again = 1; break; } } break; case S_STOP: if (read_count != 0) printk(KERN_ERR "optcd: discard data=%x frames\n", read_count); flush_data(); if (send_cmd(COMDRVST)) { state = S_IDLE; while (CURRENT_VALID) end_request(0); return; } state = S_STOPPING; timeout = STOP_TIMEOUT; break; case S_STOPPING: status = fetch_status(); if (status < 0 && timeout) break; if ((status >= 0) && (status & ST_DSK_CHG)) { toc_uptodate = 0; opt_invalidate_buffers(); } if (CURRENT_VALID) { if (status >= 0) { state = S_READ; loop_again = 1; skip = 1; break; } else { state = S_START; timeout = 1; } } else { state = S_IDLE; return; } break; default: printk(KERN_ERR "optcd: invalid state %d\n", state); return; } /* case */ } /* while */ if (!timeout--) { printk(KERN_ERR "optcd: timeout in state %d\n", state); state = S_STOP; if (exec_cmd(COMSTOP) < 0) { state = S_IDLE; while (CURRENT_VALID) end_request(0); return; } } mod_timer(&req_timer, jiffies + HZ/100);}static void do_optcd_request(request_queue_t * q){ DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)", CURRENT -> sector, CURRENT -> nr_sectors)); if (disk_info.audio) { printk(KERN_WARNING "optcd: tried to mount an Audio CD\n"); end_request(0); return; } transfer_is_active = 1; while (CURRENT_VALID) { if (CURRENT->bh) { if (!buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); } transfer(); /* First try to transfer block from buffers */ if (CURRENT -> nr_sectors == 0) { end_request(1); } else { /* Want to read a block not in buffer */ buf_out = NOBUF; if (state == S_IDLE) { /* %% Should this block the request queue?? */ if (update_toc() < 0) { while (CURRENT_VALID) end_request(0); break; } /* Start state machine */ state = S_START; timeout = READ_TIMEOUT; tries = 5; /* %% why not start right away?? */ mod_timer(&req_timer, jiffies + HZ/100); } break; } } transfer_is_active = 0; DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d", next_bn, buf_in, buf_out, buf_bn[buf_in])); DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));}/* IOCTLs */static char auto_eject = 0;static int cdrompause(void){ int status; if (audio_status != CDROM_AUDIO_PLAY) return -EINVAL; status = exec_cmd(COMPAUSEON); if (status < 0) { DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status)); return -EIO; } audio_status = CDROM_AUDIO_PAUSED; return 0;}static int cdromresume(void){ int status; if (audio_status != CDROM_AUDIO_PAUSED) return -EINVAL; status = exec_cmd(COMPAUSEOFF); if (status < 0) { DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status)); audio_status = CDROM_AUDIO_ERROR; return -EIO; } audio_status = CDROM_AUDIO_PLAY; return 0;}static int cdromplaymsf(unsigned long arg){ int status; struct cdrom_msf msf; status = verify_area(VERIFY_READ, (void *) arg, sizeof msf); if (status) return status; copy_from_user(&msf, (void *) arg, sizeof msf); bin2bcd(&msf); status = exec_long_cmd(COMPLAY, &msf); if (status < 0) { DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); audio_status = CDROM_AUDIO_ERROR; return -EIO; } audio_status = CDROM_AUDIO_PLAY; return 0;}static int cdromplaytrkind(unsigned long arg){ int status; struct cdrom_ti ti; struct cdrom_msf msf; status = verify_area(VERIFY_READ, (void *) arg, sizeof ti); if (status) return status; copy_from_user(&ti, (void *) arg, sizeof ti); if (ti.cdti_trk0 < disk_info.first || ti.cdti_trk0 > disk_info.last || ti.cdti_trk1 < ti.cdti_trk0) return -EINVAL; if (ti.cdti_trk1 > disk_info.last) ti.cdti_trk1 = disk_info.last; msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute; msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second; msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame; msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute; msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second; msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame; DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d", msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0, msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1)); bin2bcd(&msf); status = exec_long_cmd(COMPLAY, &msf); if (status < 0) { DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); audio_status = CDROM_AUDIO_ERROR; return -EIO; } audio_status = CDROM_AUDIO_PLAY; return 0;}static int cdromreadtochdr(unsigned long arg){ int status; struct cdrom_tochdr tochdr; status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr); if (status) return status; tochdr.cdth_trk0 = disk_info.first; tochdr.cdth_trk1 = disk_info.last; copy_to_user((void *) arg, &tochdr, sizeof tochdr); return 0;}static int cdromreadtocentry(unsigned long arg){ int status; struct cdrom_tocentry entry; struct cdrom_subchnl *tocptr; status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry); if (status) return status; copy_from_user(&entry, (void *) arg, sizeof entry); if (entry.cdte_track == CDROM_LEADOUT) tocptr = &toc[disk_info.last + 1]; else if (entry.cdte_track > disk_info.last || entry.cdte_track < disk_info.first) return -EINVAL; else tocptr = &toc[entry.cdte_track]; entry.cdte_adr = tocptr->cdsc_adr; entry.cdte_ctrl = tocptr->cdsc_ctrl; entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute; entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second; entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame; /* %% What should go into entry.cdte_datamode? */ if (entry.cdte_format == CDROM_LBA) msf2lba(&entry.cdte_addr); else if (entry.cdte_format != CDROM_MSF) return -EINVAL; copy_to_user((void *) arg, &entry, sizeof entry); return 0;}static int cdromvolctrl(unsigned long arg){ int status; struct cdrom_volctrl volctrl; struct cdrom_msf msf; status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -