Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 5 Devices – eine einfache Verbindung zur Hardware
  gp 5.1 Die Gerätedateitypen
  gp 5.2 Die Gerätedateinummern
  gp 5.3 Zugriff auf die Gerätedateien
  gp 5.4 Gerätenamen
  gp 5.5 Spezielle Gerätedateien
  gp 5.6 Gerätedateien in der Praxis einsetzen
    gp 5.6.1 CD auswerfen und wieder schließen
    gp 5.6.2 CD-ROM-Fähigkeiten
    gp 5.6.3 Audio-CD abspielen – komplett und einzelne Tracks – Pause, Fortfahren und Stopp
    gp 5.6.4 Aktuellen Status der Audio-CD ermitteln
    gp 5.6.5 Das komplette Listing


Rheinwerk Computing

5.6 Gerätedateien in der Praxis einsetzedowntop

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.



Rheinwerk Computing

5.6.1 CD auswerfen und wieder schließen  downtop

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");
   }
}

Rheinwerk Computing

5.6.2 CD-ROM-Fähigkeiten  downtop

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)]);
}

Rheinwerk Computing

5.6.3 Audio-CD abspielen – komplett und einzelne Tracks – Pause, Fortfahren und Stopp  downtop

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;
   }
}

Rheinwerk Computing

5.6.4 Aktuellen Status der Audio-CD ermitteln  downtop

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);
      }
   }
}

Rheinwerk Computing

5.6.5 Das komplette Listing  toptop

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 : ...
 << zurück
  
  Zum Katalog
Zum Katalog: Linux-UNIX-Programmierung
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Linux-Server






 Linux-Server


Zum Katalog: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Katalog: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Katalog: Shell-Programmierung






 Shell-
 Programmierung


Zum Katalog: Linux Handbuch






 Linux Handbuch


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de