]> git.sesse.net Git - vlc/blob - src/interface/intf_eject.c
* ALL: WinCE compilation fixes (mostly nonexistent headers). A lot of
[vlc] / src / interface / intf_eject.c
1 /*****************************************************************************
2  * intf_eject.c: CD/DVD-ROM ejection handling functions
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: intf_eject.c,v 1.16 2002/11/10 18:04:23 sam Exp $
6  *
7  * Author: Julien Blache <jb@technologeek.org> for the Linux part
8  *               with code taken from the Linux "eject" command
9  *         Jon Lech Johansen <jon-vl@nanocrew.net> for Darwin
10  *         Xavier Marchesini <xav@alarue.net> for Win32
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 #include <vlc/vlc.h>
28
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #ifdef HAVE_UNISTD_H
33 #    include <unistd.h>
34 #endif
35
36 #include <string.h>
37
38 #ifdef HAVE_FCNTL_H
39 #   include <fcntl.h>
40 #endif
41
42 #ifdef HAVE_DVD_H
43 #   include <dvd.h>
44 #endif
45
46 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
47 #   include <linux/version.h>
48     /* handy macro found in 2.1 kernels, but not in older ones */
49 #   ifndef KERNEL_VERSION
50 #       define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
51 #   endif
52
53 #   include <sys/types.h>
54 #   include <sys/stat.h>
55 #   include <sys/ioctl.h>
56
57 #   include <sys/ioctl.h>
58 #   include <sys/mount.h>
59
60 #   include <linux/cdrom.h>
61 #   if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
62 #       include <linux/ucdrom.h>
63 #   endif
64
65 #   include <scsi/scsi.h>
66 #   include <scsi/sg.h>
67 #   include <scsi/scsi_ioctl.h>
68 #endif
69
70 #if defined( WIN32 ) && !defined( UNDER_CE )
71 #   include <windows.h>
72 #   include <stdio.h>
73 #   include <winioctl.h>
74 #   include <ctype.h>
75 #   include <tchar.h>
76
77 /* define the structures to eject under Win95/98/Me */
78
79 #if !defined (VWIN32_DIOC_DOS_IOCTL)
80 #define VWIN32_DIOC_DOS_IOCTL      1
81
82 typedef struct _DIOC_REGISTERS {
83     DWORD reg_EBX;
84     DWORD reg_EDX;
85     DWORD reg_ECX;
86     DWORD reg_EAX;
87     DWORD reg_EDI;
88     DWORD reg_ESI;
89     DWORD reg_Flags;
90 } DIOC_REGISTERS, *PDIOC_REGISTERS;
91 #endif    /* VWIN32_DIOC_DOS_IOCTL */
92
93 #endif
94
95
96 /*****************************************************************************
97  * Local prototypes
98  *****************************************************************************/
99 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
100 static int EjectSCSI ( int i_fd );
101 #endif
102
103 /*****************************************************************************
104  * intf_Eject: eject the CDRom
105  *****************************************************************************
106  * returns 0 on success
107  * returns 1 on failure
108  * returns -1 if not implemented
109  *****************************************************************************/
110 int __intf_Eject( vlc_object_t *p_this, const char *psz_device )
111 {
112     int i_ret;
113
114 #ifdef SYS_DARWIN
115     FILE *p_eject;
116     char *psz_disk;
117     char sz_cmd[32];
118
119     /*
120      * The only way to cleanly unmount the disc under MacOS X
121      * is to use the 'disktool' command line utility. It uses
122      * the non-public Disk Arbitration API, which can not be
123      * used by Cocoa or Carbon applications. 
124      */
125
126     if( ( psz_disk = (char *)strstr( psz_device, "disk" ) ) != NULL &&
127         strlen( psz_disk ) > 4 )
128     {
129 #define EJECT_CMD "/usr/sbin/disktool -e %s 0"
130         snprintf( sz_cmd, sizeof(sz_cmd), EJECT_CMD, psz_disk );
131 #undef EJECT_CMD
132
133         if( ( p_eject = popen( sz_cmd, "r" ) ) != NULL )
134         {
135             char psz_result[0x200];
136             i_ret = fread( psz_result, 1, sizeof(psz_result) - 1, p_eject );
137
138             if( i_ret == 0 && ferror( p_eject ) != 0 )
139             {
140                 pclose( p_eject );
141                 return VLC_EGENERIC;
142             }
143
144             pclose( p_eject );
145
146             psz_result[ i_ret ] = 0;
147
148             if( strstr( psz_result, "Disk Ejected" ) != NULL )
149             {
150                 return VLC_SUCCESS;
151             }
152         }
153     }
154
155     return 1;
156
157 #elif defined(WIN32)
158
159 #if defined(UNDER_CE)
160     msg_Warn( p_this, "CD-Rom ejection unsupported on this platform" );
161     i_ret = -1;
162     
163 #else
164     HANDLE h_drive ;
165     TCHAR  psz_drive_id[8] ;
166     DWORD  dw_access_flags = GENERIC_READ ;
167     DWORD  dw_result ;
168     LPTSTR psz_volume_format = TEXT("\\\\.\\%s") ;
169     BYTE   by_drive ;
170     DIOC_REGISTERS regs = {0} ;
171     
172     /* Win2K ejection code */
173     if ( GetVersion() < 0x80000000 )
174     {
175         wsprintf(psz_drive_id, psz_volume_format, psz_device) ;
176          
177         msg_Dbg( p_this, "ejecting drive %s", psz_drive_id );
178         
179         /* Create the file handle */ 
180         h_drive = CreateFile(  psz_drive_id, 
181                                dw_access_flags, 
182                                FILE_SHARE_READ | FILE_SHARE_WRITE,
183                                NULL,
184                                OPEN_EXISTING,
185                                0,
186                                NULL );
187
188         if (h_drive == INVALID_HANDLE_VALUE )
189         {
190             msg_Err( p_this, "could not create handle for device %s",
191                              psz_device );
192         }
193
194         i_ret = DeviceIoControl ( h_drive, 
195                                  IOCTL_STORAGE_EJECT_MEDIA,
196                                  NULL, 0,
197                                  NULL, 0, 
198                                  &dw_result, 
199                                  NULL);
200         return (i_ret) ;
201     }
202     else        /* Win95/98/ME */
203     {
204         /* Create the handle to VWIN32 */
205         h_drive = CreateFile ("\\\\.\\vwin32", 0, 0, NULL, 0,
206                               FILE_FLAG_DELETE_ON_CLOSE, NULL ) ;
207         
208         /* Convert logical disk name to DOS-like disk name */
209         by_drive = (toupper (*psz_device) - 'A') + 1;
210
211         /* Let's eject now : Int 21H function 440DH minor code 49h*/
212         regs.reg_EAX = 0x440D ;                        
213         regs.reg_EBX = by_drive ;
214         regs.reg_ECX = MAKEWORD(0x49 , 0x08) ;        // minor code
215
216         i_ret = DeviceIoControl (h_drive, VWIN32_DIOC_DOS_IOCTL,
217                                  &regs, sizeof(regs), &regs, sizeof(regs),
218                                  &dw_result, 0) ;
219
220         CloseHandle (h_drive) ;
221         return (i_ret) ;
222     }
223 #endif /* UNDER_CE */
224
225 #else   /* WIN32 */
226
227     int i_fd;
228
229     /* This code could be extended to support CD/DVD-ROM chargers */
230
231     i_fd = open( psz_device, O_RDONLY | O_NONBLOCK );
232    
233     if( i_fd == -1 )
234     {
235         msg_Err( p_this, "could not open device %s", psz_device );
236         return VLC_EGENERIC;
237     }
238
239 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
240     /* Try a simple ATAPI eject */
241     i_ret = ioctl( i_fd, CDROMEJECT, 0 );
242
243     if( i_ret != 0 )
244     {
245         i_ret = EjectSCSI( i_fd );
246     }
247
248     if( i_ret != 0 )
249     {
250         msg_Err( p_this, "could not eject %s", psz_device );
251     }
252
253 #elif defined (HAVE_DVD_H)
254     i_ret = ioctl( i_fd, CDROMEJECT, 0 );
255
256 #else
257     msg_Warn( p_this, "CD-Rom ejection unsupported on this platform" );
258     i_ret = -1;
259
260 #endif
261     close( i_fd );
262
263     return i_ret;
264 #endif
265 }
266
267 /* The following functions are local */
268
269 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
270 /*****************************************************************************
271  * Eject using SCSI commands. Return 0 if successful
272  *****************************************************************************/
273 static int EjectSCSI( int i_fd )
274 {
275     int i_status;
276
277     struct sdata
278     {
279         int  inlen;
280         int  outlen;
281         char cmd[256];
282     } scsi_cmd;
283
284     scsi_cmd.inlen  = 0;
285     scsi_cmd.outlen = 0;
286     scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
287     scsi_cmd.cmd[1] = 0;
288     scsi_cmd.cmd[2] = 0;
289     scsi_cmd.cmd[3] = 0;
290     scsi_cmd.cmd[4] = 0;
291     scsi_cmd.cmd[5] = 0;
292     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
293     if( i_status != 0 )
294     {
295         return VLC_EGENERIC;
296     }
297
298     scsi_cmd.inlen  = 0;
299     scsi_cmd.outlen = 0;
300     scsi_cmd.cmd[0] = START_STOP;
301     scsi_cmd.cmd[1] = 0;
302     scsi_cmd.cmd[2] = 0;
303     scsi_cmd.cmd[3] = 0;
304     scsi_cmd.cmd[4] = 1;
305     scsi_cmd.cmd[5] = 0;
306     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
307     if( i_status != 0 )
308     {
309         return VLC_EGENERIC;
310     }
311   
312     scsi_cmd.inlen  = 0;
313     scsi_cmd.outlen = 0;
314     scsi_cmd.cmd[0] = START_STOP;
315     scsi_cmd.cmd[1] = 0;
316     scsi_cmd.cmd[2] = 0;
317     scsi_cmd.cmd[3] = 0;
318     scsi_cmd.cmd[4] = 2;
319     scsi_cmd.cmd[5] = 0;
320     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
321     if( i_status != 0 )
322     {
323         return VLC_EGENERIC;
324     }
325   
326     /* Force kernel to reread partition table when new disc inserted */
327     i_status = ioctl( i_fd, BLKRRPART );
328   
329     return i_status;
330 }
331 #endif
332