home *** CD-ROM | disk | FTP | other *** search
- /*
- * @(#)hardware.c 1.2 11/14/92
- *
- * Get information about a CD.
- */
- #define RCFILE "/.workmanrc"
- #define DBFILE "/.workmandb"
- static char *ident = "@(#)hardware.c 1.2 11/14/92";
-
- #include <errno.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <ustat.h>
- #ifdef solbourne
- #include <mfg/dklabel.h>
- #include <mfg/dkio.h>
- #include <dev/srvar.h>
- #else /* solbourne */
- #ifdef SYSV
- #include <sys/cdio.h>
- #else /* SYSV */
- #include <sundev/srreg.h>
- #endif /* SYSV */
- #endif /* solbourne */
- #include "struct.h"
-
- void *malloc(), *realloc(), print_cdinfo(), wipe_cdinfo();
- char *strchr(), *getenv();
-
- extern struct play *playlist;
- extern struct cdinfo thiscd, *cd;
-
- int cd_fd = -1;
- #ifdef SYSV
- char *cd_device = "/dev/rdsk/c0t6d0s2";
- #else
- char *cd_device = "/dev/rsr0\0";
- #endif
-
- extern int cur_track, cur_index, cur_lasttrack, cur_firsttrack, cur_pos_abs,
- cur_frame, cur_pos_rel, cur_tracklen, cur_cdlen, cur_ntracks,
- cur_nsections, cur_cdmode, cur_listno, cur_stopmode, exit_on_eject;
- extern char *cur_artist, *cur_cdname, *cur_trackname;
- extern char cur_contd, cur_avoid;
-
- /*
- * read_toc()
- *
- * Read the table of contents from the CD. Return a pointer to a cdinfo
- * struct containing the relevant information (minus artist/cdname/etc.)
- * This is a static struct. Returns NULL if there was an error.
- *
- * XXX allocates one trackinfo too many.
- */
- struct cdinfo *
- read_toc()
- {
- struct playlist *l;
- struct cdrom_tochdr hdr;
- struct cdrom_tocentry entry;
- int i, pos;
-
- if (cd_fd < 0)
- return(NULL);
-
- if (ioctl(cd_fd, CDROMREADTOCHDR, &hdr))
- {
- perror("readtochdr");
- return (NULL);
- }
-
- thiscd.artist[0] = thiscd.cdname[0] = '\0';
- thiscd.whichdb = thiscd.otherrc = thiscd.otherdb = NULL;
- thiscd.length = 0;
- thiscd.autoplay = thiscd.playmode = thiscd.volume = 0;
- thiscd.ntracks = hdr.cdth_trk1;
-
- if (thiscd.lists != NULL)
- {
- for (l = thiscd.lists; l->name != NULL; l++)
- {
- free(l->name);
- free(l->list);
- }
- free(thiscd.lists);
- thiscd.lists = NULL;
- }
-
- if (thiscd.trk != NULL)
- free(thiscd.trk);
-
- thiscd.trk = malloc((thiscd.ntracks + 1) * sizeof(struct trackinfo));
- if (thiscd.trk == NULL)
- {
- perror("malloc");
- return (NULL);
- }
-
- for (i = 0; i <= thiscd.ntracks; i++)
- {
- if (i == thiscd.ntracks)
- entry.cdte_track = CDROM_LEADOUT;
- else
- entry.cdte_track = i + 1;
- entry.cdte_format = CDROM_MSF;
- if (ioctl(cd_fd, CDROMREADTOCENTRY, &entry))
- {
- perror("tocentry read");
- return (NULL);
- }
-
- thiscd.trk[i].data =
- thiscd.trk[i].avoid = entry.cdte_ctrl & CDROM_DATA_TRACK ?
- 1 : 0;
- thiscd.trk[i].length = entry.cdte_addr.msf.minute * 60 +
- entry.cdte_addr.msf.second;
- thiscd.trk[i].start = thiscd.trk[i].length * 75 +
- entry.cdte_addr.msf.frame;
- thiscd.trk[i].songname = thiscd.trk[i].otherrc =
- thiscd.trk[i].otherdb = NULL;
- thiscd.trk[i].contd = 0;
- thiscd.trk[i].volume = 0;
- thiscd.trk[i].track = i + 1;
- thiscd.trk[i].section = 0;
- }
-
- /* Now compute actual track lengths. */
- pos = thiscd.trk[0].length;
-
- for (i = 0; i < thiscd.ntracks; i++)
- {
- thiscd.trk[i].length = thiscd.trk[i+1].length - pos;
- pos = thiscd.trk[i+1].length;
- if (thiscd.trk[i].data)
- thiscd.trk[i].length = (thiscd.trk[i + 1].start -
- thiscd.trk[i].start) * 2;
- if (thiscd.trk[i].avoid)
- strmcpy(&thiscd.trk[i].songname, "DATA TRACK");
- }
-
- thiscd.length = thiscd.trk[thiscd.ntracks].length;
-
- return (&thiscd);
- }
-
- /*
- * cd_status()
- *
- * Return values:
- *
- * 0 No CD in drive.
- * 1 CD in drive.
- * 2 CD has just been inserted (TOC has been read)
- * 3 CD has just been removed
- *
- * Updates cur_track, cur_pos_rel, cur_pos_abs and other variables.
- */
- int
- cd_status()
- {
- char realname[MAXPATHLEN];
- static int warned = 0;
- struct cdrom_subchnl sc;
- int i, ret = 1;
-
- if (cd_fd < 0)
- {
- if ((cd_fd = open(cd_device, 0)) < 0)
- {
-
- if (errno == EACCES)
- {
- if (!warned)
- {
- if (realpath(cd_device, realname) ==
- NULL)
- {
- perror("realpath");
- return (0);
- }
-
- fprintf(stderr,
- "As root, please run\n\nchmod 666 %s\n\n%s\n", realname,
- "to give yourself permission to access the CD-ROM device.");
- warned++;
- }
- }
- else if (errno != ENXIO)
- {
- perror(cd_device);
- exit(1);
- }
-
- return (0);
- }
- cur_cdmode = 5;
- }
-
- if (warned)
- {
- warned = 0;
- fprintf(stderr, "Thank you.\n");
- }
-
- sc.cdsc_format = CDROM_MSF;
-
- if (ioctl(cd_fd, CDROMSUBCHNL, &sc))
- {
- cur_cdmode = 5;
-
- if (exit_on_eject)
- exit(0);
-
- return (0);
- }
-
- if (cur_cdmode == 5) /* CD has been ejected */
- {
- cur_pos_rel = cur_pos_abs = cur_frame = 0;
-
- if ((cd = read_toc()) == NULL)
- {
- close(cd_fd);
- cd_fd = -1;
- if (exit_on_eject)
- exit(0);
- else
- return (0);
- }
- cur_nsections = 0;
- cur_ntracks = cd->ntracks;
- cur_cdlen = cd->length;
- load();
- cur_artist = cd->artist;
- cur_cdname = cd->cdname;
- cur_cdmode = 4;
- ret = 2;
- }
-
- switch (sc.cdsc_audiostatus) {
- case CDROM_AUDIO_PLAY:
- cur_cdmode = 1;
- cur_pos_abs = sc.cdsc_absaddr.msf.minute * 60 +
- sc.cdsc_absaddr.msf.second;
- cur_frame = cur_pos_abs * 75 + sc.cdsc_absaddr.msf.frame;
-
- /* Only look up the current track number if necessary. */
- if (cur_track < 1 || cur_frame < cd->trk[cur_track-1].start ||
- cur_frame >= (cur_track >= cur_ntracks ?
- (cur_cdlen + 1) * 75 :
- cd->trk[cur_track].start))
- {
- cur_track = 0;
- while (cur_track < cur_ntracks && cur_frame >=
- cd->trk[cur_track].start)
- cur_track++;
- }
- if (cur_track >= 1 && sc.cdsc_trk > cd->trk[cur_track-1].track)
- cur_track++;
-
- cur_index = sc.cdsc_ind;
- doall:
- if (cur_track >= 1 && cur_track <= cur_ntracks)
- {
- cur_trackname = cd->trk[cur_track-1].songname;
- cur_avoid = cd->trk[cur_track-1].avoid;
- cur_contd = cd->trk[cur_track-1].contd;
- cur_pos_rel = (cur_frame -
- cd->trk[cur_track-1].start) / 75;
- if (cur_pos_rel < 0)
- cur_pos_rel = -cur_pos_rel;
- }
-
- if (playlist != NULL && playlist[0].start)
- {
- cur_pos_abs -= cd->trk[playlist[cur_listno-1].
- start - 1].start / 75;
- cur_pos_abs += playlist[cur_listno-1].starttime;
- }
- if (cur_pos_abs < 0)
- cur_pos_abs = cur_frame = 0;
-
- if (cur_track < 1)
- cur_tracklen = cd->length;
- else
- cur_tracklen = cd->trk[cur_track-1].length;
- break;
-
- case CDROM_AUDIO_PAUSED:
- if (cur_cdmode == 1 || cur_cdmode == 3)
- {
- cur_cdmode = 3;
- cur_track = sc.cdsc_trk;
- }
- else
- cur_cdmode = 4;
- goto doall;
-
- case CDROM_AUDIO_COMPLETED:
- cur_cdmode = 0; /* waiting for next track. */
- break;
-
- case CDROM_AUDIO_NO_STATUS:
- cur_cdmode = 4;
- cur_lasttrack = cur_firsttrack = -1;
- goto doall;
- }
-
- return (ret);
- }
-
- /*
- * cd_volume(left, right)
- *
- * Set the volume levels.
- */
- void
- cd_volume(left, right)
- int left, right;
- {
- struct cdrom_volctrl v;
-
- v.channel0 = left < 0 ? 0 : left > 255 ? 255 : left;
- v.channel1 = right < 0 ? 0 : right > 255 ? 255 : right;
- if (cd_fd >= 0)
- (void) ioctl(cd_fd, CDROMVOLCTRL, &v);
- }
-
- /*
- * pause_cd()
- *
- * Pause the CD, if it's in play mode. If it's already paused, go back to
- * play mode.
- */
- void
- pause_cd()
- {
- if (cd_fd < 0) /* do nothing if there's no CD! */
- return;
-
- switch (cur_cdmode) {
- case 1: /* playing */
- cur_cdmode = 3;
- ioctl(cd_fd, CDROMPAUSE);
- break;
- case 3: /* paused */
- cur_cdmode = 1;
- ioctl(cd_fd, CDROMRESUME);
- }
- }
-
- /*
- * stop_cd()
- *
- * Stop the CD if it's not already stopped.
- */
- void
- stop_cd()
- {
- if (cd_fd < 0)
- return;
-
- if (cur_cdmode != 4)
- {
- cur_lasttrack = cur_firsttrack = -1;
- cur_cdmode = 4;
- ioctl(cd_fd, CDROMSTOP);
- cur_track = 1;
- }
- }
-
- /*
- * play_chunk(start, end)
- *
- * Play the CD from one position to another (both in frames.)
- */
- void
- play_chunk(start, end)
- int start, end;
- {
- struct cdrom_msf msf;
-
- if (cd == NULL || cd_fd < 0)
- return;
-
- end--;
- msf.cdmsf_min0 = start / (60*75);
- msf.cdmsf_sec0 = (start % (60*75)) / 75;
- msf.cdmsf_frame0 = start % 75;
- msf.cdmsf_min1 = end / (60*75);
- msf.cdmsf_sec1 = (end % (60*75)) / 75;
- msf.cdmsf_frame1 = end % 75;
-
- if (ioctl(cd_fd, CDROMSTART))
- {
- perror("CDROMSTART");
- return;
- }
- if (ioctl(cd_fd, CDROMPLAYMSF, &msf))
- {
- printf("play(%d,%d)\n",start,end);
- printf("msf = %d:%d:%d %d:%d:%d\n",
- msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
- msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
- perror("CDROMPLAYMSF");
- return;
- }
- }
-
- /*
- * play_cd(starttrack, pos, endtrack)
- *
- * Start playing the CD or jump to a new position. "pos" is in seconds,
- * relative to start of track.
- */
- void
- play_cd(start, pos, end)
- int start, pos, end;
- {
- if (cd == NULL || cd_fd < 0)
- return;
-
- cur_firsttrack = start;
- start--;
- end--;
- cur_lasttrack = end;
-
- play_chunk(cd->trk[start].start + pos * 75, end >= cur_ntracks ?
- (cur_cdlen - 1) * 75 : cd->trk[end].start - 1);
- }
-
- /*
- * Set the offset into the current track and play. -1 means end of track
- * (i.e., go to next track.)
- */
- void
- play_from_pos(pos)
- int pos;
- {
- if (pos == -1)
- if (cd)
- pos = cd->trk[cur_track - 1].length - 1;
- if (cur_cdmode == 1)
- play_cd(cur_track, pos, playlist[cur_listno-1].end);
- }
-
- /*
- * Eject the current CD, if there is one, and set the mode to 5.
- *
- * Returns 0 on success, 1 if the CD couldn't be ejected, or 2 if the
- * CD contains a mounted filesystem.
- */
- eject_cd()
- {
- struct stat stbuf;
- struct ustat ust;
-
- if (cur_cdmode == 5) /* Already ejected! */
- return (0);
-
- if (fstat(cd_fd, &stbuf) != 0)
- {
- perror("fstat");
- return (1);
- }
-
- /* Is this a mounted filesystem? */
- if (ustat(stbuf.st_rdev, &ust) == 0)
- return (2);
-
- if (ioctl(cd_fd, CDROMEJECT))
- {
- perror("CDEJECT");
- return (1);
- }
-
- if (exit_on_eject)
- exit(0);
-
- cur_cdlen = cur_tracklen = 1;
- cur_pos_abs = cur_pos_rel = cur_frame = 0;
- wipe_cdinfo();
- cur_cdmode = 5;
-
- return (0);
- }
-
- /* Try to keep the CD open all the time. This is run in a subprocess. */
- void
- keep_cd_open()
- {
- int fd;
- struct flock fl;
- extern end;
-
- for (fd = 0; fd < 256; fd++)
- close(fd);
-
- if (fork())
- exit(0);
-
- if ((fd = open("/tmp/cd.lock", O_RDWR | O_CREAT, 0666)) < 0)
- exit(0);
- fl.l_type = F_WRLCK;
- fl.l_whence = 0;
- fl.l_start = 0;
- fl.l_len = 0;
- if (fcntl(fd, F_SETLK, &fl) < 0)
- exit(0);
-
- if (open(cd_device, 0) >= 0)
- {
- brk(&end);
- pause();
- }
-
- exit(0);
- }
-
- /*
- * find_trkind(track, index)
- *
- * Start playing at a particular track and index, optionally using a particular
- * frame as a starting position. Returns a frame number near the start of the
- * index mark if successful, 0 if the track/index didn't exist.
- *
- * This is made significantly more tedious (though probably easier to port)
- * by the fact that CDROMPLAYTRKIND doesn't work as advertised. The routine
- * does a binary search of the track, terminating when the interval gets to
- * around 10 frames or when the next track is encountered, at which point
- * it's a fair bet the index in question doesn't exist.
- */
- find_trkind(track, index, start)
- int track, index, start;
- {
- int top = 0, bottom, current, interval, ret = 0, i;
-
- if (cd == NULL || cd_fd < 0)
- return;
-
- for (i = 0; i < cur_ntracks; i++)
- if (cd->trk[i].track == track)
- break;
- bottom = cd->trk[i].start;
-
- for (; i < cur_ntracks; i++)
- if (cd->trk[i].track > track)
- break;
-
- top = i == cur_ntracks ? (cd->length - 1) * 75 : cd->trk[i].start;
-
- if (start > bottom && start < top)
- bottom = start;
-
- current = (top + bottom) / 2;
- interval = (top - bottom) / 4;
-
- do {
- play_chunk(current, current + 75);
-
- if (cd_status() != 1)
- return (0);
- while (cur_frame < current)
- if (cd_status() != 1 || cur_cdmode != 1)
- return (0);
- else
- usleep(1);
-
- if (cd->trk[cur_track - 1].track > track)
- break;
-
- if (cur_index >= index)
- {
- ret = current;
- current -= interval;
- }
- else
- current += interval;
- interval /= 2;
- } while (interval > 2);
-
- return (ret);
- }
-