📄 cdrom.c
字号:
if (!(cdo->capability & ~cdi->mask & CDC_RESET)) return -ENOSYS; return cdo->reset(cdi); } case CDROM_LOCKDOOR: { cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl"); if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) { return -EDRIVE_CANT_DO_THIS; } else { keeplocked = arg ? 1 : 0; return cdo->lock_door(cdi, arg); } } case CDROM_DEBUG: { if (!capable(CAP_SYS_ADMIN)) return -EACCES; cdinfo(CD_DO_IOCTL, "%sabling debug.\n",arg?"En":"Dis"); debug = arg ? 1 : 0; return debug; } case CDROM_GET_CAPABILITY: { cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); return cdo->capability; }/* The following function is implemented, although very few audio * discs give Universal Product Code information, which should just be * the Medium Catalog Number on the box. Note, that the way the code * is written on the CD is /not/ uniform across all discs! */ case CDROM_GET_MCN: { int ret; struct cdrom_mcn mcn; cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); if (!(cdo->capability & CDC_MCN)) return -ENOSYS; if ((ret=cdo->get_mcn(cdi, &mcn))) return ret; IOCTL_OUT(arg, struct cdrom_mcn, mcn); cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); return 0; } case CDROM_DRIVE_STATUS: { cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); if (!(cdo->capability & CDC_DRIVE_STATUS)) return -ENOSYS; if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) return cdo->drive_status(cdi, arg); if (((int)arg > cdi->capacity)) return -EINVAL; return cdo->drive_status(cdi, arg); } /* Ok, this is where problems start. The current interface for the CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, while this is often the case, it is also very common for CDs to have some tracks with data, and some tracks with audio. Just because I feel like it, I declare the following to be the best way to cope. If the CD has ANY data tracks on it, it will be returned as a data CD. If it has any XA tracks, I will return it as that. Now I could simplify this interface by combining these returns with the above, but this more clearly demonstrates the problem with the current interface. Too bad this wasn't designed to use bitmasks... -Erik Well, now we have the option CDS_MIXED: a mixed-type CD. User level programmers might feel the ioctl is not very useful. ---david */ case CDROM_DISC_STATUS: { tracktype tracks; cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); cdrom_count_tracks(cdi, &tracks); if (tracks.error) return(tracks.error); /* Policy mode on */ if (tracks.audio > 0) { if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) return CDS_AUDIO; else return CDS_MIXED; } if (tracks.cdi > 0) return CDS_XA_2_2; if (tracks.xa > 0) return CDS_XA_2_1; if (tracks.data > 0) return CDS_DATA_1; /* Policy mode off */ cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognise!\n"); return CDS_NO_INFO; } case CDROM_CHANGER_NSLOTS: cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); return cdi->capacity;/* The following is not implemented, because there are too many * different data types. We could support /1/ raw mode, that is large * enough to hold everything. */#if 0 case CDROMREADMODE1: { int ret; struct cdrom_msf msf; char buf[CD_FRAMESIZE]; cdinfo(CD_DO_IOCTL, "entering CDROMREADMODE1\n"); IOCTL_IN(arg, struct cdrom_msf, msf); if (ret=cdo->read_audio(dev, cmd, &msf, &buf, cdi)) return ret; IOCTL_OUT(arg, __typeof__(buf), buf); return 0; }#endif } /* switch *//* Now all the audio-ioctls follow, they are all routed through the same call audio_ioctl(). */#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret if (!(cdo->capability & CDC_PLAY_AUDIO)) return -ENOSYS; else { switch (cmd) { case CDROMSUBCHNL: { int ret; struct cdrom_subchnl q; u_char requested, back; /* comment out the cdinfo calls here because they fill up the sys logs when CD players poll the drive*/ /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ IOCTL_IN(arg, struct cdrom_subchnl, q); requested = q.cdsc_format; if (!((requested == CDROM_MSF) || (requested == CDROM_LBA))) return -EINVAL; q.cdsc_format = CDROM_MSF; if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) return ret; back = q.cdsc_format; /* local copy */ sanitize_format(&q.cdsc_absaddr, &back, requested); sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); IOCTL_OUT(arg, struct cdrom_subchnl, q); /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } case CDROMREADTOCHDR: { int ret; struct cdrom_tochdr header; /* comment out the cdinfo calls here because they fill up the sys logs when CD players poll the drive*/ /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ IOCTL_IN(arg, struct cdrom_tochdr, header); if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) return ret; IOCTL_OUT(arg, struct cdrom_tochdr, header); /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ return 0; } case CDROMREADTOCENTRY: { int ret; struct cdrom_tocentry entry; u_char requested_format; /* comment out the cdinfo calls here because they fill up the sys logs when CD players poll the drive*/ /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ IOCTL_IN(arg, struct cdrom_tocentry, entry); requested_format = entry.cdte_format; if (!((requested_format == CDROM_MSF) || (requested_format == CDROM_LBA))) return -EINVAL; /* make interface to low-level uniform */ entry.cdte_format = CDROM_MSF; if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) return ret; sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format); IOCTL_OUT(arg, struct cdrom_tocentry, entry); /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ return 0; } case CDROMPLAYMSF: { int ret; struct cdrom_msf msf; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); IOCTL_IN(arg, struct cdrom_msf, msf); CHECKAUDIO; return cdo->audio_ioctl(cdi, cmd, &msf); } case CDROMPLAYTRKIND: { int ret; struct cdrom_ti ti; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); IOCTL_IN(arg, struct cdrom_ti, ti); CHECKAUDIO; return cdo->audio_ioctl(cdi, cmd, &ti); } case CDROMVOLCTRL: { struct cdrom_volctrl volume; cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); IOCTL_IN(arg, struct cdrom_volctrl, volume); return cdo->audio_ioctl(cdi, cmd, &volume); } case CDROMVOLREAD: { int ret; struct cdrom_volctrl volume; cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) return ret; IOCTL_OUT(arg, struct cdrom_volctrl, volume); return 0; } case CDROMSTART: case CDROMSTOP: case CDROMPAUSE: case CDROMRESUME: { int ret; cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); CHECKAUDIO; return cdo->audio_ioctl(cdi, cmd, NULL); } } /* switch */ } /* device specific ioctls? */ if (!(cdo->capability & CDC_IOCTLS)) return -ENOSYS; else return cdo->dev_ioctl(cdi, cmd, arg);}EXPORT_SYMBOL(cdrom_count_tracks);EXPORT_SYMBOL(register_cdrom);EXPORT_SYMBOL(unregister_cdrom);EXPORT_SYMBOL(cdrom_fops);#ifdef CONFIG_SYSCTL#define CDROM_STR_SIZE 1000static char cdrom_drive_info[CDROM_STR_SIZE]="info\n";int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp){ int pos; struct cdrom_device_info *cdi; if (!*lenp || (filp->f_pos && !write)) { *lenp = 0; return 0; } pos = sprintf(cdrom_drive_info, "CD-ROM information, " VERSION "\n"); pos += sprintf(cdrom_drive_info+pos, "\ndrive name:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%s", cdi->name); pos += sprintf(cdrom_drive_info+pos, "\ndrive speed:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->speed); pos += sprintf(cdrom_drive_info+pos, "\ndrive # of slots:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->capacity); pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_CLOSE_TRAY)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_OPEN_TRAY)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_LOCK)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_SELECT_SPEED)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_SELECT_DISC)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_MULTI_SESSION)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan read MCN:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_MCN)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nReports media changed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_MEDIA_CHANGED)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", ((cdi->ops->capability & CDC_PLAY_AUDIO)!=0)); strcpy(cdrom_drive_info+pos,"\n\n"); *lenp=pos+3; return proc_dostring(ctl, write, filp, buffer, lenp);}/* Place files in /proc/sys/dev/cdrom */ctl_table cdrom_table[] = { {DEV_CDROM_INFO, "info", &cdrom_drive_info, CDROM_STR_SIZE, 0444, NULL, &cdrom_sysctl_info}, {0} };ctl_table cdrom_cdrom_table[] = { {DEV_CDROM, "cdrom", NULL, 0, 0555, cdrom_table}, {0} };/* Make sure that /proc/sys/dev is there */ctl_table cdrom_root_table[] = { {CTL_DEV, "dev", NULL, 0, 0555, cdrom_cdrom_table}, {0} };static struct ctl_table_header *cdrom_sysctl_header;/* * This is called as the fill_inode function when an inode * is going into (fill = 1) or out of service (fill = 0). * We use it here to manage the module use counts. * * Note: only the top-level directory needs to do this; if * a lower level is referenced, the parent will be as well. */static void cdrom_procfs_modcount(struct inode *inode, int fill){ if (fill) { MOD_INC_USE_COUNT; } else { MOD_DEC_USE_COUNT; }}static void cdrom_sysctl_register(void){ static int initialized = 0; if (initialized == 1) return; cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount; initialized = 1;}#ifdef MODULEstatic void cdrom_sysctl_unregister(void){ unregister_sysctl_table(cdrom_sysctl_header);}#endif /* endif MODULE */#endif /* endif CONFIG_SYSCTL */#ifdef MODULEint init_module(void){#ifdef CONFIG_SYSCTL cdrom_sysctl_register();#endif /* CONFIG_SYSCTL */ return 0;}void cleanup_module(void){ printk(KERN_INFO "Uniform CD-ROM driver unloaded\n");#ifdef CONFIG_SYSCTL cdrom_sysctl_unregister();#endif /* CONFIG_SYSCTL */ }#endif /* endif MODULE *//* * Local variables: * comment-column: 40 * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cdrom.o cdrom.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -