5.6 Gerätedateien in der Praxis einsetzen
Auf den folgenden Seiten will ich Ihnen nun zeigen, wie Sie die Gerätedatei in der Praxis einsetzen können; also neben dem Lesen und Schreiben auch das Steuern des Treibers durch die Gerätedatei. Das Ziel des Abschnitts ist es, Ihnen ein Gefühl dafür zu geben, wie Sie die entsprechenden Informationen ermitteln können, um den unübersichtlichen Haufen von Gerätedateien steuern zu können.
Als Beispiel wird das CD-ROM-Laufwerk verwendet, da zum einen fast jeder Leser so etwas besitzen dürfte, und zum anderen lässt es sich damit relativ leicht nachvollziehen, da hierfür keine speziellen Hardware-Kenntnisse nötig sind. Es soll hierbei ein Listing erstellt werden, womit Sie die Lade öffnen können, um eine Musik-CD einzulegen. Weiterhin soll es möglich sein, die Track-Informationen einzulesen und auch wieder auszugeben. Die Musik soll ebenfalls wiedergegeben werden, mitsamt der Anzeige, welcher Track gerade läuft und wo gerade gelesen wird (zeitmäßig gesehen).
Das Ganze hört sich schlimmer an, als es ist, und lässt sich relativ einfach mit den Treiberbefehlen der Gerätedatei über ioctl() steuern. Das CD-ROM-Laufwerk lässt sich gewöhnlich von Haus aus über den Mountpoint /dev/cdrom oder auch /media/cdrom ansprechen. Wenn dies bei Ihnen nicht der Fall ist, wäre es sinnvoll, selbst einen symbolischen Link zum CD-ROM-Laufwerk zu legen. In der Tabelle zu den Gerätedateien können Sie das Verzeichnis für Ihr CD-ROM-Laufwerk herauslesen.
Außerdem benötigen Sie mindestens Leserechte auf das CD-ROM-Laufwerk. Sofern diese bei Ihnen nicht vorhanden sind, sollten Sie dieses Recht mittels chmod a+r /dev/hdc (/dev/hdc/ sei hier der Pfad zur Gerätedatei) setzen oder von Ihrem Administrator setzen lassen.
Zuerst müssen Sie die Informationen zu den Treiberbefehlen des CD-ROM-Laufwerks suchen. Einen ersten Überblick hierzu können Sie sich, wie schon erwähnt, unter man ioctl_list verschaffen. Folgende Informationen können hierbei schon ermittelt werden:
$ man ioctl_list
...
// <include/linux/cdrom.h>
0x00005301 CDROMPAUSE void
0x00005302 CDROMRESUME void
0x00005303 CDROMPLAYMSF const struct cdrom_msf *
0x00005304 CDROMPLAYTRKIND const struct cdrom_ti *
0x00005305 CDROMREADTOCHDR struct cdrom_tochdr *
0x00005306 CDROMREADTOCENTRY struct cdrom_tocentry *
0x00005307 CDROMSTOP void
0x00005308 CDROMSTART void
0x00005309 CDROMEJECT void
0x0000530A CDROMVOLCTRL const struct cdrom_volctrl *
0x0000530B CDROMSUBCHNL struct cdrom_subchnl *
0x0000530C CDROMREADMODE2 const struct cdrom_msf *
...
0x00005312 CDROMRESET void
0x00005313 CDROMVOLREAD struct cdrom_volctrl *
0x00005314 CDROMREADRAW const struct cdrom_msf *
0x00005315 CDROMREADCOOKED const struct cdrom_msf *
0x00005316 CDROMSEEK const struct cdrom_msf *
...
In der ersten Spalte finden Sie den Hexwert für den Treiber. Als Mensch liest man gerne, und daher finden Sie in der zweiten Spalte die symbolische Konstante dazu. In der dritten Spalte finden Sie außerdem den entsprechenden Datentyp oder die Struktur, worauf sich der Befehl bezieht – sprich das dritte Argument für die Funktion ioctl(). Dies ist schon ein guter Überblick. Aber um einen Blick in die Headerdatei für den Linux CD-ROM-Treiber kommen Sie nicht mehr herum, wenn Sie die einzelnen Strukturvariablen verwenden wollen. Wo Sie diese finden können, ist gleich zu Beginn bei der Manual Page mit <include/linux/cdrom.h> angegeben. Sie müssen also ins Verzeichnis Ihrer include-Dateien gehen. Meistens ist dies /usr/include oder /usr/local/include. Darin finden Sie jetzt außer den Befehlen noch alles, was Sie für die weitere Verwendung benötigen – vor allem auch eine kurze Beschreibung der einzelnen Befehle, was man ja bei man ioctl_list schmerzlich vermisst.
Hinweis Das folgende Beispiel lässt sich nur mit einem Linux-Rechner übersetzen und ausführen. Sofern Sie ein ähnliches Beispiel auf Systemen wie SunOS, NetBSD, OpenBSD oder FreeBSD erstellen wollen, benötigen Sie hierzu die Headerdatei sys/cdio.h anstatt linux/cdrom.h.
|
Leider gibt es hierbei einige (geringfügige) Differenzen, so dass ich mir hier nicht mit einer bedingten Kompilierung behelfen kann. Natürlich finden Sie als BSD-Leser auf der Buch-CD ein entsprechendes Listing (bsd_cdrom.c), das auf allen BSD- und eventuell (ungetestet) auch auf SunOS-Systemen laufen sollte.
|
5.6.1 CD auswerfen und wieder schließen
Bevor Sie das CD-ROM-Laufwerk steuern können, müssen Sie die entsprechende Gerätedatei zum Lesen öffnen. Der Übersichtlichkeit halber wurden die einzelnen Aktionen in kleine Routinen gepackt, womit Sie diese jederzeit für Ihre Zwecke verwenden können. Am Ende des Kapitels finden Sie die einzelnen Routinen nochmals als komplettes Listing wieder.
...
#define CDROM "/dev/cdrom"
...
static int open_cdrom (void) {
int fd = open (CDROM, O_RDONLY | O_NONBLOCK);
if (fd == -1) {
if (errno == ENOMEDIUM)
printf ("Keine CD im Laufwerk!\n");
else
perror ("Fehler bei open()");
exit (EXIT_FAILURE);
}
return fd;
}
Damit die Funktion open() nicht blockiert, wenn Sie mal keine CD im Laufwerk haben, muss das Flag O_NONBLOCK verwendet werden. Die Funktion gibt den Filedeskriptor cdrom für die anschließende weitere Steuerung mit ioctl() zurück.
Nachdem Sie die Gerätedatei zum Lesen geöffnet haben, können Sie die ersten Steuerbefehle ausführen. Hierzu werden erst einmal die einfachsten Kommandos, die keine weiteren Parameter in ioctl() mehr benötigen, verwendet, zum einen das Auswerfen der CD, zum anderen – falls technisch möglich – das Einfahren des Caddys. Gerade bei Laptops ist das Zurückfahren des CD-Fachs nicht möglich. Dafür bekommen Sie – wenn technisch nicht möglich – eine Meldung zurück, dies doch selbst zu tun.
static void open_tray (int cdrom) {
if (ioctl (cdrom, CDROMEJECT) == -1) {
perror ("Eject yourself");
exit (EXIT_FAILURE);
}
}
/* Funktioniert nicht überall */
static void close_tray (int cdrom) {
if (ioctl (cdrom, CDROMCLOSETRAY) == -1) {
printf ("CD-Tray bitte von Hand schließen\n");
}
}
5.6.2 CD-ROM-Fähigkeiten
Benötigen Sie die Fähigkeiten des CD-ROM-Laufwerks, dann können Sie dies mithilfe des Kommandos CDROM_GET_CAPABILITY ermitteln. In diesem Fall liefert ioctl() als Rückgabewert einen Integer zurück, dessen einzelne Bit-Werte es gilt auszulesen. In unserem Beispiel ermitteln wir zwar nur, um was für ein Laufwerk es sich handelt – sprich CD-R, CD-RW, DVD etc. –, aber Sie können gerne weitere Fähigkeiten, die alle mit dem Präfix CDC_ beginnen, zur Überprüfung verwenden und auswerten. Sie müssen lediglich den Rückgabewert von ioctl() mit dem bitweisen UND-Operator und der entsprechenden symbolischen CDC_-Konstante als Bedingung verwenden. Ist die Bedingung wahr, dann trifft Entsprechendes zu.
static void capability_cdrom (int cdrom) {
const char *j[] = {"nein", "ja"};
int caps = ioctl (cdrom, CDROM_GET_CAPABILITY);
if (caps == -1) {
perror ("CDROM_GET_CAPABILITY");
return;
}
printf ("CDROM-Fähigkeiten:\n"
"\tCD-R : %s\n"
"\tCD-RW : %s\n"
"\tDVD : %s\n"
"\tDVD-R : %s\n"
"\tDVD-RAM : %s\n",
j[!!(caps & CDC_CD_R)],
j[!!(caps & CDC_CD_RW)],
j[!!(caps & CDC_DVD)],
j[!!(caps & CDC_DVD_R)],
j[!!(caps & CDC_DVD_RAM)]);
}
5.6.3 Audio-CD abspielen – komplett und einzelne Tracks – Pause, Fortfahren und Stopp
Um das Inhaltsverzeichnis der CD einzulesen, können Sie die Kommandos CDROMTOCHDR und CDROMREADTOCENTRY verwenden (TOC = Table Of Contents). Verwenden Sie ioctl() mit CDROMTOCHDR, wird als dritter Parameter eine Adresse vom Typ struct cdrom_tochdr erwartet. Diese Struktur sieht in der Headerdatei cdrom.h wie folgt aus:
/* Struktur wird bei CDROMREADTOCHDR mit ioctl() erwartet */
struct cdrom_tochdr {
__u8 cdth_trk0; /* start track */
__u8 cdth_trk1; /* end track */
};
Wenn Sie das Kommando mit ioctl() verwenden, wird in der Struktur cdrom_tochdr der erste (cdth_trk0) und der letzte (cdth_trk1) Track eingetragen. Somit können Sie mit dem Auslesen des letzten Tracks schon ermitteln, wie viele Tracks sich auf der Audio-CD befinden.
Das zweite Kommando CDROMREADTOCENTRY hingegen benötigt als dritten Parameter für ioctl() eine Struktur vom Typ cdrom_tocentry, die folgendermaßen in der Headerdatei cdrom.h definiert ist.
/* Struktur wird bei CDROMREADTOCENTRY mit ioctl() erwartet */
struct cdrom_tocentry {
__u8 cdte_track;
__u8 cdte_adr : 4;
__u8 cdte_ctrl : 4;
__u8 cdte_format;
union cdrom_addr cdte_addr;
__u8 cdte_datamode;
};
Auf jeden Fall angeben müssen Sie in dieser Struktur den Track (cdte_track) und das Format der Ausgabe (cdte_format). Beim Format geben Sie CDROM_MSF (MSF = Minute, Sekunde, Frame) an. Möglich wäre auch CDROM_LBA (Logical Block Address), was eine Adresse, die durch eine Integerzahl dargestellt wird, zurückgeben würde. cdte_ctrl können Sie z. B. verwenden, um herauszufinden, ob es sich bei dem Track um einen Audio- oder Datentrack handelt. Hierzu müssen Sie nur wieder den bitweisen UND-Operator mit der Konstante CDROM_DATA_TRACK überprüfen. Ist der Ausdruck wahr, handelt es sich um einen Datentrack, ansonsten ist es ein Audiotrack.
Hinweis Eine Sekunde besteht aus 75 Frames. Ein Frame ist 2352 Bytes lang.
|
Da wir uns für die Minuten, Sekunden und Framelänge der CD-ROM mit CDROM_MSF interessieren, benötigen Sie union cdrom_addr cdte_addr – was allerdings nicht mehr auf den ersten Blick ersichtlich ist. Die Union cdrom_addr wiederum beinhaltet eine Struktur mit dem Namen struct cdrom_msf msf, die das beinhaltet, wonach Sie suchen. Hier die beiden Strukturen:
union cdrom_addr {
struct cdrom_msf0 msf;
int lba;
};
struct cdrom_msf0 {
__u8 minute;
__u8 second;
__u8 frame;
};
Hinweis Sofern Ihnen die Dokumentation der Gerätedatei nicht mehr weiterhilft, müssen Sie, ausgehend von den Angaben des Kommandos in ioctl(), die Angaben einer Struktur selbst systematisch absuchen. Ein Greenhorn verfängt sich bei umfangreicheren Gerätedateien dabei recht schnell im Netz der Spinne.
|
Hier die Funktion, die das Inhaltsverzeichnis einer Audio-CD auslesen soll.
static void content_cdrom (int cdrom) {
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocentry;
int track;
if (ioctl (cdrom, CDROMREADTOCHDR, &tochdr) == -1) {
perror ("Kann den Header nicht holen");
exit (EXIT_FAILURE);
}
printf ("\nInhalt %d Tracks:\n", tochdr.cdth_trk1);
track = tochdr.cdth_trk0;
while (track <= tochdr.cdth_trk1) {
tocentry.cdte_track = track;
tocentry.cdte_format = CDROM_MSF;
if (ioctl (cdrom, CDROMREADTOCENTRY, &tocentry)==-1) {
perror ("Kann Inhalt der CD nicht ermitteln");
exit (EXIT_FAILURE);
}
printf ("%3d: %02d:%02d:%02d (%06d) %s%s\n",
tocentry.cdte_track,
tocentry.cdte_addr.msf.minute,
tocentry.cdte_addr.msf.second,
tocentry.cdte_addr.msf.frame,
tocentry.cdte_addr.msf.frame +
tocentry.cdte_addr.msf.second * 75 +
tocentry.cdte_addr.msf.minute * 75 * 60 - 150,
(tocentry.cdte_ctrl & CDROM_DATA_TRACK)
? "data " : "audio",
CDROM_LEADOUT == track ? " (leadout)" : "");
track++;
}
}
Im nächsten Schritt soll die Audio-CD abgespielt werden. Zur Auswahl steht, entweder die komplette CD oder nur einen bestimmten Track abzuspielen. Auch hierzu benötigen Sie das Kommando CDROMREADTOCENTRY, um den Inhalt der CD bzw. bestimmte Tracks abzuspielen. Die Struktur cdrom_tocentry benötigen Sie, um den Anfang des ersten Tracks (cdte_track), das Format (CDROM_MSF) und das Ende des letzten bzw., im Falle einer Einzelauswahl, das Ende des nächsten Tracks anzuzeigen. Den letzten Track können Sie übrigens auch mit der symbolischen Konstante CDROM_LEADOUT angeben.
Abgespielt wird diese Position dann mit dem Kommando CDROMPLAYMSF und der Struktur cdrom_msf als dritten Parameter von ioctl().
/* Struktur wird bei CDROMPLAYMSF mit ioctl() erwartet */
struct cdrom_msf {
__u8 cdmsf_min0; /* start minute */
__u8 cdmsf_sec0; /* start second */
__u8 cdmsf_frame0; /* start frame */
__u8 cdmsf_min1; /* end minute */
__u8 cdmsf_sec1; /* end second */
__u8 cdmsf_frame1; /* end frame */
};
Bevor Sie also ioctl() und das Kommando CDROMPLAYMSF auf die Struktur loslassen, müssen Sie zuerst die Anfangsposition an den einzelnen Strukturvariablen übergeben – was alle Strukturvariablen mit der ..0 am Ende beinhaltet (cdmsf_min0, cdmsf_sec0, cdmsf_frame0) – und die Endposition, was alle Strukturvariablen (wer hätte das gedacht) mit einer ..1 am Ende beinhaltet (cdmsf_min1, cdmsf_sec1, cdmsf_frame1). Hier die Funktion dazu:
static void play_cdrom ( int cdrom, int flag ) {
struct cdrom_tocentry tocentry;
struct cdrom_msf play;
int track = flag;
int lead = flag;
if(flag == FULL) {
track = 1;
lead = CDROM_LEADOUT;
}
else {
track = flag;
lead = flag+1;
}
/* Anfang des ersten Liedes */
tocentry.cdte_track = track;
tocentry.cdte_format = CDROM_MSF;
if (ioctl (cdrom, CDROMREADTOCENTRY, &tocentry) == -1) {
perror ("Kann den Inhalt der CD nicht ermitteln\n");
exit (EXIT_FAILURE);
}
play.cdmsf_min0 = tocentry.cdte_addr.msf.minute;
play.cdmsf_sec0 = tocentry.cdte_addr.msf.second;
play.cdmsf_frame0 = tocentry.cdte_addr.msf.frame;
/* Ende des letzten Liedes */
tocentry.cdte_track = lead;
tocentry.cdte_format = CDROM_MSF;
if (ioctl (cdrom, CDROMREADTOCENTRY, &tocentry) == -1) {
perror ("Kann den Inhalt der CD nicht ermitteln\n");
exit (EXIT_FAILURE);
}
play.cdmsf_min1 = tocentry.cdte_addr.msf.minute;
play.cdmsf_sec1 = tocentry.cdte_addr.msf.second;
play.cdmsf_frame1 = tocentry.cdte_addr.msf.frame;
if (ioctl (cdrom, CDROMPLAYMSF, &play) == -1) {
perror ("Kann CD nicht abspielen");
exit (EXIT_FAILURE);
}
}
Wollen Sie die CD stoppen, eine Pause einbauen und den Track wieder aufnehmen, so müssen Sie nur die Kommandos CDROMSTOP, CDROMPAUSE und CDROMRESUME ohne weitere Parameter mit ioctl() aufrufen.
static void stop_cdrom (int cdrom) {
if (ioctl (cdrom, CDROMSTOP) == -1) {
perror ("Kann CD nicht anhalten");
return;
}
}
static void pause_cdrom (int cdrom) {
if (ioctl (cdrom, CDROMPAUSE) == -1) {
perror ("Kann PAUSE nicht setzen");
return;
}
}
static void resume_cdrom (int cdrom) {
if (ioctl (cdrom, CDROMRESUME) == -1) {
perror ("Kann CD nicht mehr fortfahren");
return;
}
}
5.6.4 Aktuellen Status der Audio-CD ermitteln
Nachdem Sie eventuell die Audio-CD gestartet haben, möchten Sie sicherlich auch wissen, welcher Track gerade abgespielt wird oder wie lange der Track oder die CD insgesamt schon abgespielt wurde – oder ob die CD überhaupt gerade gespielt wird, falls jemand gerade Pause gedrückt hat, etc.
Den Status einer laufenden Audio-CD können Sie mit dem Kommando CDROMSUBCHNL und der Struktur cdrom_subchnl als dritten Parameter für ioctl() ermitteln.
/* Struktur wird bei CDROMSUBCHNL mit ioctl() erwartet */
struct cdrom_subchnl {
__u8 cdsc_format;
__u8 cdsc_audiostatus;
__u8 cdsc_adr: 4;
__u8 cdsc_ctrl: 4;
__u8 cdsc_trk;
__u8 cdsc_ind;
union cdrom_addr cdsc_absaddr;
union cdrom_addr cdsc_reladdr;
};
Bevor Sie ioctl() aufrufen, sollten Sie zuvor noch das Format (cdsc_format=CDROM_MSF) angeben. Nach dem Aufruf von ioctl() beinhaltet cdsc_audiostatus den aktuellen Status der Audio-CD. Dies können folgende symbolische Konstanten sein:
/* Audio-Status ermitteln wird nicht unterstützt */
#define CDROM_AUDIO_INVALID 0x00
/* Audio-CD wird gerade abgespielt */
#define CDROM_AUDIO_PLAY 0x11
/* Audio-CD wurde angehalten (Pause) */
#define CDROM_AUDIO_PAUSED 0x12
/* Audio-CD wurde komplett abgespielt */
#define CDROM_AUDIO_COMPLETED 0x13
/* Audio-CD abspielen wurde wegen Fehler unterbrochen */
#define CDROM_AUDIO_ERROR 0x14
/* Kein besonderer Status vorhanden */
#define CDROM_AUDIO_NO_STATUS 0x15
Über die Strukturvariable cdsc_absaddr können Sie dann die absolute Zeit und über cdsc_reladdr die relative Zeit der Audio-CD ermitteln. Auch hier finden Sie wieder die entsprechenden Werte über den Umweg zur Union cdrom_addr. Hier die Funktion dafür:
static void get_audio_status (int cdrom) {
struct cdrom_subchnl sub;
printf ("Audio status: ");
fflush (stdout);
sub.cdsc_format = CDROM_MSF;
if (ioctl (cdrom, CDROMSUBCHNL, &sub))
printf ("FAILED\n");
else {
switch (sub.cdsc_audiostatus) {
case CDROM_AUDIO_INVALID:
printf ("invalid\n");
break;
case CDROM_AUDIO_PLAY:
printf ("playing");
break;
case CDROM_AUDIO_PAUSED:
printf ("paused");
break;
case CDROM_AUDIO_COMPLETED:
printf ("completed\n");
break;
case CDROM_AUDIO_ERROR:
printf ("error\n");
break;
case CDROM_AUDIO_NO_STATUS:
printf ("no status\n");
break;
default:
printf ("Oops: unknown\n");
}
if (sub.cdsc_audiostatus == CDROM_AUDIO_PLAY ||
sub.cdsc_audiostatus == CDROM_AUDIO_PAUSED) {
printf (" at: %02d:%02d abs/ %02d:%02d track %d\n",
sub.cdsc_absaddr.msf.minute,
sub.cdsc_absaddr.msf.second,
sub.cdsc_reladdr.msf.minute,
sub.cdsc_reladdr.msf.second, sub.cdsc_trk);
}
}
}
5.6.5 Das komplette Listing
Sie haben nun gesehen, wie einfach es ist, mit ioctl() und den entsprechenden Kommandos auf die Treiberschnittstelle der Hardware über die Gerätedatei zuzugreifen. Allerdings haben Sie leider auch gemerkt, dass dies recht mühsam werden kann, wenn man den ganzen Strukturen folgen muss. Aber so, wie Sie hierbei vorgegangen sind, werden Sie in der Regel immer vorgehen müssen. Aufgrund des enormen Umfangs der Gerätedateien ist das immer noch eine recht undokumentierte Geschichte.
Hier nun nochmals die einzelnen Funktionen, eingebaut in einem kompletten Listing:
/* cdrom.c */
#include <stdio.h>
#include <unistd. h.>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/cdrom.h>
#include <errno.h>
/* Bitte ggf. Anpassen */
#define CDROM "/dev/cdrom"
#define FULL 0 /* komplette Audio-CD abspielen */
static int open_cdrom (void) {
int fd = open (CDROM, O_RDONLY | O_NONBLOCK);
if (fd == -1) {
if (errno == ENOMEDIUM)
printf ("Keine CD im Laufwerk!\n");
else
perror ("Fehler bei open()");
exit (EXIT_FAILURE);
}
return fd;
}
static void open_tray (int cdrom) {
if (ioctl (cdrom, CDROMEJECT) == -1) {
perror ("Eject yourself");
exit (EXIT_FAILURE);
}
}
/* Funktioniert nicht überall */
static void close_tray (int cdrom) {
if (ioctl (cdrom, CDROMCLOSETRAY) == -1) {
printf ("CD-Tray bitte von Hand schließen\n");
}
}
static void capability_cdrom (int cdrom) {
const char *j[] = {"nein", "ja"};
int caps = ioctl (cdrom, CDROM_GET_CAPABILITY);
if (caps == -1) {
perror ("CDROM_GET_CAPABILITY");
return;
}
printf ("CDROM-Fähigkeiten:\n"
"\tCD-R : %s\n"
"\tCD-RW : %s\n"
"\tDVD : %s\n"
"\tDVD-R : %s\n"
"\tDVD-RAM : %s\n",
j[!!(caps & CDC_CD_R)],
j[!!(caps & CDC_CD_RW)],
j[!!(caps & CDC_DVD)],
j[!!(caps & CDC_DVD_R)],
j[!!(caps & CDC_DVD_RAM)]);
}
static void get_audio_status (int cdrom) {
struct cdrom_subchnl sub;
printf ("Audio-Status: ");
fflush (stdout);
sub.cdsc_format = CDROM_MSF;
if (ioctl (cdrom, CDROMSUBCHNL, &sub))
printf ("FAILED\n");
else {
switch (sub.cdsc_audiostatus) {
case CDROM_AUDIO_INVALID:
printf ("invalid\n");
break;
case CDROM_AUDIO_PLAY:
printf ("playing");
break;
case CDROM_AUDIO_PAUSED:
printf ("paused");
break;
case CDROM_AUDIO_COMPLETED:
printf ("completed\n");
break;
case CDROM_AUDIO_ERROR:
printf ("error\n");
break;
case CDROM_AUDIO_NO_STATUS:
printf ("no status\n");
break;
default:
printf ("Oops: unknown\n");
}
if (sub.cdsc_audiostatus == CDROM_AUDIO_PLAY ||
sub.cdsc_audiostatus == CDROM_AUDIO_PAUSED) {
printf (" at: %02d:%02d abs/ %02d:%02d track %d\n",
sub.cdsc_absaddr.msf.minute,
sub.cdsc_absaddr.msf.second,
sub.cdsc_reladdr.msf.minute,
sub.cdsc_reladdr.msf.second, sub.cdsc_trk);
}
}
}
static void content_cdrom (int cdrom) {
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocentry;
int track;
if (ioctl (cdrom, CDROMREADTOCHDR, &tochdr) == -1) {
perror ("Kann den Header nicht holen");
exit (EXIT_FAILURE);
}
printf ("\nInhalt %d Tracks:\n", tochdr.cdth_trk1);
track = tochdr.cdth_trk0;
while (track <= tochdr.cdth_trk1) {
tocentry.cdte_track = track;
tocentry.cdte_format = CDROM_MSF;
if (ioctl (cdrom, CDROMREADTOCENTRY, &tocentry)==-1) {
perror ("Kann den Inhalt der CD nicht ermitteln");
exit (EXIT_FAILURE);
}
printf ("%3d: %02d:%02d:%02d (%06d) %s%s\n",
tocentry.cdte_track,
tocentry.cdte_addr.msf.minute,
tocentry.cdte_addr.msf.second,
tocentry.cdte_addr.msf.frame,
tocentry.cdte_addr.msf.frame +
tocentry.cdte_addr.msf.second * 75 +
tocentry.cdte_addr.msf.minute * 75 * 60 - 150,
(tocentry.cdte_ctrl & CDROM_DATA_TRACK) ?
"data " : "audio",
CDROM_LEADOUT == track ? " (leadout)" : "");
track++;
}
}
static void play_cdrom ( int cdrom, int flag ) {
struct cdrom_tocentry tocentry;
struct cdrom_msf play;
int track = flag;
int lead = flag;
if(flag == FULL) {
track = 1;
lead = CDROM_LEADOUT;
}
else {
track = flag;
lead = flag+1;
}
/* Anfang des ersten Liedes */
tocentry.cdte_track = track;
tocentry.cdte_format = CDROM_MSF;
if (ioctl (cdrom, CDROMREADTOCENTRY, &tocentry) == -1) {
perror ("Kann den Inhalt der CD nicht ermitteln\n");
exit (EXIT_FAILURE);
}
play.cdmsf_min0 = tocentry.cdte_addr.msf.minute;
play.cdmsf_sec0 = tocentry.cdte_addr.msf.second;
play.cdmsf_frame0 = tocentry.cdte_addr.msf.frame;
/* Ende des letzten Liedes */
tocentry.cdte_track = lead;
tocentry.cdte_format = CDROM_MSF;
if (ioctl (cdrom, CDROMREADTOCENTRY, &tocentry) == -1) {
perror ("Kann den Inhalt der CD nicht ermitteln\n");
exit (EXIT_FAILURE);
}
play.cdmsf_min1 = tocentry.cdte_addr.msf.minute;
play.cdmsf_sec1 = tocentry.cdte_addr.msf.second;
play.cdmsf_frame1 = tocentry.cdte_addr.msf.frame;
if (ioctl (cdrom, CDROMPLAYMSF, &play) == -1) {
perror ("Kann CD nicht abspielen");
exit (EXIT_FAILURE);
}
}
static void stop_cdrom (int cdrom) {
if (ioctl (cdrom, CDROMSTOP) == -1) {
perror ("Kann CD nicht anhalten");
return;
}
}
static void pause_cdrom (int cdrom) {
if (ioctl (cdrom, CDROMPAUSE) == -1) {
perror ("Kann PAUSE nicht setzen");
return;
}
}
static void resume_cdrom (int cdrom) {
if (ioctl (cdrom, CDROMRESUME) == -1) {
perror ("Kann CD nicht mehr fortfahren");
return;
}
}
int main (void) {
int fd_cdrom;
int select;
int track;
fd_cdrom = open_cdrom();
do{
printf("-1- CD-Tray öffnen\n");
printf("-2- CD-Tray schließen\n");
printf("-3- CDROM-Fähigkeiten\n");
printf("-4- Audio-CD abspielen (komplett)\n");
printf("-5- Einzelnen Track abspielen\n");
printf("-6- <PAUSE> Audio-CD abspielen\n");
printf("-7- <FORTFAHREN> Audio-CD abspielen\n");
printf("-8- <STOP> Audio-CD abspielen\n");
printf("-9- Aktuellen Status ermitteln\n");
printf("-10- CD-Inhalt ausgeben\n");
printf("-11- Programmende\n");
printf("\nIhre Auswahl : ");
scanf("%d",&select);
switch( select ) {
case 1: open_tray( fd_cdrom ); break;
case 2: close_tray( fd_cdrom ); break;
case 3: capability_cdrom (fd_cdrom); break;
case 4: play_cdrom (fd_cdrom, FULL); break;
case 5: printf("Welchen Track wollen Sie hören: ");
scanf("%d",&track);
play_cdrom( fd_cdrom, track); break;
case 6: pause_cdrom( fd_cdrom ); break;
case 7: resume_cdrom( fd_cdrom ); break;
case 8: stop_cdrom( fd_cdrom ); break;
case 9: get_audio_status( fd_cdrom );break;
case 10: content_cdrom( fd_cdrom ); break;
case 11: printf("Bye\n"); break;
default : printf("Häh!\n");
}
} while( select != 11 );
stop_cdrom( fd_cdrom );
close (fd_cdrom);
return 0;
}
Das Programm bei der Ausführung:
$ gcc -o cdrom cdrom.c
$ ./cdrom
-1- CD-Tray öffnen
-2- CD-Tray schließen
-3- CDROM-Fähigkeiten
-4- Audio-CD abspielen (komplett)
-5- Einzelnen Track abspielen
-6- <PAUSE> Audio-CD abspielen
-7- <FORTFAHREN> Audio-CD abspielen
-8- <STOP> Audio-CD abspielen
-9- Aktuellen Status ermitteln
-10- CD-Inhalt ausgeben
-11- Programmende
Ihre Auswahl : ...
|