?? pcd.c
字號:
"generic packet");}#define DBMSG(msg) ((verbose>1)?(msg):NULL)static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr){ struct pcd_unit *cd = cdi->handle; int res = cd->changed; if (res) cd->changed = 0; return res;}static int pcd_lock_door(struct cdrom_device_info *cdi, int lock){ char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 }; return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch, lock ? "lock door" : "unlock door");}static int pcd_tray_move(struct cdrom_device_info *cdi, int position){ char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 }; return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch, position ? "eject" : "close tray");}static void pcd_sleep(int cs){ schedule_timeout_interruptible(cs);}static int pcd_reset(struct pcd_unit *cd){ int i, k, flg; int expect[5] = { 1, 1, 1, 0x14, 0xeb }; pi_connect(cd->pi); write_reg(cd, 6, 0xa0 + 0x10 * cd->drive); write_reg(cd, 7, 8); pcd_sleep(20 * HZ / 1000); /* delay a bit */ k = 0; while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY)) pcd_sleep(HZ / 10); flg = 1; for (i = 0; i < 5; i++) flg &= (read_reg(cd, i + 1) == expect[i]); if (verbose) { printk("%s: Reset (%d) signature = ", cd->name, k); for (i = 0; i < 5; i++) printk("%3x", read_reg(cd, i + 1)); if (!flg) printk(" (incorrect)"); printk("\n"); } pi_disconnect(cd->pi); return flg - 1;}static int pcd_drive_reset(struct cdrom_device_info *cdi){ return pcd_reset(cdi->handle);}static int pcd_ready_wait(struct pcd_unit *cd, int tmo){ char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int k, p; k = 0; while (k < tmo) { cd->last_sense = 0; pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready")); p = cd->last_sense; if (!p) return 0; if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6))) return p; k++; pcd_sleep(HZ); } return 0x000020; /* timeout */}static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr){ char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; struct pcd_unit *cd = cdi->handle; if (pcd_ready_wait(cd, PCD_READY_TMO)) return CDS_DRIVE_NOT_READY; if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media"))) return CDS_NO_DISC; return CDS_DISC_OK;}static int pcd_identify(struct pcd_unit *cd, char *id){ int k, s; char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; pcd_bufblk = -1; s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify"); if (s) return -1; if ((pcd_buffer[0] & 0x1f) != 5) { if (verbose) printk("%s: %s is not a CD-ROM\n", cd->name, cd->drive ? "Slave" : "Master"); return -1; } memcpy(id, pcd_buffer + 16, 16); id[16] = 0; k = 16; while ((k >= 0) && (id[k] <= 0x20)) { id[k] = 0; k--; } printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id); return 0;}/* * returns 0, with id set if drive is detected * -1, if drive detection failed */static int pcd_probe(struct pcd_unit *cd, int ms, char *id){ if (ms == -1) { for (cd->drive = 0; cd->drive <= 1; cd->drive++) if (!pcd_reset(cd) && !pcd_identify(cd, id)) return 0; } else { cd->drive = ms; if (!pcd_reset(cd) && !pcd_identify(cd, id)) return 0; } return -1;}static void pcd_probe_capabilities(void){ int unit, r; char buffer[32]; char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 }; struct pcd_unit *cd; for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { if (!cd->present) continue; r = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities"); if (r) continue; /* we should now have the cap page */ if ((buffer[11] & 1) == 0) cd->info.mask |= CDC_CD_R; if ((buffer[11] & 2) == 0) cd->info.mask |= CDC_CD_RW; if ((buffer[12] & 1) == 0) cd->info.mask |= CDC_PLAY_AUDIO; if ((buffer[14] & 1) == 0) cd->info.mask |= CDC_LOCK; if ((buffer[14] & 8) == 0) cd->info.mask |= CDC_OPEN_TRAY; if ((buffer[14] >> 6) == 0) cd->info.mask |= CDC_CLOSE_TRAY; }}static int pcd_detect(void){ char id[18]; int k, unit; struct pcd_unit *cd; printk("%s: %s version %s, major %d, nice %d\n", name, name, PCD_VERSION, major, nice); k = 0; if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ cd = pcd; if (pi_init(cd->pi, 1, -1, -1, -1, -1, -1, pcd_buffer, PI_PCD, verbose, cd->name)) { if (!pcd_probe(cd, -1, id) && cd->disk) { cd->present = 1; k++; } else pi_release(cd->pi); } } else { for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { int *conf = *drives[unit]; if (!conf[D_PRT]) continue; if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD], conf[D_UNI], conf[D_PRO], conf[D_DLY], pcd_buffer, PI_PCD, verbose, cd->name)) continue; if (!pcd_probe(cd, conf[D_SLV], id) && cd->disk) { cd->present = 1; k++; } else pi_release(cd->pi); } } if (k) return 0; printk("%s: No CD-ROM drive found\n", name); for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) put_disk(cd->disk); return -1;}/* I/O request processing */static struct request_queue *pcd_queue;static void do_pcd_request(request_queue_t * q){ if (pcd_busy) return; while (1) { pcd_req = elv_next_request(q); if (!pcd_req) return; if (rq_data_dir(pcd_req) == READ) { struct pcd_unit *cd = pcd_req->rq_disk->private_data; if (cd != pcd_current) pcd_bufblk = -1; pcd_current = cd; pcd_sector = pcd_req->sector; pcd_count = pcd_req->current_nr_sectors; pcd_buf = pcd_req->buffer; pcd_busy = 1; ps_set_intr(do_pcd_read, NULL, 0, nice); return; } else end_request(pcd_req, 0); }}static inline void next_request(int success){ unsigned long saved_flags; spin_lock_irqsave(&pcd_lock, saved_flags); end_request(pcd_req, success); pcd_busy = 0; do_pcd_request(pcd_queue); spin_unlock_irqrestore(&pcd_lock, saved_flags);}static int pcd_ready(void){ return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));}static void pcd_transfer(void){ while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) { int o = (pcd_sector % 4) * 512; memcpy(pcd_buf, pcd_buffer + o, 512); pcd_count--; pcd_buf += 512; pcd_sector++; }}static void pcd_start(void){ int b, i; char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; pcd_bufblk = pcd_sector / 4; b = pcd_bufblk; for (i = 0; i < 4; i++) { rd_cmd[5 - i] = b & 0xff; b = b >> 8; } if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) { pcd_bufblk = -1; next_request(0); return; } mdelay(1); ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);}static void do_pcd_read(void){ pcd_busy = 1; pcd_retries = 0; pcd_transfer(); if (!pcd_count) { next_request(1); return; } pi_do_claimed(pcd_current->pi, pcd_start);}static void do_pcd_read_drq(void){ unsigned long saved_flags; if (pcd_completion(pcd_current, pcd_buffer, "read block")) { if (pcd_retries < PCD_RETRIES) { mdelay(1); pcd_retries++; pi_do_claimed(pcd_current->pi, pcd_start); return; } pcd_bufblk = -1; next_request(0); return; } do_pcd_read(); spin_lock_irqsave(&pcd_lock, saved_flags); do_pcd_request(pcd_queue); spin_unlock_irqrestore(&pcd_lock, saved_flags);}/* the audio_ioctl stuff is adapted from sr_ioctl.c */static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg){ struct pcd_unit *cd = cdi->handle; switch (cmd) { case CDROMREADTOCHDR: { char cmd[12] = { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0 }; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; char buffer[32]; int r; r = pcd_atapi(cd, cmd, 12, buffer, "read toc header"); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; return r ? -EIO : 0; } case CDROMREADTOCENTRY: { char cmd[12] = { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0 }; struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; unsigned char buffer[32]; int r; cmd[1] = (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); cmd[6] = tocentry->cdte_track; r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry"); tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_adr = buffer[5] >> 4; tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; if (tocentry->cdte_format == CDROM_MSF) { tocentry->cdte_addr.msf.minute = buffer[9]; tocentry->cdte_addr.msf.second = buffer[10]; tocentry->cdte_addr.msf.frame = buffer[11]; } else tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + buffer[10]) << 8) + buffer[11]; return r ? -EIO : 0; } default: return -ENOSYS; }}static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn){ char cmd[12] = { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 }; char buffer[32]; if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn")) return -EIO; memcpy(mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; return 0;}static int __init pcd_init(void){ struct pcd_unit *cd; int unit; if (disable) return -1; pcd_init_units(); if (pcd_detect()) return -1; /* get the atapi capabilities page */ pcd_probe_capabilities(); if (register_blkdev(major, name)) { for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) put_disk(cd->disk); return -1; } pcd_queue = blk_init_queue(do_pcd_request, &pcd_lock); if (!pcd_queue) { unregister_blkdev(major, name); for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) put_disk(cd->disk); return -1; } for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { if (cd->present) { register_cdrom(&cd->info); cd->disk->private_data = cd; cd->disk->queue = pcd_queue; add_disk(cd->disk); } } return 0;}static void __exit pcd_exit(void){ struct pcd_unit *cd; int unit; for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { if (cd->present) { del_gendisk(cd->disk); pi_release(cd->pi); unregister_cdrom(&cd->info); } put_disk(cd->disk); } blk_cleanup_queue(pcd_queue); unregister_blkdev(major, name);}MODULE_LICENSE("GPL");module_init(pcd_init)module_exit(pcd_exit)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -