cdrom.c
来自「linux 内核源代码」· C语言 代码 · 共 2,396 行 · 第 1/5 页
C
2,396 行
int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med){ struct packet_command cgc; unsigned char buffer[8]; struct event_header *eh = (struct event_header *) buffer; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; cgc.cmd[1] = 1; /* IMMED */ cgc.cmd[4] = 1 << 4; /* media event */ cgc.cmd[8] = sizeof(buffer); cgc.quiet = 1; if (cdi->ops->generic_packet(cdi, &cgc)) return 1; if (be16_to_cpu(eh->data_len) < sizeof(*med)) return 1; if (eh->nea || eh->notification_class != 0x4) return 1; memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); return 0;}/* * the first prototypes used 0x2c as the page code for the mrw mode page, * subsequently this was changed to 0x03. probe the one used by this drive */static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi){ struct packet_command cgc; char buffer[16]; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.timeout = HZ; cgc.quiet = 1; if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { cdi->mrw_mode_page = MRW_MODE_PC; return 0; } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { cdi->mrw_mode_page = MRW_MODE_PC_PRE1; return 0; } return 1;}static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write){ struct packet_command cgc; struct mrw_feature_desc *mfd; unsigned char buffer[16]; int ret; *write = 0; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[3] = CDF_MRW; cgc.cmd[8] = sizeof(buffer); cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) return ret; mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; if (be16_to_cpu(mfd->feature_code) != CDF_MRW) return 1; *write = mfd->write; if ((ret = cdrom_mrw_probe_pc(cdi))) { *write = 0; return ret; } return 0;}static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont){ struct packet_command cgc; unsigned char buffer[12]; int ret; printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); /* * FmtData bit set (bit 4), format type is 1 */ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); cgc.cmd[0] = GPCMD_FORMAT_UNIT; cgc.cmd[1] = (1 << 4) | 1; cgc.timeout = 5 * 60 * HZ; /* * 4 byte format list header, 8 byte format list descriptor */ buffer[1] = 1 << 1; buffer[3] = 8; /* * nr_blocks field */ buffer[4] = 0xff; buffer[5] = 0xff; buffer[6] = 0xff; buffer[7] = 0xff; buffer[8] = 0x24 << 2; buffer[11] = cont; ret = cdi->ops->generic_packet(cdi, &cgc); if (ret) printk(KERN_INFO "cdrom: bgformat failed\n"); return ret;}static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed){ struct packet_command cgc; init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.cmd[0] = GPCMD_CLOSE_TRACK; /* * Session = 1, Track = 0 */ cgc.cmd[1] = !!immed; cgc.cmd[2] = 1 << 1; cgc.timeout = 5 * 60 * HZ; return cdi->ops->generic_packet(cdi, &cgc);}static int cdrom_flush_cache(struct cdrom_device_info *cdi){ struct packet_command cgc; init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.cmd[0] = GPCMD_FLUSH_CACHE; cgc.timeout = 5 * 60 * HZ; return cdi->ops->generic_packet(cdi, &cgc);}static int cdrom_mrw_exit(struct cdrom_device_info *cdi){ disc_information di; int ret; ret = cdrom_get_disc_info(cdi, &di); if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type)) return 1; ret = 0; if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { printk(KERN_INFO "cdrom: issuing MRW back ground " "format suspend\n"); ret = cdrom_mrw_bgformat_susp(cdi, 0); } if (!ret && cdi->media_written) ret = cdrom_flush_cache(cdi); return ret;}static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space){ struct packet_command cgc; struct mode_page_header *mph; char buffer[16]; int ret, offset, size; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.buffer = buffer; cgc.buflen = sizeof(buffer); if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) return ret; mph = (struct mode_page_header *) buffer; offset = be16_to_cpu(mph->desc_length); size = be16_to_cpu(mph->mode_data_length) + 2; buffer[offset + 3] = space; cgc.buflen = size; if ((ret = cdrom_mode_select(cdi, &cgc))) return ret; printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); return 0;}static int cdrom_get_random_writable(struct cdrom_device_info *cdi, struct rwrt_feature_desc *rfd){ struct packet_command cgc; char buffer[24]; int ret; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */ cgc.cmd[3] = CDF_RWRT; /* often 0x0020 */ cgc.cmd[8] = sizeof(buffer); /* often 0x18 */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) return ret; memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd)); return 0;}static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi){ struct packet_command cgc; char buffer[16]; __be16 *feature_code; int ret; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[3] = CDF_HWDM; cgc.cmd[8] = sizeof(buffer); cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) return ret; feature_code = (__be16 *) &buffer[sizeof(struct feature_header)]; if (be16_to_cpu(*feature_code) == CDF_HWDM) return 0; return 1;}static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write){ struct rwrt_feature_desc rfd; int ret; *write = 0; if ((ret = cdrom_get_random_writable(cdi, &rfd))) return ret; if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) *write = 1; return 0;}static int cdrom_media_erasable(struct cdrom_device_info *cdi){ disc_information di; int ret; ret = cdrom_get_disc_info(cdi, &di); if (ret < 0 || ret < offsetof(typeof(di), n_first_track)) return -1; return di.erasable;}/* * FIXME: check RO bit */static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi){ int ret = cdrom_media_erasable(cdi); /* * allow writable open if media info read worked and media is * erasable, _or_ if it fails since not all drives support it */ if (!ret) return 1; return 0;}static int cdrom_mrw_open_write(struct cdrom_device_info *cdi){ disc_information di; int ret; /* * always reset to DMA lba space on open */ if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) { printk(KERN_ERR "cdrom: failed setting lba address space\n"); return 1; } ret = cdrom_get_disc_info(cdi, &di); if (ret < 0 || ret < offsetof(typeof(di),disc_type)) return 1; if (!di.erasable) return 1; /* * mrw_status * 0 - not MRW formatted * 1 - MRW bgformat started, but not running or complete * 2 - MRW bgformat in progress * 3 - MRW formatting complete */ ret = 0; printk(KERN_INFO "cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]); if (!di.mrw_status) ret = 1; else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart) ret = cdrom_mrw_bgformat(cdi, 1); return ret;}static int mo_open_write(struct cdrom_device_info *cdi){ struct packet_command cgc; char buffer[255]; int ret; init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ); cgc.quiet = 1; /* * obtain write protect information as per * drivers/scsi/sd.c:sd_read_write_protect_flag */ ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); if (ret) ret = cdrom_mode_sense(cdi, &cgc, GPMODE_VENDOR_PAGE, 0); if (ret) { cgc.buflen = 255; ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); } /* drive gave us no info, let the user go ahead */ if (ret) return 0; return buffer[3] & 0x80;}static int cdrom_ram_open_write(struct cdrom_device_info *cdi){ struct rwrt_feature_desc rfd; int ret; if ((ret = cdrom_has_defect_mgt(cdi))) return ret; if ((ret = cdrom_get_random_writable(cdi, &rfd))) return ret; else if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) ret = !rfd.curr; cdinfo(CD_OPEN, "can open for random write\n"); return ret;}static void cdrom_mmc3_profile(struct cdrom_device_info *cdi){ struct packet_command cgc; char buffer[32]; int ret, mmc3_profile; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[1] = 0; cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */ cgc.cmd[8] = sizeof(buffer); /* Allocation Length */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) mmc3_profile = 0xffff; else mmc3_profile = (buffer[6] << 8) | buffer[7]; cdi->mmc3_profile = mmc3_profile;}static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi){ switch (cdi->mmc3_profile) { case 0x12: /* DVD-RAM */ case 0x1A: /* DVD+RW */ return 0; default: return 1; }}/* * returns 0 for ok to open write, non-0 to disallow */static int cdrom_open_write(struct cdrom_device_info *cdi){ int mrw, mrw_write, ram_write; int ret = 1; mrw = 0; if (!cdrom_is_mrw(cdi, &mrw_write)) mrw = 1; if (CDROM_CAN(CDC_MO_DRIVE)) ram_write = 1; else (void) cdrom_is_random_writable(cdi, &ram_write); if (mrw) cdi->mask &= ~CDC_MRW; else cdi->mask |= CDC_MRW; if (mrw_write) cdi->mask &= ~CDC_MRW_W; else cdi->mask |= CDC_MRW_W; if (ram_write) cdi->mask &= ~CDC_RAM; else cdi->mask |= CDC_RAM; if (CDROM_CAN(CDC_MRW_W)) ret = cdrom_mrw_open_write(cdi); else if (CDROM_CAN(CDC_DVD_RAM)) ret = cdrom_dvdram_open_write(cdi); else if (CDROM_CAN(CDC_RAM) && !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW|CDC_MO_DRIVE)) ret = cdrom_ram_open_write(cdi); else if (CDROM_CAN(CDC_MO_DRIVE)) ret = mo_open_write(cdi); else if (!cdrom_is_dvd_rw(cdi)) ret = 0; return ret;}static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi){ struct packet_command cgc; if (cdi->mmc3_profile != 0x1a) { cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name); return; } if (!cdi->media_written) { cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name); return; } printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n", cdi->name); init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?