symbian-qemu-0.9.1-12/libsdl-trunk/src/cdrom/qnx/SDL_syscdrom.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2006 Sam Lantinga
       
     4 
       
     5     This library is free software; you can redistribute it and/or
       
     6     modify it under the terms of the GNU Lesser General Public
       
     7     License as published by the Free Software Foundation; either
       
     8     version 2.1 of the License, or (at your option) any later version.
       
     9 
       
    10     This library 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 GNU
       
    13     Lesser General Public License for more details.
       
    14 
       
    15     You should have received a copy of the GNU Lesser General Public
       
    16     License along with this library; if not, write to the Free Software
       
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    18 
       
    19     Sam Lantinga
       
    20     slouken@libsdl.org
       
    21 */
       
    22 #include "SDL_config.h"
       
    23 
       
    24 #ifdef SDL_CDROM_QNX
       
    25 
       
    26 /* Functions for system-level CD-ROM audio control */
       
    27 
       
    28 #include <sys/types.h>
       
    29 #include <sys/stat.h>
       
    30 #include <sys/ioctl.h>
       
    31 #include <fcntl.h>
       
    32 #include <errno.h>
       
    33 #include <unistd.h>
       
    34 #include <sys/cdrom.h>
       
    35 #include <sys/dcmd_cam.h>
       
    36 
       
    37 #include "SDL_timer.h"
       
    38 #include "SDL_cdrom.h"
       
    39 #include "../SDL_syscdrom.h"
       
    40 
       
    41 /* The maximum number of CD-ROM drives we'll detect */
       
    42 #define MAX_DRIVES 16
       
    43 
       
    44 #define QNX_CD_OPENMODE O_RDONLY | O_EXCL
       
    45 
       
    46 /* A list of available CD-ROM drives */
       
    47 static char *SDL_cdlist[MAX_DRIVES];
       
    48 static dev_t SDL_cdmode[MAX_DRIVES];
       
    49 static int   SDL_cdopen[MAX_DRIVES];
       
    50 
       
    51 /* The system-dependent CD control functions */
       
    52 static const char *SDL_SYS_CDName(int drive);
       
    53 static int SDL_SYS_CDOpen(int drive);
       
    54 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
       
    55 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
       
    56 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
       
    57 static int SDL_SYS_CDPause(SDL_CD *cdrom);
       
    58 static int SDL_SYS_CDResume(SDL_CD *cdrom);
       
    59 static int SDL_SYS_CDStop(SDL_CD *cdrom);
       
    60 static int SDL_SYS_CDEject(SDL_CD *cdrom);
       
    61 static void SDL_SYS_CDClose(SDL_CD *cdrom);
       
    62 
       
    63 /* Check a drive to see if it is a CD-ROM */
       
    64 static int CheckDrive(char *drive, struct stat *stbuf)
       
    65 {
       
    66     int is_cd, cdfd;
       
    67     cam_devinfo_t dinfo;
       
    68     int devctlret=0;
       
    69 
       
    70     int atapi;
       
    71     int removable;
       
    72     int cdb10;
       
    73 
       
    74     /* If it doesn't exist, return -1 */
       
    75     if (stat(drive, stbuf) < 0)
       
    76     {
       
    77         return(-1);
       
    78     }
       
    79 
       
    80     /* If it does exist, verify that it's an available CD-ROM */
       
    81     is_cd = 0;
       
    82 
       
    83     if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode))
       
    84     {
       
    85         cdfd = open(drive, QNX_CD_OPENMODE);
       
    86         if ( cdfd >= 0 )
       
    87         {
       
    88             devctlret=devctl(cdfd, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t), NULL);
       
    89 
       
    90             if (devctlret==EOK)
       
    91             {
       
    92                atapi=dinfo.flags & DEV_ATAPI;
       
    93                removable=dinfo.flags & DEV_REMOVABLE;
       
    94                cdb10=dinfo.flags & DEV_CDB_10; /* I'm not sure about that flag */
       
    95 
       
    96                /* in the near future need to add more checks for splitting cdroms from other devices */
       
    97                if ((atapi)&&(removable))
       
    98                {
       
    99                    is_cd = 1;
       
   100                }
       
   101             }
       
   102 
       
   103             close(cdfd);
       
   104         }
       
   105     }
       
   106     return(is_cd);
       
   107 }
       
   108 
       
   109 /* Add a CD-ROM drive to our list of valid drives */
       
   110 static void AddDrive(char *drive, struct stat *stbuf)
       
   111 {
       
   112     int i;
       
   113 
       
   114     if (SDL_numcds < MAX_DRIVES)
       
   115     {
       
   116         /* Check to make sure it's not already in our list.
       
   117         This can happen when we see a drive via symbolic link. */
       
   118 
       
   119         for (i=0; i<SDL_numcds; ++i)
       
   120         {
       
   121             if (stbuf->st_rdev == SDL_cdmode[i])
       
   122             {
       
   123                 return;
       
   124             }
       
   125         }
       
   126 
       
   127         /* Add this drive to our list */
       
   128 
       
   129         i = SDL_numcds;
       
   130         SDL_cdlist[i] = SDL_strdup(drive);
       
   131         if (SDL_cdlist[i] == NULL)
       
   132         {
       
   133             SDL_OutOfMemory();
       
   134             return;
       
   135         }
       
   136         SDL_cdmode[i] = stbuf->st_rdev;
       
   137         ++SDL_numcds;
       
   138     }
       
   139 }
       
   140 
       
   141 int SDL_SYS_CDInit(void)
       
   142 {
       
   143     /* checklist: /dev/cdrom, /dev/cd?, /dev/scd? */
       
   144     static char *checklist[]={"cdrom", "?0 cd?", "?1 cd?", "?0 scd?", NULL};
       
   145 
       
   146     char *SDLcdrom;
       
   147     int i, j, exists;
       
   148     char drive[32];
       
   149     struct stat stbuf;
       
   150 
       
   151     /* Fill in our driver capabilities */
       
   152     SDL_CDcaps.Name = SDL_SYS_CDName;
       
   153     SDL_CDcaps.Open = SDL_SYS_CDOpen;
       
   154     SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
       
   155     SDL_CDcaps.Status = SDL_SYS_CDStatus;
       
   156     SDL_CDcaps.Play = SDL_SYS_CDPlay;
       
   157     SDL_CDcaps.Pause = SDL_SYS_CDPause;
       
   158     SDL_CDcaps.Resume = SDL_SYS_CDResume;
       
   159     SDL_CDcaps.Stop = SDL_SYS_CDStop;
       
   160     SDL_CDcaps.Eject = SDL_SYS_CDEject;
       
   161     SDL_CDcaps.Close = SDL_SYS_CDClose;
       
   162 
       
   163     /* clearing device open status */
       
   164     for (i=0; i<MAX_DRIVES; i++)
       
   165     {
       
   166        SDL_cdopen[i]=0;
       
   167     }
       
   168 
       
   169     /* Look in the environment for our CD-ROM drive list */
       
   170     SDLcdrom = SDL_getenv("SDL_CDROM");	/* ':' separated list of devices */
       
   171     if ( SDLcdrom != NULL )
       
   172     {
       
   173         char *cdpath, *delim;
       
   174 	size_t len = SDL_strlen(SDLcdrom)+1;
       
   175         cdpath = SDL_stack_alloc(char, len);
       
   176         if (cdpath != NULL)
       
   177         {
       
   178             SDL_strlcpy(cdpath, SDLcdrom, len);
       
   179             SDLcdrom = cdpath;
       
   180             do {
       
   181                 delim = SDL_strchr(SDLcdrom, ':');
       
   182                 if (delim)
       
   183                 {
       
   184                     *delim++ = '\0';
       
   185                 }
       
   186                 if (CheckDrive(SDLcdrom, &stbuf) > 0)
       
   187                 {
       
   188                     AddDrive(SDLcdrom, &stbuf);
       
   189                 }
       
   190                 if (delim)
       
   191                 {
       
   192                     SDLcdrom = delim;
       
   193                 }
       
   194                 else
       
   195                 {
       
   196                     SDLcdrom = NULL;
       
   197                 }
       
   198             } while (SDLcdrom);
       
   199             SDL_stack_free(cdpath);
       
   200         }
       
   201 
       
   202         /* If we found our drives, there's nothing left to do */
       
   203         if (SDL_numcds > 0)
       
   204         {
       
   205             return(0);
       
   206         }
       
   207     }
       
   208 
       
   209     /* Scan the system for CD-ROM drives */
       
   210     for ( i=0; checklist[i]; ++i )
       
   211     {
       
   212         if (checklist[i][0] == '?')
       
   213         {
       
   214             char* insert;
       
   215             exists = 1;
       
   216 
       
   217             for ( j=checklist[i][1]; exists; ++j )
       
   218             {
       
   219                 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]);
       
   220                 insert = SDL_strchr(drive, '?');
       
   221                 if (insert != NULL)
       
   222                 {
       
   223                     *insert = j;
       
   224                 }
       
   225                 switch (CheckDrive(drive, &stbuf))
       
   226                 {
       
   227                     /* Drive exists and is a CD-ROM */
       
   228                     case 1:
       
   229                              AddDrive(drive, &stbuf);
       
   230                              break;
       
   231                     /* Drive exists, but isn't a CD-ROM */
       
   232                     case 0:
       
   233                              break;
       
   234                     /* Drive doesn't exist */
       
   235                     case -1:
       
   236                              exists = 0;
       
   237                              break;
       
   238                 }
       
   239             }
       
   240         }
       
   241         else
       
   242         {
       
   243             SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]);
       
   244             if (CheckDrive(drive, &stbuf) > 0)
       
   245             {
       
   246                 AddDrive(drive, &stbuf);
       
   247             }
       
   248         }
       
   249     }
       
   250     return(0);
       
   251 }
       
   252 
       
   253 static const char *SDL_SYS_CDName(int drive)
       
   254 {
       
   255     return(SDL_cdlist[drive]);
       
   256 }
       
   257 
       
   258 static int SDL_SYS_CDOpen(int drive)
       
   259 {
       
   260     int handle;
       
   261 
       
   262     handle=open(SDL_cdlist[drive], QNX_CD_OPENMODE);
       
   263 
       
   264     if (handle>0)
       
   265     {
       
   266         SDL_cdopen[drive]=handle;
       
   267     }
       
   268 
       
   269     return (handle);
       
   270 }
       
   271 
       
   272 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
       
   273 {
       
   274     cdrom_read_toc_t toc;
       
   275     int i, okay;
       
   276 
       
   277     okay = 0;
       
   278     if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL) == 0)
       
   279     {
       
   280         cdrom->numtracks = toc.last_track - toc.first_track + 1;
       
   281         if (cdrom->numtracks > SDL_MAX_TRACKS)
       
   282         {
       
   283             cdrom->numtracks = SDL_MAX_TRACKS;
       
   284         }
       
   285         /* Read all the track TOC entries */
       
   286         for (i=0; i<=cdrom->numtracks; ++i)
       
   287         {
       
   288             if (i == cdrom->numtracks)
       
   289             {
       
   290                 cdrom->track[i].id = CDROM_LEADOUT;
       
   291             }
       
   292             else
       
   293             {
       
   294                 cdrom->track[i].id = toc.first_track+i;
       
   295             }
       
   296 
       
   297             cdrom->track[i].type = toc.toc_entry[i].control_adr & 0x0F;
       
   298             cdrom->track[i].offset = toc.toc_entry[i].addr.lba;
       
   299             cdrom->track[i].length = 0;
       
   300 
       
   301             if (i > 0)
       
   302             {
       
   303                  cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset;
       
   304             }
       
   305         }
       
   306         if (i == (cdrom->numtracks+1))
       
   307         {
       
   308             okay = 1;
       
   309         }
       
   310     }
       
   311     return (okay ? 0 : -1);
       
   312 }
       
   313 
       
   314 /* Get CD-ROM status */
       
   315 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
       
   316 {
       
   317     CDstatus status;
       
   318 
       
   319     cdrom_read_toc_t toc;
       
   320     cdrom_subch_data_t info;
       
   321     cam_devinfo_t dinfo;
       
   322 
       
   323     int devctlret=0;
       
   324     int drive=-1;
       
   325     int i;
       
   326     int eagaincnt=0;
       
   327 
       
   328     /* check media presence before read subchannel call, some cdroms can lockups */
       
   329     /* if no media, while calling read subchannel functions.                     */
       
   330     devctlret=devctl(cdrom->id, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t), NULL);
       
   331 
       
   332     if (devctlret==EOK)
       
   333     {
       
   334         if ((dinfo.flags & DEV_NO_MEDIA)!=0)
       
   335         {
       
   336             status = CD_TRAYEMPTY;
       
   337             if (position)
       
   338             {
       
   339                 *position = 0;
       
   340             }
       
   341             return (status);
       
   342         }
       
   343     }
       
   344 
       
   345     /* if media exists, then do other stuff */
       
   346 
       
   347     SDL_memset(&info, 0x00, sizeof(info));
       
   348     info.subch_command.data_format = CDROM_SUBCH_CURRENT_POSITION;
       
   349 
       
   350     do {
       
   351         devctlret=devctl(cdrom->id, DCMD_CAM_CDROMSUBCHNL, &info, sizeof(info), NULL);
       
   352         if (devctlret==EIO)
       
   353         {
       
   354             /* big workaround for media change, handle is unusable after that,
       
   355                that bug was found in QNX 6.2, 6.2.1 is not released yet.    */
       
   356 
       
   357             for (i=0; i<MAX_DRIVES; i++)
       
   358             {
       
   359                 if (SDL_cdopen[i]==cdrom->id)
       
   360                 {
       
   361                     drive=i;
       
   362                     break;
       
   363                 }
       
   364             }
       
   365             if (drive==-1)
       
   366             {
       
   367                /* that cannot happen, but ... */
       
   368                break;
       
   369             }
       
   370             close(cdrom->id);
       
   371             cdrom->id=open(SDL_cdlist[drive], QNX_CD_OPENMODE);
       
   372             devctlret=EAGAIN;
       
   373         }
       
   374         if (devctlret==EAGAIN)
       
   375         {
       
   376             eagaincnt++;
       
   377         }
       
   378         if (eagaincnt==2)
       
   379         {
       
   380             /* workaround for broken cdroms, which can return always EAGAIN when its not ready, */
       
   381             /* that mean errornous media or just no media avail                                 */
       
   382             devctlret=ENXIO;
       
   383             break;
       
   384         }
       
   385     } while ((devctlret==EAGAIN)||(devctlret==ESTALE));
       
   386 
       
   387     if (devctlret != 0)
       
   388     {
       
   389         if (devctlret==ENXIO)
       
   390         {
       
   391             status = CD_TRAYEMPTY;
       
   392         }
       
   393         else
       
   394         {
       
   395             status = CD_ERROR;
       
   396         }
       
   397     }
       
   398     else
       
   399     {
       
   400         switch (info.current_position.header.audio_status)
       
   401         {
       
   402             case CDROM_AUDIO_INVALID:
       
   403             case CDROM_AUDIO_NO_STATUS:
       
   404                  /* Try to determine if there's a CD available */
       
   405                  if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL)==0)
       
   406                      status = CD_STOPPED;
       
   407                  else
       
   408                      status = CD_TRAYEMPTY;
       
   409                  break;
       
   410             case CDROM_AUDIO_COMPLETED:
       
   411                  status = CD_STOPPED;
       
   412                  break;
       
   413             case CDROM_AUDIO_PLAY:
       
   414                  status = CD_PLAYING;
       
   415                  break;
       
   416             case CDROM_AUDIO_PAUSED:
       
   417                  /* Workaround buggy CD-ROM drive */
       
   418                  if (info.current_position.data_format == CDROM_LEADOUT)
       
   419                  {
       
   420                      status = CD_STOPPED;
       
   421                  }
       
   422                  else
       
   423                  {
       
   424                      status = CD_PAUSED;
       
   425                  }
       
   426                  break;
       
   427             default:
       
   428                  status = CD_ERROR;
       
   429                  break;
       
   430         }
       
   431     }
       
   432 
       
   433     if (position)
       
   434     {
       
   435        if (status==CD_PLAYING || (status==CD_PAUSED))
       
   436        {
       
   437            *position = MSF_TO_FRAMES(info.current_position.addr.msf.minute,
       
   438                                      info.current_position.addr.msf.second,
       
   439                                      info.current_position.addr.msf.frame);
       
   440        }
       
   441        else
       
   442        {
       
   443            *position = 0;
       
   444        }
       
   445     }
       
   446 
       
   447     return (status);
       
   448 }
       
   449 
       
   450 /* Start play */
       
   451 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
       
   452 {
       
   453     cdrom_playmsf_t playtime;
       
   454 
       
   455     FRAMES_TO_MSF(start, &playtime.start_minute, &playtime.start_second, &playtime.start_frame);
       
   456     FRAMES_TO_MSF(start+length, &playtime.end_minute, &playtime.end_second, &playtime.end_frame);
       
   457 
       
   458     if (devctl(cdrom->id, DCMD_CAM_CDROMPLAYMSF, &playtime, sizeof(playtime), NULL) != 0)
       
   459     {
       
   460        return -1;
       
   461     }
       
   462     else
       
   463     {
       
   464        return 0;
       
   465     }
       
   466 }
       
   467 
       
   468 /* Pause play */
       
   469 static int SDL_SYS_CDPause(SDL_CD *cdrom)
       
   470 {
       
   471     if (devctl(cdrom->id, DCMD_CAM_CDROMPAUSE, NULL, 0, NULL)!=0)
       
   472     {
       
   473        return -1;
       
   474     }
       
   475     else
       
   476     {
       
   477        return 0;
       
   478     }
       
   479 }
       
   480 
       
   481 /* Resume play */
       
   482 static int SDL_SYS_CDResume(SDL_CD *cdrom)
       
   483 {
       
   484     if (devctl(cdrom->id, DCMD_CAM_CDROMRESUME, NULL, 0, NULL)!=0)
       
   485     {
       
   486        return -1;
       
   487     }
       
   488     else
       
   489     {
       
   490        return 0;
       
   491     }
       
   492 }
       
   493 
       
   494 /* Stop play */
       
   495 static int SDL_SYS_CDStop(SDL_CD *cdrom)
       
   496 {
       
   497     if (devctl(cdrom->id, DCMD_CAM_CDROMSTOP, NULL, 0, NULL)!=0)
       
   498     {
       
   499        return -1;
       
   500     }
       
   501     else
       
   502     {
       
   503        return 0;
       
   504     }
       
   505 }
       
   506 
       
   507 /* Eject the CD-ROM */
       
   508 static int SDL_SYS_CDEject(SDL_CD *cdrom)
       
   509 {
       
   510     if (devctl(cdrom->id, DCMD_CAM_EJECT_MEDIA, NULL, 0, NULL)!=0)
       
   511     {
       
   512        return -1;
       
   513     }
       
   514     else
       
   515     {
       
   516        return 0;
       
   517     }
       
   518 }
       
   519 
       
   520 /* Close the CD-ROM handle */
       
   521 static void SDL_SYS_CDClose(SDL_CD *cdrom)
       
   522 {
       
   523     int i;
       
   524 
       
   525     for (i=0; i<MAX_DRIVES; i++)
       
   526     {
       
   527        if (SDL_cdopen[i]==cdrom->id)
       
   528        {
       
   529            SDL_cdopen[i]=0;
       
   530            break;
       
   531        }
       
   532     }
       
   533 
       
   534     close(cdrom->id);
       
   535 }
       
   536 
       
   537 void SDL_SYS_CDQuit(void)
       
   538 {
       
   539     int i;
       
   540 
       
   541     if (SDL_numcds > 0)
       
   542     {
       
   543         for (i=0; i<SDL_numcds; ++i)
       
   544         {
       
   545             SDL_free(SDL_cdlist[i]);
       
   546         }
       
   547         SDL_numcds = 0;
       
   548     }
       
   549 }
       
   550 
       
   551 #endif /* SDL_CDROM_QNX */