📄 cdrom.c
字号:
return ret;}static int cdrom_media_changed(kdev_t dev){ struct cdrom_device_info *cdi = cdrom_find_device(dev); /* This talks to the VFS, which doesn't like errors - just 1 or 0. * Returning "0" is always safe (media hasn't been changed). Do that * if the low-level cdrom driver dosn't support media changed. */ if (cdi == NULL || cdi->ops->media_changed == NULL) return 0; if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return 0; return media_changed(cdi, 0);}/* badly broken, I know. Is due for a fixup anytime. */void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks){ struct cdrom_tochdr header; struct cdrom_tocentry entry; int ret, i; tracks->data=0; tracks->audio=0; tracks->cdi=0; tracks->xa=0; tracks->error=0; cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); if (!CDROM_CAN(CDC_PLAY_AUDIO)) { tracks->error=CDS_NO_INFO; return; } /* Grab the TOC header so we can see how many tracks there are */ if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { if (ret == -ENOMEDIUM) tracks->error = CDS_NO_DISC; else tracks->error = CDS_NO_INFO; return; } /* check what type of tracks are on this disc */ entry.cdte_format = CDROM_MSF; for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { entry.cdte_track = i; if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { tracks->error=CDS_NO_INFO; return; } if (entry.cdte_ctrl & CDROM_DATA_TRACK) { if (entry.cdte_format == 0x10) tracks->cdi++; else if (entry.cdte_format == 0x20) tracks->xa++; else tracks->data++; } else tracks->audio++; cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", i, entry.cdte_format, entry.cdte_ctrl); } cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", header.cdth_trk1, tracks->audio, tracks->data, tracks->cdi, tracks->xa);} /* Requests to the low-level drivers will /always/ be done in the following format convention: CDROM_LBA: all data-related requests. CDROM_MSF: all audio-related requests. However, a low-level implementation is allowed to refuse this request, and return information in its own favorite format. It doesn't make sense /at all/ to ask for a play_audio in LBA format, or ask for multi-session info in MSF format. However, for backward compatibility these format requests will be satisfied, but the requests to the low-level drivers will be sanitized in the more meaningful format indicated above. */staticvoid sanitize_format(union cdrom_addr *addr, u_char * curr, u_char requested){ if (*curr == requested) return; /* nothing to be done! */ if (requested == CDROM_LBA) { addr->lba = (int) addr->msf.frame + 75 * (addr->msf.second - 2 + 60 * addr->msf.minute); } else { /* CDROM_MSF */ int lba = addr->lba; addr->msf.frame = lba % 75; lba /= 75; lba += 2; addr->msf.second = lba % 60; addr->msf.minute = lba / 60; } *curr = requested;}void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len, int type){ memset(cgc, 0, sizeof(struct cdrom_generic_command)); if (buf) memset(buf, 0, len); cgc->buffer = (char *) buf; cgc->buflen = len; cgc->data_direction = type; cgc->timeout = 5*HZ;}/* DVD handling */#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key))#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))static void setup_report_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type){ cgc->cmd[0] = GPCMD_REPORT_KEY; cgc->cmd[10] = type | (agid << 6); switch (type) { case 0: case 8: case 5: { cgc->buflen = 8; break; } case 1: { cgc->buflen = 16; break; } case 2: case 4: { cgc->buflen = 12; break; } } cgc->cmd[9] = cgc->buflen; cgc->data_direction = CGC_DATA_READ;}static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type){ cgc->cmd[0] = GPCMD_SEND_KEY; cgc->cmd[10] = type | (agid << 6); switch (type) { case 1: { cgc->buflen = 16; break; } case 3: { cgc->buflen = 12; break; } case 6: { cgc->buflen = 8; break; } } cgc->cmd[9] = cgc->buflen; cgc->data_direction = CGC_DATA_WRITE;}static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai){ int ret; u_char buf[20]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; rpc_state_t rpc_state; memset(buf, 0, sizeof(buf)); init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); switch (ai->type) { /* LU data send */ case DVD_LU_SEND_AGID: cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); setup_report_key(&cgc, ai->lsa.agid, 0); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; ai->lsa.agid = buf[7] >> 6; /* Returning data, let host change state */ break; case DVD_LU_SEND_KEY1: cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); setup_report_key(&cgc, ai->lsk.agid, 2); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; copy_key(ai->lsk.key, &buf[4]); /* Returning data, let host change state */ break; case DVD_LU_SEND_CHALLENGE: cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); setup_report_key(&cgc, ai->lsc.agid, 1); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; copy_chal(ai->lsc.chal, &buf[4]); /* Returning data, let host change state */ break; /* Post-auth key */ case DVD_LU_SEND_TITLE_KEY: cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); setup_report_key(&cgc, ai->lstk.agid, 4); cgc.cmd[5] = ai->lstk.lba; cgc.cmd[4] = ai->lstk.lba >> 8; cgc.cmd[3] = ai->lstk.lba >> 16; cgc.cmd[2] = ai->lstk.lba >> 24; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; ai->lstk.cpm = (buf[4] >> 7) & 1; ai->lstk.cp_sec = (buf[4] >> 6) & 1; ai->lstk.cgms = (buf[4] >> 4) & 3; copy_key(ai->lstk.title_key, &buf[5]); /* Returning data, let host change state */ break; case DVD_LU_SEND_ASF: cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); setup_report_key(&cgc, ai->lsasf.agid, 5); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; ai->lsasf.asf = buf[7] & 1; break; /* LU data receive (LU changes state) */ case DVD_HOST_SEND_CHALLENGE: cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); setup_send_key(&cgc, ai->hsc.agid, 1); buf[1] = 0xe; copy_chal(&buf[4], ai->hsc.chal); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; ai->type = DVD_LU_SEND_KEY1; break; case DVD_HOST_SEND_KEY2: cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); setup_send_key(&cgc, ai->hsk.agid, 3); buf[1] = 0xa; copy_key(&buf[4], ai->hsk.key); if ((ret = cdo->generic_packet(cdi, &cgc))) { ai->type = DVD_AUTH_FAILURE; return ret; } ai->type = DVD_AUTH_ESTABLISHED; break; /* Misc */ case DVD_INVALIDATE_AGID: cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); setup_report_key(&cgc, ai->lsa.agid, 0x3f); if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; break; /* Get region settings */ case DVD_LU_SEND_RPC_STATE: cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); memset(&rpc_state, 0, sizeof(rpc_state_t)); cgc.buffer = (char *) &rpc_state; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; ai->lrpcs.type = rpc_state.type_code; ai->lrpcs.vra = rpc_state.vra; ai->lrpcs.ucca = rpc_state.ucca; ai->lrpcs.region_mask = rpc_state.region_mask; ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; break; /* Set region settings */ case DVD_HOST_SEND_RPC_STATE: cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); setup_send_key(&cgc, 0, 6); buf[1] = 6; buf[4] = ai->hrpcs.pdrc; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; break; default: cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); return -ENOTTY; } return 0;}static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s){ int ret, i; u_char buf[4 + 4 * 20], *base; struct dvd_layer *layer; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->physical.layer_num; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; base = &buf[4]; layer = &s->physical.layer[0]; /* place the data... really ugly, but at least we won't have to worry about endianess in userspace or here. */ for (i = 0; i < 4; ++i, base += 20, ++layer) { memset(layer, 0, sizeof(*layer)); layer->book_version = base[0] & 0xf; layer->book_type = base[0] >> 4; layer->min_rate = base[1] & 0xf; layer->disc_size = base[1] >> 4; layer->layer_type = base[2] & 0xf; layer->track_path = (base[2] >> 4) & 1; layer->nlayers = (base[2] >> 5) & 3; layer->track_density = base[3] & 0xf; layer->linear_density = base[3] >> 4; layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; layer->bca = base[16] >> 7; } return 0;}static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s){ int ret; u_char buf[8]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->copyright.layer_num; cgc.cmd[7] = s->type; cgc.cmd[8] = cgc.buflen >> 8; cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; s->copyright.cpst = buf[4]; s->copyright.rmi = buf[5]; return 0;}static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s){ int ret, size; u_char *buf; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; size = sizeof(s->disckey.value) + 4; if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[8] = size >> 8; cgc.cmd[9] = size & 0xff; cgc.cmd[10] = s->disckey.agid << 6; if (!(ret = cdo->generic_packet(cdi, &cgc))) memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value)); kfree(buf); return ret;}static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s){ int ret; u_char buf[4 + 188]; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen = 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; s->bca.len = buf[0] << 8 | buf[1]; if (s->bca.len < 12 || s->bca.len > 188) { cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); return -EIO; } memcpy(s->bca.value, &buf[4], s->bca.len); return 0;}static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s){ int ret = 0, size; u_char *buf; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; size = sizeof(s->manufact.value) + 4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -