home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / alt / sources / 2524 / hardware.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-15  |  11.5 KB  |  587 lines

  1. /*
  2.  * @(#)hardware.c    1.2    11/14/92
  3.  *
  4.  * Get information about a CD.
  5.  */
  6. #define RCFILE "/.workmanrc"
  7. #define DBFILE "/.workmandb"
  8. static char *ident = "@(#)hardware.c    1.2 11/14/92";
  9.  
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <sys/param.h>
  15. #include <sys/stat.h>
  16. #include <ustat.h>
  17. #ifdef solbourne
  18. #include <mfg/dklabel.h>
  19. #include <mfg/dkio.h>
  20. #include <dev/srvar.h>
  21. #else /* solbourne */
  22. #ifdef SYSV
  23. #include <sys/cdio.h>
  24. #else /* SYSV */
  25. #include <sundev/srreg.h>
  26. #endif /* SYSV */
  27. #endif /* solbourne */
  28. #include "struct.h"
  29.  
  30. void *malloc(), *realloc(), print_cdinfo(), wipe_cdinfo();
  31. char *strchr(), *getenv();
  32.  
  33. extern struct play *playlist;
  34. extern struct cdinfo thiscd, *cd;
  35.  
  36. int    cd_fd = -1;
  37. #ifdef SYSV
  38. char    *cd_device = "/dev/rdsk/c0t6d0s2";
  39. #else
  40. char    *cd_device = "/dev/rsr0\0";
  41. #endif
  42.  
  43. extern int cur_track, cur_index, cur_lasttrack, cur_firsttrack, cur_pos_abs,    
  44.     cur_frame, cur_pos_rel, cur_tracklen, cur_cdlen, cur_ntracks,    
  45.     cur_nsections, cur_cdmode, cur_listno, cur_stopmode, exit_on_eject;
  46. extern char *cur_artist, *cur_cdname, *cur_trackname;
  47. extern char    cur_contd, cur_avoid;
  48.  
  49. /*
  50.  * read_toc()
  51.  *
  52.  * Read the table of contents from the CD.  Return a pointer to a cdinfo
  53.  * struct containing the relevant information (minus artist/cdname/etc.)
  54.  * This is a static struct.  Returns NULL if there was an error.
  55.  *
  56.  * XXX allocates one trackinfo too many.
  57.  */
  58. struct cdinfo *
  59. read_toc()
  60. {
  61.     struct playlist        *l;
  62.     struct cdrom_tochdr    hdr;
  63.     struct cdrom_tocentry    entry;
  64.     int            i, pos;
  65.  
  66.     if (cd_fd < 0)
  67.         return(NULL);
  68.  
  69.     if (ioctl(cd_fd, CDROMREADTOCHDR, &hdr))
  70.     {
  71.         perror("readtochdr");
  72.         return (NULL);
  73.     }
  74.  
  75.     thiscd.artist[0] = thiscd.cdname[0] = '\0';
  76.     thiscd.whichdb = thiscd.otherrc = thiscd.otherdb = NULL;
  77.     thiscd.length = 0;
  78.     thiscd.autoplay = thiscd.playmode = thiscd.volume = 0;
  79.     thiscd.ntracks = hdr.cdth_trk1;
  80.  
  81.     if (thiscd.lists != NULL)
  82.     {
  83.         for (l = thiscd.lists; l->name != NULL; l++)
  84.         {
  85.             free(l->name);
  86.             free(l->list);
  87.         }
  88.         free(thiscd.lists);
  89.         thiscd.lists = NULL;
  90.     }
  91.  
  92.     if (thiscd.trk != NULL)
  93.         free(thiscd.trk);
  94.  
  95.     thiscd.trk = malloc((thiscd.ntracks + 1) * sizeof(struct trackinfo));
  96.     if (thiscd.trk == NULL)
  97.     {
  98.         perror("malloc");
  99.         return (NULL);
  100.     }
  101.  
  102.     for (i = 0; i <= thiscd.ntracks; i++)
  103.     {
  104.         if (i == thiscd.ntracks)
  105.             entry.cdte_track = CDROM_LEADOUT;
  106.         else
  107.             entry.cdte_track = i + 1;
  108.         entry.cdte_format = CDROM_MSF;
  109.         if (ioctl(cd_fd, CDROMREADTOCENTRY, &entry))
  110.         {
  111.             perror("tocentry read");
  112.             return (NULL);
  113.         }
  114.  
  115.         thiscd.trk[i].data =
  116.         thiscd.trk[i].avoid = entry.cdte_ctrl & CDROM_DATA_TRACK ?
  117.             1 : 0;
  118.         thiscd.trk[i].length = entry.cdte_addr.msf.minute * 60 +
  119.                 entry.cdte_addr.msf.second;
  120.         thiscd.trk[i].start = thiscd.trk[i].length * 75 +
  121.                 entry.cdte_addr.msf.frame;
  122.         thiscd.trk[i].songname = thiscd.trk[i].otherrc =
  123.         thiscd.trk[i].otherdb = NULL;
  124.         thiscd.trk[i].contd = 0;
  125.         thiscd.trk[i].volume = 0;
  126.         thiscd.trk[i].track = i + 1;
  127.         thiscd.trk[i].section = 0;
  128.     }
  129.  
  130. /* Now compute actual track lengths. */
  131.     pos = thiscd.trk[0].length;
  132.  
  133.     for (i = 0; i < thiscd.ntracks; i++)
  134.     {
  135.         thiscd.trk[i].length = thiscd.trk[i+1].length - pos;
  136.         pos = thiscd.trk[i+1].length;
  137.         if (thiscd.trk[i].data)
  138.             thiscd.trk[i].length = (thiscd.trk[i + 1].start -
  139.                 thiscd.trk[i].start) * 2;
  140.         if (thiscd.trk[i].avoid)
  141.             strmcpy(&thiscd.trk[i].songname, "DATA TRACK");
  142.     }
  143.  
  144.     thiscd.length = thiscd.trk[thiscd.ntracks].length;
  145.  
  146.     return (&thiscd);
  147. }
  148.  
  149. /*
  150.  * cd_status()
  151.  *
  152.  * Return values:
  153.  *
  154.  *    0    No CD in drive.
  155.  *    1    CD in drive.
  156.  *    2    CD has just been inserted (TOC has been read)
  157.  *    3    CD has just been removed
  158.  *
  159.  * Updates cur_track, cur_pos_rel, cur_pos_abs and other variables.
  160.  */
  161. int
  162. cd_status()
  163. {
  164.     char realname[MAXPATHLEN];
  165.     static int warned = 0;
  166.     struct cdrom_subchnl    sc;
  167.     int            i, ret = 1;
  168.  
  169.     if (cd_fd < 0)
  170.     {
  171.         if ((cd_fd = open(cd_device, 0)) < 0)
  172.         {
  173.  
  174.             if (errno == EACCES)
  175.             {
  176.                 if (!warned)
  177.                 {
  178.                     if (realpath(cd_device, realname) ==
  179.                         NULL)
  180.                     {
  181.                         perror("realpath");
  182.                         return (0);
  183.                     }
  184.  
  185.                     fprintf(stderr,
  186.         "As root, please run\n\nchmod 666 %s\n\n%s\n", realname,
  187.         "to give yourself permission to access the CD-ROM device.");
  188.                     warned++;
  189.                 }
  190.             }
  191.             else if (errno != ENXIO)
  192.             {
  193.                 perror(cd_device);
  194.                 exit(1);
  195.             }
  196.  
  197.             return (0);
  198.         }
  199.         cur_cdmode = 5;
  200.     }
  201.  
  202.     if (warned)
  203.     {
  204.         warned = 0;
  205.         fprintf(stderr, "Thank you.\n");
  206.     }
  207.  
  208.     sc.cdsc_format = CDROM_MSF;
  209.  
  210.     if (ioctl(cd_fd, CDROMSUBCHNL, &sc))
  211.     {
  212.         cur_cdmode = 5;
  213.  
  214.         if (exit_on_eject)
  215.             exit(0);
  216.  
  217.         return (0);
  218.     }
  219.  
  220.     if (cur_cdmode == 5)    /* CD has been ejected */
  221.     {
  222.         cur_pos_rel = cur_pos_abs = cur_frame = 0;
  223.  
  224.         if ((cd = read_toc()) == NULL)
  225.         {
  226.             close(cd_fd);
  227.             cd_fd = -1;
  228.             if (exit_on_eject)
  229.                 exit(0);
  230.             else
  231.                 return (0);
  232.         }
  233.         cur_nsections = 0;
  234.         cur_ntracks = cd->ntracks;
  235.         cur_cdlen = cd->length;
  236.         load();
  237.         cur_artist = cd->artist;
  238.         cur_cdname = cd->cdname;
  239.         cur_cdmode = 4;
  240.         ret = 2;
  241.     }
  242.  
  243.     switch (sc.cdsc_audiostatus) {
  244.     case CDROM_AUDIO_PLAY:
  245.         cur_cdmode = 1;
  246.         cur_pos_abs = sc.cdsc_absaddr.msf.minute * 60 +
  247.             sc.cdsc_absaddr.msf.second;
  248.         cur_frame = cur_pos_abs * 75 + sc.cdsc_absaddr.msf.frame;
  249.  
  250.         /* Only look up the current track number if necessary. */
  251.         if (cur_track < 1 || cur_frame < cd->trk[cur_track-1].start ||
  252.                 cur_frame >= (cur_track >= cur_ntracks ?
  253.                 (cur_cdlen + 1) * 75 :
  254.                 cd->trk[cur_track].start))
  255.         {
  256.             cur_track = 0;
  257.             while (cur_track < cur_ntracks && cur_frame >=
  258.                     cd->trk[cur_track].start)
  259.                 cur_track++;
  260.         }
  261.         if (cur_track >= 1 && sc.cdsc_trk > cd->trk[cur_track-1].track)
  262.             cur_track++;
  263.  
  264.         cur_index = sc.cdsc_ind;
  265. doall:
  266.         if (cur_track >= 1 && cur_track <= cur_ntracks)
  267.         {
  268.             cur_trackname = cd->trk[cur_track-1].songname;
  269.             cur_avoid = cd->trk[cur_track-1].avoid;
  270.             cur_contd = cd->trk[cur_track-1].contd;
  271.             cur_pos_rel = (cur_frame -
  272.                 cd->trk[cur_track-1].start) / 75;
  273.             if (cur_pos_rel < 0)
  274.                 cur_pos_rel = -cur_pos_rel;
  275.         }
  276.  
  277.         if (playlist != NULL && playlist[0].start)
  278.         {
  279.             cur_pos_abs -= cd->trk[playlist[cur_listno-1].
  280.                 start - 1].start / 75;
  281.             cur_pos_abs += playlist[cur_listno-1].starttime;
  282.         }
  283.         if (cur_pos_abs < 0)
  284.             cur_pos_abs = cur_frame = 0;
  285.  
  286.         if (cur_track < 1)
  287.             cur_tracklen = cd->length;
  288.         else
  289.             cur_tracklen = cd->trk[cur_track-1].length;
  290.         break;
  291.  
  292.     case CDROM_AUDIO_PAUSED:
  293.         if (cur_cdmode == 1 || cur_cdmode == 3)
  294.         {
  295.             cur_cdmode = 3;
  296.             cur_track = sc.cdsc_trk;
  297.         }
  298.         else
  299.             cur_cdmode = 4;
  300.         goto doall;
  301.  
  302.     case CDROM_AUDIO_COMPLETED:
  303.         cur_cdmode = 0;        /* waiting for next track. */
  304.         break;
  305.  
  306.     case CDROM_AUDIO_NO_STATUS:
  307.         cur_cdmode = 4;
  308.         cur_lasttrack = cur_firsttrack = -1;
  309.         goto doall;
  310.     }
  311.  
  312.     return (ret);
  313. }
  314.  
  315. /*
  316.  * cd_volume(left, right)
  317.  *
  318.  * Set the volume levels.
  319.  */
  320. void
  321. cd_volume(left, right)
  322.     int    left, right;
  323. {
  324.     struct cdrom_volctrl v;
  325.  
  326.     v.channel0 = left < 0 ? 0 : left > 255 ? 255 : left;
  327.     v.channel1 = right < 0 ? 0 : right > 255 ? 255 : right;
  328.     if (cd_fd >= 0)
  329.         (void) ioctl(cd_fd, CDROMVOLCTRL, &v);
  330. }
  331.  
  332. /*
  333.  * pause_cd()
  334.  *
  335.  * Pause the CD, if it's in play mode.  If it's already paused, go back to
  336.  * play mode.
  337.  */
  338. void
  339. pause_cd()
  340. {
  341.     if (cd_fd < 0)    /* do nothing if there's no CD! */
  342.         return;
  343.  
  344.     switch (cur_cdmode) {
  345.     case 1:        /* playing */
  346.         cur_cdmode = 3;
  347.         ioctl(cd_fd, CDROMPAUSE);
  348.         break;
  349.     case 3:        /* paused */
  350.         cur_cdmode = 1;
  351.         ioctl(cd_fd, CDROMRESUME);
  352.     }
  353. }
  354.  
  355. /*
  356.  * stop_cd()
  357.  *
  358.  * Stop the CD if it's not already stopped.
  359.  */
  360. void
  361. stop_cd()
  362. {
  363.     if (cd_fd < 0)
  364.         return;
  365.  
  366.     if (cur_cdmode != 4)
  367.     {
  368.         cur_lasttrack = cur_firsttrack = -1;
  369.         cur_cdmode = 4;
  370.         ioctl(cd_fd, CDROMSTOP);
  371.         cur_track = 1;
  372.     }
  373. }
  374.  
  375. /*
  376.  * play_chunk(start, end)
  377.  *
  378.  * Play the CD from one position to another (both in frames.)
  379.  */
  380. void
  381. play_chunk(start, end)
  382.     int start, end;
  383. {
  384.     struct cdrom_msf msf;
  385.  
  386.     if (cd == NULL || cd_fd < 0)
  387.         return;
  388.  
  389.     end--;
  390.     msf.cdmsf_min0 = start / (60*75);
  391.     msf.cdmsf_sec0 = (start % (60*75)) / 75;
  392.     msf.cdmsf_frame0 = start % 75;
  393.     msf.cdmsf_min1 = end / (60*75);
  394.     msf.cdmsf_sec1 = (end % (60*75)) / 75;
  395.     msf.cdmsf_frame1 = end % 75;
  396.  
  397.     if (ioctl(cd_fd, CDROMSTART))
  398.     {
  399.         perror("CDROMSTART");
  400.         return;
  401.     }
  402.     if (ioctl(cd_fd, CDROMPLAYMSF, &msf))
  403.     {
  404.         printf("play(%d,%d)\n",start,end);
  405.         printf("msf = %d:%d:%d %d:%d:%d\n",
  406.             msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
  407.             msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
  408.         perror("CDROMPLAYMSF");
  409.         return;
  410.     }
  411. }
  412.  
  413. /*
  414.  * play_cd(starttrack, pos, endtrack)
  415.  *
  416.  * Start playing the CD or jump to a new position.  "pos" is in seconds,
  417.  * relative to start of track.
  418.  */
  419. void
  420. play_cd(start, pos, end)
  421. int start, pos, end;
  422. {
  423.     if (cd == NULL || cd_fd < 0)
  424.         return;
  425.  
  426.     cur_firsttrack = start;
  427.     start--;
  428.     end--;
  429.     cur_lasttrack = end;
  430.  
  431.     play_chunk(cd->trk[start].start + pos * 75, end >= cur_ntracks ?
  432.         (cur_cdlen - 1) * 75 : cd->trk[end].start - 1);
  433. }
  434.  
  435. /*
  436.  * Set the offset into the current track and play.  -1 means end of track
  437.  * (i.e., go to next track.)
  438.  */
  439. void
  440. play_from_pos(pos)
  441.     int    pos;
  442. {
  443.     if (pos == -1)
  444.         if (cd)
  445.             pos = cd->trk[cur_track - 1].length - 1;
  446.     if (cur_cdmode == 1)
  447.         play_cd(cur_track, pos, playlist[cur_listno-1].end);
  448. }
  449.  
  450. /*
  451.  * Eject the current CD, if there is one, and set the mode to 5.
  452.  *
  453.  * Returns 0 on success, 1 if the CD couldn't be ejected, or 2 if the
  454.  * CD contains a mounted filesystem.
  455.  */
  456. eject_cd()
  457. {
  458.     struct stat    stbuf;
  459.     struct ustat    ust;
  460.  
  461.     if (cur_cdmode == 5)        /* Already ejected! */
  462.         return (0);
  463.  
  464.     if (fstat(cd_fd, &stbuf) != 0)
  465.     {
  466.         perror("fstat");
  467.         return (1);
  468.     }
  469.  
  470.     /* Is this a mounted filesystem? */
  471.     if (ustat(stbuf.st_rdev, &ust) == 0)
  472.         return (2);
  473.  
  474.     if (ioctl(cd_fd, CDROMEJECT))
  475.     {
  476.         perror("CDEJECT");
  477.         return (1);
  478.     }
  479.  
  480.     if (exit_on_eject)
  481.         exit(0);
  482.  
  483.     cur_cdlen = cur_tracklen = 1;
  484.     cur_pos_abs = cur_pos_rel = cur_frame = 0;
  485.     wipe_cdinfo();
  486.     cur_cdmode = 5;
  487.  
  488.     return (0);
  489. }
  490.  
  491. /* Try to keep the CD open all the time.  This is run in a subprocess. */
  492. void
  493. keep_cd_open()
  494. {
  495.     int    fd;
  496.     struct flock    fl;
  497.     extern    end;
  498.  
  499.     for (fd = 0; fd < 256; fd++)
  500.         close(fd);
  501.  
  502.     if (fork())
  503.         exit(0);
  504.  
  505.     if ((fd = open("/tmp/cd.lock", O_RDWR | O_CREAT, 0666)) < 0)
  506.         exit(0);
  507.     fl.l_type = F_WRLCK;
  508.     fl.l_whence = 0;
  509.     fl.l_start = 0;
  510.     fl.l_len = 0;
  511.     if (fcntl(fd, F_SETLK, &fl) < 0)
  512.         exit(0);
  513.  
  514.     if (open(cd_device, 0) >= 0)
  515.     {
  516.         brk(&end);
  517.         pause();
  518.     }
  519.  
  520.     exit(0);
  521. }
  522.  
  523. /*
  524.  * find_trkind(track, index)
  525.  *
  526.  * Start playing at a particular track and index, optionally using a particular
  527.  * frame as a starting position.  Returns a frame number near the start of the
  528.  * index mark if successful, 0 if the track/index didn't exist.
  529.  *
  530.  * This is made significantly more tedious (though probably easier to port)
  531.  * by the fact that CDROMPLAYTRKIND doesn't work as advertised.  The routine
  532.  * does a binary search of the track, terminating when the interval gets to
  533.  * around 10 frames or when the next track is encountered, at which point
  534.  * it's a fair bet the index in question doesn't exist.
  535.  */
  536. find_trkind(track, index, start)
  537.     int    track, index, start;
  538. {
  539.     int    top = 0, bottom, current, interval, ret = 0, i;
  540.  
  541.     if (cd == NULL || cd_fd < 0)
  542.         return;
  543.  
  544.     for (i = 0; i < cur_ntracks; i++)
  545.         if (cd->trk[i].track == track)
  546.             break;
  547.     bottom = cd->trk[i].start;
  548.  
  549.     for (; i < cur_ntracks; i++)
  550.         if (cd->trk[i].track > track)
  551.             break;
  552.  
  553.     top = i == cur_ntracks ? (cd->length - 1) * 75 : cd->trk[i].start;
  554.  
  555.     if (start > bottom && start < top)
  556.         bottom = start;
  557.  
  558.     current = (top + bottom) / 2;
  559.     interval = (top - bottom) / 4;
  560.  
  561.     do {
  562.         play_chunk(current, current + 75);
  563.  
  564.         if (cd_status() != 1)
  565.             return (0);
  566.         while (cur_frame < current)
  567.             if (cd_status() != 1 || cur_cdmode != 1)
  568.                 return (0);
  569.             else
  570.                 usleep(1);
  571.  
  572.         if (cd->trk[cur_track - 1].track > track)
  573.             break;
  574.  
  575.         if (cur_index >= index)
  576.         {
  577.             ret = current;
  578.             current -= interval;
  579.         }
  580.         else
  581.             current += interval;
  582.         interval /= 2;
  583.     } while (interval > 2);
  584.  
  585.     return (ret);
  586. }
  587.