mcd.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:36k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2. linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
  3. Copyright (C) 1992  Martin Harriss
  4. Portions Copyright (C) 2001 Red Hat
  5. martin@bdsi.com (no longer valid - where are you now, Martin?)
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. HISTORY
  18. 0.1 First attempt - internal use only
  19. 0.2 Cleaned up delays and use of timer - alpha release
  20. 0.3 Audio support added
  21. 0.3.1 Changes for mitsumi CRMC LU005S march version
  22.    (stud11@cc4.kuleuven.ac.be)
  23.         0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
  24.    (Jon Tombs <jon@robots.ox.ac.uk>)
  25.         0.3.3 Added more #defines and mcd_setup()
  26.        (Jon Tombs <jon@gtex02.us.es>)
  27. October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
  28. Braunschweig, Germany: rework to speed up data read operation.
  29. Also enabled definition of irq and address from bootstrap, using the
  30. environment.
  31. November 93 added code for FX001 S,D (single & double speed).
  32. February 94 added code for broken M 5/6 series of 16-bit single speed.
  33.         0.4   
  34.         Added support for loadable MODULEs, so mcd can now also be loaded by 
  35.         insmod and removed by rmmod during runtime.
  36.         Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
  37. 0.5
  38. I added code for FX001 D to drop from double speed to single speed 
  39. when encountering errors... this helps with some "problematic" CD's
  40. that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
  41. severely scratched, or possibly slightly warped! I have noticed that
  42. the Mitsumi 2x/4x drives are just less tolerant and the firmware is 
  43. not smart enough to drop speed, so let's just kludge it with software!
  44. ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
  45. Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
  46. even WORSE! ;)
  47. ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
  48. certain "large" CD's that have data on the outside edge in your 
  49. DOS DRIVERS .... Accuracy counts... speed is secondary ;)
  50. 17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
  51. 07 July 1995 Modifications by Andrew J. Kroll
  52. Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
  53. Michael K. Johnson <johnsonm@redhat.com> added retries on open
  54. for slow drives which take a while to recognize that they contain
  55. a CD.
  56. November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
  57. March    1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
  58. November 1999 -- Make kernel-parameter implementation work with 2.3.x 
  59.                  Removed init_module & cleanup_module in favor of 
  60.  module_init & module_exit.
  61.  Torben Mathiasen <tmm@image.dk>
  62. September 2001 - Reformatted and cleaned up the code
  63.  Alan Cox <alan@redhat.com>  
  64. */
  65. #include <linux/module.h>
  66. #include <linux/errno.h>
  67. #include <linux/signal.h>
  68. #include <linux/sched.h>
  69. #include <linux/mm.h>
  70. #include <linux/timer.h>
  71. #include <linux/fs.h>
  72. #include <linux/kernel.h>
  73. #include <linux/devfs_fs_kernel.h>
  74. #include <linux/cdrom.h>
  75. #include <linux/ioport.h>
  76. #include <linux/string.h>
  77. #include <linux/delay.h>
  78. #include <linux/init.h>
  79. #include <linux/config.h>
  80. /* #define REALLY_SLOW_IO  */
  81. #include <asm/system.h>
  82. #include <asm/io.h>
  83. #include <asm/uaccess.h>
  84. #define MAJOR_NR MITSUMI_CDROM_MAJOR
  85. #include <linux/blk.h>
  86. #define mcd_port mcd /* for compatible parameter passing with "insmod" */
  87. #include "mcd.h"
  88. static int mcd_blocksizes[1];
  89. /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
  90. static int mcdDouble;
  91. /* How many sectors to hold at 1x speed counter */
  92. static int mcd1xhold;
  93. /* Is the drive connected properly and responding?? */
  94. static int mcdPresent;
  95. #define QUICK_LOOP_DELAY udelay(45) /* use udelay */
  96. #define QUICK_LOOP_COUNT 20
  97. #define CURRENT_VALID 
  98. (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ 
  99. && CURRENT -> sector != -1)
  100. #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
  101. #define MCD_BUF_SIZ 16
  102. static volatile int mcd_transfer_is_active;
  103. static char mcd_buf[2048 * MCD_BUF_SIZ]; /* buffer for block size conversion */
  104. static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
  105. static volatile int mcd_buf_in, mcd_buf_out = -1;
  106. static volatile int mcd_error;
  107. static int mcd_open_count;
  108. enum mcd_state_e {
  109. MCD_S_IDLE, /* 0 */
  110. MCD_S_START, /* 1 */
  111. MCD_S_MODE, /* 2 */
  112. MCD_S_READ, /* 3 */
  113. MCD_S_DATA, /* 4 */
  114. MCD_S_STOP, /* 5 */
  115. MCD_S_STOPPING /* 6 */
  116. };
  117. static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
  118. static int mcd_mode = -1;
  119. static int MCMD_DATA_READ = MCMD_PLAY_READ;
  120. #define READ_TIMEOUT 3000
  121. int mitsumi_bug_93_wait;
  122. static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
  123. static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */
  124. MODULE_PARM(mcd, "1-2i");
  125. static int McdTimeout, McdTries;
  126. static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
  127. static struct mcd_DiskInfo DiskInfo;
  128. static struct mcd_Toc Toc[MAX_TRACKS];
  129. static struct mcd_Play_msf mcd_Play;
  130. static int audioStatus;
  131. static char mcdDiskChanged;
  132. static char tocUpToDate;
  133. static char mcdVersion;
  134. static void mcd_transfer(void);
  135. static void mcd_poll(unsigned long dummy);
  136. static void mcd_invalidate_buffers(void);
  137. static void hsg2msf(long hsg, struct msf *msf);
  138. static void bin2bcd(unsigned char *p);
  139. static int bcd2bin(unsigned char bcd);
  140. static int mcdStatus(void);
  141. static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
  142. static int getMcdStatus(int timeout);
  143. static int GetQChannelInfo(struct mcd_Toc *qp);
  144. static int updateToc(void);
  145. static int GetDiskInfo(void);
  146. static int GetToc(void);
  147. static int getValue(unsigned char *result);
  148. static int mcd_open(struct cdrom_device_info *cdi, int purpose);
  149. static void mcd_release(struct cdrom_device_info *cdi);
  150. static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
  151. static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
  152. int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
  153.     void *arg);
  154. int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
  155. struct block_device_operations mcd_bdops =
  156. {
  157. owner: THIS_MODULE,
  158. open: cdrom_open,
  159. release: cdrom_release,
  160. ioctl: cdrom_ioctl,
  161. check_media_change: cdrom_media_changed,
  162. };
  163. static struct timer_list mcd_timer;
  164. static struct cdrom_device_ops mcd_dops = {
  165. open:mcd_open,
  166. release:mcd_release,
  167. drive_status:mcd_drive_status,
  168. media_changed:mcd_media_changed,
  169. tray_move:mcd_tray_move,
  170. audio_ioctl:mcd_audio_ioctl,
  171. capability:CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
  172.     CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
  173. };
  174. static struct cdrom_device_info mcd_info = {
  175. ops:&mcd_dops,
  176. speed:2,
  177. capacity:1,
  178. name:"mcd",
  179. };
  180. #ifndef MODULE
  181. static int __init mcd_setup(char *str)
  182. {
  183. int ints[9];
  184. (void) get_options(str, ARRAY_SIZE(ints), ints);
  185. if (ints[0] > 0)
  186. mcd_port = ints[1];
  187. if (ints[0] > 1)
  188. mcd_irq = ints[2];
  189. if (ints[0] > 2)
  190. mitsumi_bug_93_wait = ints[3];
  191. return 1;
  192. }
  193. __setup("mcd=", mcd_setup);
  194. #endif /* MODULE */
  195. static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
  196. {
  197. return 0;
  198. }
  199. /*
  200.  * Do a 'get status' command and get the result.  Only use from the top half
  201.  * because it calls 'getMcdStatus' which sleeps.
  202.  */
  203. static int statusCmd(void)
  204. {
  205. int st = -1, retry;
  206. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  207. /* send get-status cmd */
  208. outb(MCMD_GET_STATUS, MCDPORT(0));
  209. st = getMcdStatus(MCD_STATUS_DELAY);
  210. if (st != -1)
  211. break;
  212. }
  213. return st;
  214. }
  215. /*
  216.  * Send a 'Play' command and get the status.  Use only from the top half.
  217.  */
  218. static int mcdPlay(struct mcd_Play_msf *arg)
  219. {
  220. int retry, st = -1;
  221. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  222. sendMcdCmd(MCMD_PLAY_READ, arg);
  223. st = getMcdStatus(2 * MCD_STATUS_DELAY);
  224. if (st != -1)
  225. break;
  226. }
  227. return st;
  228. }
  229. static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
  230. {
  231. int i;
  232. if (position) {
  233. /*  Eject */
  234. /* all drives can at least stop! */
  235. if (audioStatus == CDROM_AUDIO_PLAY) {
  236. outb(MCMD_STOP, MCDPORT(0));
  237. i = getMcdStatus(MCD_STATUS_DELAY);
  238. }
  239. audioStatus = CDROM_AUDIO_NO_STATUS;
  240. outb(MCMD_EJECT, MCDPORT(0));
  241. /*
  242.  * the status (i) shows failure on all but the FX drives.
  243.  * But nothing we can do about that in software!
  244.  * So just read the status and forget it. - Jon.
  245.  */
  246. i = getMcdStatus(MCD_STATUS_DELAY);
  247. return 0;
  248. } else
  249. return -EINVAL;
  250. }
  251. long msf2hsg(struct msf *mp)
  252. {
  253. return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
  254. }
  255. int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
  256.     void *arg)
  257. {
  258. int i, st;
  259. struct mcd_Toc qInfo;
  260. struct cdrom_ti *ti;
  261. struct cdrom_tochdr *tocHdr;
  262. struct cdrom_msf *msf;
  263. struct cdrom_subchnl *subchnl;
  264. struct cdrom_tocentry *entry;
  265. struct mcd_Toc *tocPtr;
  266. struct cdrom_volctrl *volctrl;
  267. st = statusCmd();
  268. if (st < 0)
  269. return -EIO;
  270. if (!tocUpToDate) {
  271. i = updateToc();
  272. if (i < 0)
  273. return i; /* error reading TOC */
  274. }
  275. switch (cmd) {
  276. case CDROMSTART: /* Spin up the drive */
  277. /* Don't think we can do this.  Even if we could,
  278.  * I think the drive times out and stops after a while
  279.  * anyway.  For now, ignore it.
  280.  */
  281. return 0;
  282. case CDROMSTOP: /* Spin down the drive */
  283. outb(MCMD_STOP, MCDPORT(0));
  284. i = getMcdStatus(MCD_STATUS_DELAY);
  285. /* should we do anything if it fails? */
  286. audioStatus = CDROM_AUDIO_NO_STATUS;
  287. return 0;
  288. case CDROMPAUSE: /* Pause the drive */
  289. if (audioStatus != CDROM_AUDIO_PLAY)
  290. return -EINVAL;
  291. outb(MCMD_STOP, MCDPORT(0));
  292. i = getMcdStatus(MCD_STATUS_DELAY);
  293. if (GetQChannelInfo(&qInfo) < 0) {
  294. /* didn't get q channel info */
  295. audioStatus = CDROM_AUDIO_NO_STATUS;
  296. return 0;
  297. }
  298. mcd_Play.start = qInfo.diskTime; /* remember restart point */
  299. audioStatus = CDROM_AUDIO_PAUSED;
  300. return 0;
  301. case CDROMRESUME: /* Play it again, Sam */
  302. if (audioStatus != CDROM_AUDIO_PAUSED)
  303. return -EINVAL;
  304. /* restart the drive at the saved position. */
  305. i = mcdPlay(&mcd_Play);
  306. if (i < 0) {
  307. audioStatus = CDROM_AUDIO_ERROR;
  308. return -EIO;
  309. }
  310. audioStatus = CDROM_AUDIO_PLAY;
  311. return 0;
  312. case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
  313. ti = (struct cdrom_ti *) arg;
  314. if (ti->cdti_trk0 < DiskInfo.first
  315.     || ti->cdti_trk0 > DiskInfo.last
  316.     || ti->cdti_trk1 < ti->cdti_trk0) {
  317. return -EINVAL;
  318. }
  319. if (ti->cdti_trk1 > DiskInfo.last)
  320. ti->cdti_trk1 = DiskInfo.last;
  321. mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
  322. mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
  323. #ifdef MCD_DEBUG
  324. printk("play: %02x:%02x.%02x to %02x:%02x.%02xn",
  325.        mcd_Play.start.min, mcd_Play.start.sec,
  326.        mcd_Play.start.frame, mcd_Play.end.min,
  327.        mcd_Play.end.sec, mcd_Play.end.frame);
  328. #endif
  329. i = mcdPlay(&mcd_Play);
  330. if (i < 0) {
  331. audioStatus = CDROM_AUDIO_ERROR;
  332. return -EIO;
  333. }
  334. audioStatus = CDROM_AUDIO_PLAY;
  335. return 0;
  336. case CDROMPLAYMSF: /* Play starting at the given MSF address. */
  337. if (audioStatus == CDROM_AUDIO_PLAY) {
  338. outb(MCMD_STOP, MCDPORT(0));
  339. i = getMcdStatus(MCD_STATUS_DELAY);
  340. audioStatus = CDROM_AUDIO_NO_STATUS;
  341. }
  342. msf = (struct cdrom_msf *) arg;
  343. /* convert to bcd */
  344. bin2bcd(&msf->cdmsf_min0);
  345. bin2bcd(&msf->cdmsf_sec0);
  346. bin2bcd(&msf->cdmsf_frame0);
  347. bin2bcd(&msf->cdmsf_min1);
  348. bin2bcd(&msf->cdmsf_sec1);
  349. bin2bcd(&msf->cdmsf_frame1);
  350. mcd_Play.start.min = msf->cdmsf_min0;
  351. mcd_Play.start.sec = msf->cdmsf_sec0;
  352. mcd_Play.start.frame = msf->cdmsf_frame0;
  353. mcd_Play.end.min = msf->cdmsf_min1;
  354. mcd_Play.end.sec = msf->cdmsf_sec1;
  355. mcd_Play.end.frame = msf->cdmsf_frame1;
  356. #ifdef MCD_DEBUG
  357. printk("play: %02x:%02x.%02x to %02x:%02x.%02xn",
  358.        mcd_Play.start.min, mcd_Play.start.sec,
  359.        mcd_Play.start.frame, mcd_Play.end.min,
  360.        mcd_Play.end.sec, mcd_Play.end.frame);
  361. #endif
  362. i = mcdPlay(&mcd_Play);
  363. if (i < 0) {
  364. audioStatus = CDROM_AUDIO_ERROR;
  365. return -EIO;
  366. }
  367. audioStatus = CDROM_AUDIO_PLAY;
  368. return 0;
  369. case CDROMREADTOCHDR: /* Read the table of contents header */
  370. tocHdr = (struct cdrom_tochdr *) arg;
  371. tocHdr->cdth_trk0 = DiskInfo.first;
  372. tocHdr->cdth_trk1 = DiskInfo.last;
  373. return 0;
  374. case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
  375. entry = (struct cdrom_tocentry *) arg;
  376. if (entry->cdte_track == CDROM_LEADOUT)
  377. tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
  378. else if (entry->cdte_track > DiskInfo.last
  379.  || entry->cdte_track < DiskInfo.first)
  380. return -EINVAL;
  381. else
  382. tocPtr = &Toc[entry->cdte_track];
  383. entry->cdte_adr = tocPtr->ctrl_addr;
  384. entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
  385. if (entry->cdte_format == CDROM_LBA)
  386. entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
  387. else if (entry->cdte_format == CDROM_MSF) {
  388. entry->cdte_addr.msf.minute =
  389.     bcd2bin(tocPtr->diskTime.min);
  390. entry->cdte_addr.msf.second =
  391.     bcd2bin(tocPtr->diskTime.sec);
  392. entry->cdte_addr.msf.frame =
  393.     bcd2bin(tocPtr->diskTime.frame);
  394. }
  395. else
  396. return -EINVAL;
  397. return 0;
  398. case CDROMSUBCHNL: /* Get subchannel info */
  399. subchnl = (struct cdrom_subchnl *) arg;
  400. if (GetQChannelInfo(&qInfo) < 0)
  401. return -EIO;
  402. subchnl->cdsc_audiostatus = audioStatus;
  403. subchnl->cdsc_adr = qInfo.ctrl_addr;
  404. subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
  405. subchnl->cdsc_trk = bcd2bin(qInfo.track);
  406. subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
  407. subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
  408. subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
  409. subchnl->cdsc_absaddr.msf.frame  = bcd2bin(qInfo.diskTime.frame);
  410. subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
  411. subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
  412. subchnl->cdsc_reladdr.msf.frame  = bcd2bin(qInfo.trackTime.frame);
  413. return (0);
  414. case CDROMVOLCTRL: /* Volume control */
  415. volctrl = (struct cdrom_volctrl *) arg;
  416. outb(MCMD_SET_VOLUME, MCDPORT(0));
  417. outb(volctrl->channel0, MCDPORT(0));
  418. outb(255, MCDPORT(0));
  419. outb(volctrl->channel1, MCDPORT(0));
  420. outb(255, MCDPORT(0));
  421. i = getMcdStatus(MCD_STATUS_DELAY);
  422. if (i < 0)
  423. return -EIO;
  424. {
  425. char a, b, c, d;
  426. getValue(&a);
  427. getValue(&b);
  428. getValue(&c);
  429. getValue(&d);
  430. }
  431. return 0;
  432. default:
  433. return -EINVAL;
  434. }
  435. }
  436. /*
  437.  * Take care of the different block sizes between cdrom and Linux.
  438.  * When Linux gets variable block sizes this will probably go away.
  439.  */
  440. static void mcd_transfer(void)
  441. {
  442. if (CURRENT_VALID) {
  443. while (CURRENT->nr_sectors) {
  444. int bn = CURRENT->sector / 4;
  445. int i;
  446. for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn;
  447.      ++i);
  448. if (i < MCD_BUF_SIZ) {
  449. int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
  450. int nr_sectors = 4 - (CURRENT->sector & 3);
  451. if (mcd_buf_out != i) {
  452. mcd_buf_out = i;
  453. if (mcd_buf_bn[i] != bn) {
  454. mcd_buf_out = -1;
  455. continue;
  456. }
  457. }
  458. if (nr_sectors > CURRENT->nr_sectors)
  459. nr_sectors = CURRENT->nr_sectors;
  460. memcpy(CURRENT->buffer, mcd_buf + offs,
  461.        nr_sectors * 512);
  462. CURRENT->nr_sectors -= nr_sectors;
  463. CURRENT->sector += nr_sectors;
  464. CURRENT->buffer += nr_sectors * 512;
  465. } else {
  466. mcd_buf_out = -1;
  467. break;
  468. }
  469. }
  470. }
  471. }
  472. /*
  473.  * We only seem to get interrupts after an error.
  474.  * Just take the interrupt and clear out the status reg.
  475.  */
  476. static void mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  477. {
  478. int st;
  479. st = inb(MCDPORT(1)) & 0xFF;
  480. test1(printk("<int1-%02X>", st));
  481. if (!(st & MFL_STATUS)) {
  482. st = inb(MCDPORT(0)) & 0xFF;
  483. test1(printk("<int0-%02X>", st));
  484. if ((st & 0xFF) != 0xFF)
  485. mcd_error = st ? st & 0xFF : -1;
  486. }
  487. }
  488. static void do_mcd_request(request_queue_t * q)
  489. {
  490. test2(printk(" do_mcd_request(%ld+%ld)n", CURRENT->sector,
  491.        CURRENT->nr_sectors));
  492. mcd_transfer_is_active = 1;
  493. while (CURRENT_VALID) {
  494. if (CURRENT->bh) {
  495. if (!buffer_locked(CURRENT->bh))
  496. panic(DEVICE_NAME ": block not locked");
  497. }
  498. mcd_transfer();
  499. if (CURRENT->nr_sectors == 0) {
  500. end_request(1);
  501. } else {
  502. mcd_buf_out = -1; /* Want to read a block not in buffer */
  503. if (mcd_state == MCD_S_IDLE) {
  504. if (!tocUpToDate) {
  505. if (updateToc() < 0) {
  506. while (CURRENT_VALID)
  507. end_request(0);
  508. break;
  509. }
  510. }
  511. mcd_state = MCD_S_START;
  512. McdTries = 5;
  513. mcd_timer.function = mcd_poll;
  514. mod_timer(&mcd_timer, jiffies + 1);
  515. }
  516. break;
  517. }
  518. }
  519. mcd_transfer_is_active = 0;
  520. test2(printk(" do_mcd_request endsn"));
  521. }
  522. static void mcd_poll(unsigned long dummy)
  523. {
  524. int st;
  525. if (mcd_error) {
  526. if (mcd_error & 0xA5) {
  527. printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
  528. if (mcd_error & 0x80)
  529. printk(" (Door open)");
  530. if (mcd_error & 0x20)
  531. printk(" (Disk changed)");
  532. if (mcd_error & 0x04) {
  533. printk(" (Read error)"); /* Bitch about the problem. */
  534. /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
  535. /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
  536. /* But I find that rather HANDY!!! */
  537. /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
  538. /* AJK [06/17/95] */
  539. /* Slap the CD down to single speed! */
  540. if (mcdDouble == 1
  541.     && McdTries == MCD_RETRY_ATTEMPTS
  542.     && MCMD_DATA_READ == MCMD_2X_READ) {
  543. MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
  544. mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
  545. printk(" Speed now 1x"); /* Pull my finger! */
  546. }
  547. }
  548. printk("n");
  549. mcd_invalidate_buffers();
  550. #ifdef WARN_IF_READ_FAILURE
  551. if (McdTries == MCD_RETRY_ATTEMPTS)
  552. printk(KERN_ERR "mcd: read of block %d failedn",
  553.        mcd_next_bn);
  554. #endif
  555. if (!McdTries--) {
  556. /* Nuts! This cd is ready for recycling! */
  557. /* When WAS the last time YOU cleaned it CORRECTLY?! */
  558. printk(KERN_ERR "mcd: read of block %d failed, giving upn",
  559.      mcd_next_bn);
  560. if (mcd_transfer_is_active) {
  561. McdTries = 0;
  562. goto ret;
  563. }
  564. if (CURRENT_VALID)
  565. end_request(0);
  566. McdTries = MCD_RETRY_ATTEMPTS;
  567. }
  568. }
  569. mcd_error = 0;
  570. mcd_state = MCD_S_STOP;
  571. }
  572. /* Switch back to Double speed if enough GOOD sectors were read! */
  573. /* Are we a double speed with a crappy CD?! */
  574. if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
  575.     && MCMD_DATA_READ == MCMD_PLAY_READ) {
  576. /* We ARE a double speed and we ARE bitching! */
  577. if (mcd1xhold == 0) { /* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
  578. MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
  579. printk(KERN_INFO "mcd: Switching back to 2X speed!n"); /* Tell 'em! */
  580. } else
  581. mcd1xhold--; /* No?! Count down the good reads some more... */
  582. /* and try, try again! */
  583. }
  584. immediately:
  585. switch (mcd_state) {
  586. case MCD_S_IDLE:
  587. test3(printk("MCD_S_IDLEn"));
  588. goto out;
  589. case MCD_S_START:
  590. test3(printk("MCD_S_STARTn"));
  591. outb(MCMD_GET_STATUS, MCDPORT(0));
  592. mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
  593. McdTimeout = 3000;
  594. break;
  595. case MCD_S_MODE:
  596. test3(printk("MCD_S_MODEn"));
  597. if ((st = mcdStatus()) != -1) {
  598. if (st & MST_DSK_CHG) {
  599. mcdDiskChanged = 1;
  600. tocUpToDate = 0;
  601. mcd_invalidate_buffers();
  602. }
  603. set_mode_immediately:
  604. if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
  605. mcdDiskChanged = 1;
  606. tocUpToDate = 0;
  607. if (mcd_transfer_is_active) {
  608. mcd_state = MCD_S_START;
  609. goto immediately;
  610. }
  611. printk(KERN_INFO);
  612. printk((st & MST_DOOR_OPEN) ?
  613.        "mcd: door openn" :
  614.        "mcd: disk removedn");
  615. mcd_state = MCD_S_IDLE;
  616. while (CURRENT_VALID)
  617. end_request(0);
  618. goto out;
  619. }
  620. outb(MCMD_SET_MODE, MCDPORT(0));
  621. outb(1, MCDPORT(0));
  622. mcd_mode = 1;
  623. mcd_state = MCD_S_READ;
  624. McdTimeout = 3000;
  625. }
  626. break;
  627. case MCD_S_READ:
  628. test3(printk("MCD_S_READn"));
  629. if ((st = mcdStatus()) != -1) {
  630. if (st & MST_DSK_CHG) {
  631. mcdDiskChanged = 1;
  632. tocUpToDate = 0;
  633. mcd_invalidate_buffers();
  634. }
  635. read_immediately:
  636. if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
  637. mcdDiskChanged = 1;
  638. tocUpToDate = 0;
  639. if (mcd_transfer_is_active) {
  640. mcd_state = MCD_S_START;
  641. goto immediately;
  642. }
  643. printk(KERN_INFO);
  644. printk((st & MST_DOOR_OPEN) ?
  645.        "mcd: door openn" :
  646.        "mcd: disk removedn");
  647. mcd_state = MCD_S_IDLE;
  648. while (CURRENT_VALID)
  649. end_request(0);
  650. goto out;
  651. }
  652. if (CURRENT_VALID) {
  653. struct mcd_Play_msf msf;
  654. mcd_next_bn = CURRENT->sector / 4;
  655. hsg2msf(mcd_next_bn, &msf.start);
  656. msf.end.min = ~0;
  657. msf.end.sec = ~0;
  658. msf.end.frame = ~0;
  659. sendMcdCmd(MCMD_DATA_READ, &msf);
  660. mcd_state = MCD_S_DATA;
  661. McdTimeout = READ_TIMEOUT;
  662. } else {
  663. mcd_state = MCD_S_STOP;
  664. goto immediately;
  665. }
  666. }
  667. break;
  668. case MCD_S_DATA:
  669. test3(printk("MCD_S_DATAn"));
  670. st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
  671. data_immediately:
  672. test5(printk("Status %02xn", st))
  673. switch (st) {
  674. case MFL_DATA:
  675. #ifdef WARN_IF_READ_FAILURE
  676. if (McdTries == 5)
  677. printk(KERN_WARNING "mcd: read of block %d failedn",
  678.        mcd_next_bn);
  679. #endif
  680. if (!McdTries--) {
  681. printk(KERN_ERR "mcd: read of block %d failed, giving upn", mcd_next_bn);
  682. if (mcd_transfer_is_active) {
  683. McdTries = 0;
  684. break;
  685. }
  686. if (CURRENT_VALID)
  687. end_request(0);
  688. McdTries = 5;
  689. }
  690. mcd_state = MCD_S_START;
  691. McdTimeout = READ_TIMEOUT;
  692. goto immediately;
  693. case MFL_STATUSorDATA:
  694. break;
  695. default:
  696. McdTries = 5;
  697. if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
  698. mcd_state = MCD_S_STOP;
  699. goto immediately;
  700. }
  701. mcd_buf_bn[mcd_buf_in] = -1;
  702. insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
  703.   2048);
  704. mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
  705. if (mcd_buf_out == -1)
  706. mcd_buf_out = mcd_buf_in;
  707. mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
  708. if (!mcd_transfer_is_active) {
  709. while (CURRENT_VALID) {
  710. mcd_transfer();
  711. if (CURRENT->nr_sectors == 0)
  712. end_request(1);
  713. else
  714. break;
  715. }
  716. }
  717. if (CURRENT_VALID
  718.     && (CURRENT->sector / 4 < mcd_next_bn ||
  719. CURRENT->sector / 4 > mcd_next_bn + 16)) {
  720. mcd_state = MCD_S_STOP;
  721. goto immediately;
  722. }
  723. McdTimeout = READ_TIMEOUT;
  724. {
  725. int count = QUICK_LOOP_COUNT;
  726. while (count--) {
  727. QUICK_LOOP_DELAY;
  728. if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
  729. test4(printk(" %d ", QUICK_LOOP_COUNT - count));
  730. goto data_immediately;
  731. }
  732. }
  733. test4(printk("ended "));
  734. }
  735. break;
  736. }
  737. break;
  738. case MCD_S_STOP:
  739. test3(printk("MCD_S_STOPn"));
  740. if (!mitsumi_bug_93_wait)
  741. goto do_not_work_around_mitsumi_bug_93_1;
  742. McdTimeout = mitsumi_bug_93_wait;
  743. mcd_state = 9 + 3 + 1;
  744. break;
  745. case 9 + 3 + 1:
  746. if (McdTimeout)
  747. break;
  748. do_not_work_around_mitsumi_bug_93_1:
  749. outb(MCMD_STOP, MCDPORT(0));
  750. if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
  751. int i = 4096;
  752. do {
  753. inb(MCDPORT(0));
  754. } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
  755. outb(MCMD_STOP, MCDPORT(0));
  756. if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
  757. i = 4096;
  758. do {
  759. inb(MCDPORT(0));
  760. } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
  761. outb(MCMD_STOP, MCDPORT(0));
  762. }
  763. }
  764. mcd_state = MCD_S_STOPPING;
  765. McdTimeout = 1000;
  766. break;
  767. case MCD_S_STOPPING:
  768. test3(printk("MCD_S_STOPPINGn"));
  769. if ((st = mcdStatus()) == -1 && McdTimeout)
  770. break;
  771. if ((st != -1) && (st & MST_DSK_CHG)) {
  772. mcdDiskChanged = 1;
  773. tocUpToDate = 0;
  774. mcd_invalidate_buffers();
  775. }
  776. if (!mitsumi_bug_93_wait)
  777. goto do_not_work_around_mitsumi_bug_93_2;
  778. McdTimeout = mitsumi_bug_93_wait;
  779. mcd_state = 9 + 3 + 2;
  780. break;
  781. case 9 + 3 + 2:
  782. if (McdTimeout)
  783. break;
  784. st = -1;
  785. do_not_work_around_mitsumi_bug_93_2:
  786. test3(printk("CURRENT_VALID %d mcd_mode %dn", CURRENT_VALID, mcd_mode));
  787. if (CURRENT_VALID) {
  788. if (st != -1) {
  789. if (mcd_mode == 1)
  790. goto read_immediately;
  791. else
  792. goto set_mode_immediately;
  793. } else {
  794. mcd_state = MCD_S_START;
  795. McdTimeout = 1;
  796. }
  797. } else {
  798. mcd_state = MCD_S_IDLE;
  799. goto out;
  800. }
  801. break;
  802. default:
  803. printk(KERN_ERR "mcd: invalid state %dn", mcd_state);
  804. goto out;
  805. }
  806. ret:
  807. if (!McdTimeout--) {
  808. printk(KERN_WARNING "mcd: timeout in state %dn", mcd_state);
  809. mcd_state = MCD_S_STOP;
  810. }
  811. mcd_timer.function = mcd_poll;
  812. mod_timer(&mcd_timer, jiffies + 1);
  813. out:
  814. return;
  815. }
  816. static void mcd_invalidate_buffers(void)
  817. {
  818. int i;
  819. for (i = 0; i < MCD_BUF_SIZ; ++i)
  820. mcd_buf_bn[i] = -1;
  821. mcd_buf_out = -1;
  822. }
  823. /*
  824.  * Open the device special file.  Check that a disk is in.
  825.  */
  826. static int mcd_open(struct cdrom_device_info *cdi, int purpose)
  827. {
  828. int st, count = 0;
  829. if (mcdPresent == 0)
  830. return -ENXIO; /* no hardware */
  831. if (mcd_open_count || mcd_state != MCD_S_IDLE)
  832. goto bump_count;
  833. mcd_invalidate_buffers();
  834. do {
  835. st = statusCmd(); /* check drive status */
  836. if (st == -1)
  837. goto err_out; /* drive doesn't respond */
  838. if ((st & MST_READY) == 0) { /* no disk? wait a sec... */
  839. current->state = TASK_INTERRUPTIBLE;
  840. schedule_timeout(HZ);
  841. }
  842. } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
  843. if (updateToc() < 0)
  844. goto err_out;
  845. bump_count:
  846. ++mcd_open_count;
  847. return 0;
  848. err_out:
  849. return -EIO;
  850. }
  851. /*
  852.  * On close, we flush all mcd blocks from the buffer cache.
  853.  */
  854. static void mcd_release(struct cdrom_device_info *cdi)
  855. {
  856. if (!--mcd_open_count) {
  857. mcd_invalidate_buffers();
  858. }
  859. }
  860. /* This routine gets called during initialization if things go wrong,
  861.  * and is used in mcd_exit as well. */
  862. static void cleanup(int level)
  863. {
  864. switch (level) {
  865. case 3:
  866. if (unregister_cdrom(&mcd_info)) {
  867. printk(KERN_WARNING "Can't unregister cdrom mcdn");
  868. return;
  869. }
  870. free_irq(mcd_irq, NULL);
  871. case 2:
  872. release_region(mcd_port, 4);
  873. case 1:
  874. if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {
  875. printk(KERN_WARNING "Can't unregister major mcdn");
  876. return;
  877. }
  878. blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
  879. default:;
  880. }
  881. }
  882. /*
  883.  * Test for presence of drive and initialize it.  Called at boot time.
  884.  */
  885. int __init mcd_init(void)
  886. {
  887. int count;
  888. unsigned char result[3];
  889. char msg[80];
  890. if (mcd_port <= 0 || mcd_irq <= 0) {
  891. printk(KERN_INFO "mcd: not probing.n");
  892. return -EIO;
  893. }
  894. if (devfs_register_blkdev(MAJOR_NR, "mcd", &mcd_bdops) != 0) {
  895. printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROMn", MAJOR_NR);
  896. return -EIO;
  897. }
  898. if (check_region(mcd_port, 4)) {
  899. cleanup(1);
  900. printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in usen", mcd_port);
  901. return -EIO;
  902. }
  903. blksize_size[MAJOR_NR] = mcd_blocksizes;
  904. blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
  905. read_ahead[MAJOR_NR] = 4;
  906. /* check for card */
  907. outb(0, MCDPORT(1)); /* send reset */
  908. for (count = 0; count < 2000000; count++)
  909. (void) inb(MCDPORT(1)); /* delay a bit */
  910. outb(0x40, MCDPORT(0)); /* send get-stat cmd */
  911. for (count = 0; count < 2000000; count++)
  912. if (!(inb(MCDPORT(1)) & MFL_STATUS))
  913. break;
  914. if (count >= 2000000) {
  915. printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %dn",
  916.        mcd_port, mcd_irq);
  917. cleanup(1);
  918. return -EIO;
  919. }
  920. count = inb(MCDPORT(0)); /* pick up the status */
  921. outb(MCMD_GET_VERSION, MCDPORT(0));
  922. for (count = 0; count < 3; count++)
  923. if (getValue(result + count)) {
  924. printk(KERN_ERR "mcd: mitsumi get version failed at 0x%xn",
  925.        mcd_port);
  926. cleanup(1);
  927. return -EIO;
  928. }
  929. if (result[0] == result[1] && result[1] == result[2]) {
  930. cleanup(1);
  931. return -EIO;
  932. }
  933. mcdVersion = result[2];
  934. if (mcdVersion >= 4)
  935. outb(4, MCDPORT(2)); /* magic happens */
  936. /* don't get the IRQ until we know for sure the drive is there */
  937. if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
  938. printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROMn", mcd_irq);
  939. cleanup(1);
  940. return -EIO;
  941. }
  942. if (result[1] == 'D') {
  943. MCMD_DATA_READ = MCMD_2X_READ;
  944. /* Added flag to drop to 1x speed if too many errors */
  945. mcdDouble = 1;
  946. } else
  947. mcd_info.speed = 1;
  948. sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
  949. " irq=%dn", mcd_info.speed == 1 ? "Single" : "Double",
  950. mcd_port, mcd_irq);
  951. request_region(mcd_port, 4, "mcd");
  952. outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
  953. outb(0x02, MCDPORT(0));
  954. outb(0x00, MCDPORT(0));
  955. getValue(result);
  956. outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
  957. outb(0x10, MCDPORT(0));
  958. outb(0x04, MCDPORT(0));
  959. getValue(result);
  960. mcd_invalidate_buffers();
  961. mcdPresent = 1;
  962. mcd_info.dev = MKDEV(MAJOR_NR, 0);
  963. if (register_cdrom(&mcd_info) != 0) {
  964. printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.n");
  965. cleanup(3);
  966. return -EIO;
  967. }
  968. devfs_plain_cdrom(&mcd_info, &mcd_bdops);
  969. printk(msg);
  970. return 0;
  971. }
  972. static void hsg2msf(long hsg, struct msf *msf)
  973. {
  974. hsg += 150;
  975. msf->min = hsg / 4500;
  976. hsg %= 4500;
  977. msf->sec = hsg / 75;
  978. msf->frame = hsg % 75;
  979. bin2bcd(&msf->min); /* convert to BCD */
  980. bin2bcd(&msf->sec);
  981. bin2bcd(&msf->frame);
  982. }
  983. static void bin2bcd(unsigned char *p)
  984. {
  985. int u, t;
  986. u = *p % 10;
  987. t = *p / 10;
  988. *p = u | (t << 4);
  989. }
  990. static int bcd2bin(unsigned char bcd)
  991. {
  992. return (bcd >> 4) * 10 + (bcd & 0xF);
  993. }
  994. /*
  995.  * See if a status is ready from the drive and return it
  996.  * if it is ready.
  997.  */
  998. static int mcdStatus(void)
  999. {
  1000. int i;
  1001. int st;
  1002. st = inb(MCDPORT(1)) & MFL_STATUS;
  1003. if (!st) {
  1004. i = inb(MCDPORT(0)) & 0xFF;
  1005. return i;
  1006. } else
  1007. return -1;
  1008. }
  1009. /*
  1010.  * Send a play or read command to the drive
  1011.  */
  1012. static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
  1013. {
  1014. outb(cmd, MCDPORT(0));
  1015. outb(params->start.min, MCDPORT(0));
  1016. outb(params->start.sec, MCDPORT(0));
  1017. outb(params->start.frame, MCDPORT(0));
  1018. outb(params->end.min, MCDPORT(0));
  1019. outb(params->end.sec, MCDPORT(0));
  1020. outb(params->end.frame, MCDPORT(0));
  1021. }
  1022. /*
  1023.  * Timer interrupt routine to test for status ready from the drive.
  1024.  * (see the next routine)
  1025.  */
  1026. static void mcdStatTimer(unsigned long dummy)
  1027. {
  1028. if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
  1029. wake_up(&mcd_waitq);
  1030. return;
  1031. }
  1032. McdTimeout--;
  1033. if (McdTimeout <= 0) {
  1034. wake_up(&mcd_waitq);
  1035. return;
  1036. }
  1037. mcd_timer.function = mcdStatTimer;
  1038. mod_timer(&mcd_timer, jiffies + 1);
  1039. }
  1040. /*
  1041.  * Wait for a status to be returned from the drive.  The actual test
  1042.  * (see routine above) is done by the timer interrupt to avoid
  1043.  * excessive rescheduling.
  1044.  */
  1045. static int getMcdStatus(int timeout)
  1046. {
  1047. int st;
  1048. McdTimeout = timeout;
  1049. mcd_timer.function = mcdStatTimer;
  1050. mod_timer(&mcd_timer, jiffies + 1);
  1051. sleep_on(&mcd_waitq);
  1052. if (McdTimeout <= 0)
  1053. return -1;
  1054. st = inb(MCDPORT(0)) & 0xFF;
  1055. if (st == 0xFF)
  1056. return -1;
  1057. if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
  1058. /* XXX might be an error? look at q-channel? */
  1059. audioStatus = CDROM_AUDIO_COMPLETED;
  1060. if (st & MST_DSK_CHG) {
  1061. mcdDiskChanged = 1;
  1062. tocUpToDate = 0;
  1063. audioStatus = CDROM_AUDIO_NO_STATUS;
  1064. }
  1065. return st;
  1066. }
  1067. /* gives current state of the drive This function is quite unreliable, 
  1068.    and should probably be rewritten by someone, eventually... */
  1069. int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
  1070. {
  1071. int st;
  1072. st = statusCmd(); /* check drive status */
  1073. if (st == -1)
  1074. return -EIO; /* drive doesn't respond */
  1075. if ((st & MST_READY))
  1076. return CDS_DISC_OK;
  1077. if ((st & MST_DOOR_OPEN))
  1078. return CDS_TRAY_OPEN;
  1079. if ((st & MST_DSK_CHG))
  1080. return CDS_NO_DISC;
  1081. if ((st & MST_BUSY))
  1082. return CDS_DRIVE_NOT_READY;
  1083. return -EIO;
  1084. }
  1085. /*
  1086.  * Read a value from the drive.
  1087.  */
  1088. static int getValue(unsigned char *result)
  1089. {
  1090. int count;
  1091. int s;
  1092. for (count = 0; count < 2000; count++)
  1093. if (!(inb(MCDPORT(1)) & MFL_STATUS))
  1094. break;
  1095. if (count >= 2000) {
  1096. printk("mcd: getValue timeoutn");
  1097. return -1;
  1098. }
  1099. s = inb(MCDPORT(0)) & 0xFF;
  1100. *result = (unsigned char) s;
  1101. return 0;
  1102. }
  1103. /*
  1104.  * Read the current Q-channel info.  Also used for reading the
  1105.  * table of contents.
  1106.  */
  1107. int GetQChannelInfo(struct mcd_Toc *qp)
  1108. {
  1109. unsigned char notUsed;
  1110. int retry;
  1111. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  1112. outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
  1113. if (getMcdStatus(MCD_STATUS_DELAY) != -1)
  1114. break;
  1115. }
  1116. if (retry >= MCD_RETRY_ATTEMPTS)
  1117. return -1;
  1118. if (getValue(&qp->ctrl_addr) < 0)
  1119. return -1;
  1120. if (getValue(&qp->track) < 0)
  1121. return -1;
  1122. if (getValue(&qp->pointIndex) < 0)
  1123. return -1;
  1124. if (getValue(&qp->trackTime.min) < 0)
  1125. return -1;
  1126. if (getValue(&qp->trackTime.sec) < 0)
  1127. return -1;
  1128. if (getValue(&qp->trackTime.frame) < 0)
  1129. return -1;
  1130. if (getValue(&notUsed) < 0)
  1131. return -1;
  1132. if (getValue(&qp->diskTime.min) < 0)
  1133. return -1;
  1134. if (getValue(&qp->diskTime.sec) < 0)
  1135. return -1;
  1136. if (getValue(&qp->diskTime.frame) < 0)
  1137. return -1;
  1138. return 0;
  1139. }
  1140. /*
  1141.  * Read the table of contents (TOC) and TOC header if necessary
  1142.  */
  1143. static int updateToc(void)
  1144. {
  1145. if (tocUpToDate)
  1146. return 0;
  1147. if (GetDiskInfo() < 0)
  1148. return -EIO;
  1149. if (GetToc() < 0)
  1150. return -EIO;
  1151. tocUpToDate = 1;
  1152. return 0;
  1153. }
  1154. /*
  1155.  * Read the table of contents header
  1156.  */
  1157. static int GetDiskInfo(void)
  1158. {
  1159. int retry;
  1160. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  1161. outb(MCMD_GET_DISK_INFO, MCDPORT(0));
  1162. if (getMcdStatus(MCD_STATUS_DELAY) != -1)
  1163. break;
  1164. }
  1165. if (retry >= MCD_RETRY_ATTEMPTS)
  1166. return -1;
  1167. if (getValue(&DiskInfo.first) < 0)
  1168. return -1;
  1169. if (getValue(&DiskInfo.last) < 0)
  1170. return -1;
  1171. DiskInfo.first = bcd2bin(DiskInfo.first);
  1172. DiskInfo.last = bcd2bin(DiskInfo.last);
  1173. #ifdef MCD_DEBUG
  1174. printk
  1175.     ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02xn",
  1176.      DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
  1177.      DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
  1178.      DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
  1179.      DiskInfo.firstTrack.frame);
  1180. #endif
  1181. if (getValue(&DiskInfo.diskLength.min) < 0)
  1182. return -1;
  1183. if (getValue(&DiskInfo.diskLength.sec) < 0)
  1184. return -1;
  1185. if (getValue(&DiskInfo.diskLength.frame) < 0)
  1186. return -1;
  1187. if (getValue(&DiskInfo.firstTrack.min) < 0)
  1188. return -1;
  1189. if (getValue(&DiskInfo.firstTrack.sec) < 0)
  1190. return -1;
  1191. if (getValue(&DiskInfo.firstTrack.frame) < 0)
  1192. return -1;
  1193. return 0;
  1194. }
  1195. /*
  1196.  * Read the table of contents (TOC)
  1197.  */
  1198. static int GetToc(void)
  1199. {
  1200. int i, px;
  1201. int limit;
  1202. int retry;
  1203. struct mcd_Toc qInfo;
  1204. for (i = 0; i < MAX_TRACKS; i++)
  1205. Toc[i].pointIndex = 0;
  1206. i = DiskInfo.last + 3;
  1207. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  1208. outb(MCMD_STOP, MCDPORT(0));
  1209. if (getMcdStatus(MCD_STATUS_DELAY) != -1)
  1210. break;
  1211. }
  1212. if (retry >= MCD_RETRY_ATTEMPTS)
  1213. return -1;
  1214. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  1215. outb(MCMD_SET_MODE, MCDPORT(0));
  1216. outb(0x05, MCDPORT(0)); /* mode: toc */
  1217. mcd_mode = 0x05;
  1218. if (getMcdStatus(MCD_STATUS_DELAY) != -1)
  1219. break;
  1220. }
  1221. if (retry >= MCD_RETRY_ATTEMPTS)
  1222. return -1;
  1223. for (limit = 300; limit > 0; limit--) {
  1224. if (GetQChannelInfo(&qInfo) < 0)
  1225. break;
  1226. px = bcd2bin(qInfo.pointIndex);
  1227. if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
  1228. if (Toc[px].pointIndex == 0) {
  1229. Toc[px] = qInfo;
  1230. i--;
  1231. }
  1232. if (i <= 0)
  1233. break;
  1234. }
  1235. Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
  1236. for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
  1237. outb(MCMD_SET_MODE, MCDPORT(0));
  1238. outb(0x01, MCDPORT(0));
  1239. mcd_mode = 1;
  1240. if (getMcdStatus(MCD_STATUS_DELAY) != -1)
  1241. break;
  1242. }
  1243. #ifdef MCD_DEBUG
  1244. for (i = 1; i <= DiskInfo.last; i++)
  1245. printk
  1246.     ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02Xn",
  1247.      i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
  1248.      Toc[i].trackTime.min, Toc[i].trackTime.sec,
  1249.      Toc[i].trackTime.frame, Toc[i].diskTime.min,
  1250.      Toc[i].diskTime.sec, Toc[i].diskTime.frame);
  1251. for (i = 100; i < 103; i++)
  1252. printk
  1253.     ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02Xn",
  1254.      i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
  1255.      Toc[i].trackTime.min, Toc[i].trackTime.sec,
  1256.      Toc[i].trackTime.frame, Toc[i].diskTime.min,
  1257.      Toc[i].diskTime.sec, Toc[i].diskTime.frame);
  1258. #endif
  1259. return limit > 0 ? 0 : -1;
  1260. }
  1261. void __exit mcd_exit(void)
  1262. {
  1263. cleanup(3);
  1264. del_timer_sync(&mcd_timer);
  1265. }
  1266. #ifdef MODULE
  1267. module_init(mcd_init);
  1268. #endif
  1269. module_exit(mcd_exit);
  1270. MODULE_AUTHOR("Martin Harriss");
  1271. MODULE_LICENSE("GPL");