]> git.sesse.net Git - vlc/blob - src/interface/intf_eject.c
* ./bootstrap: bootstrap now requires the --config flag. With no arguments
[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.18 2002/11/13 20:51:05 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 = VLC_SUCCESS;
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 VLC_EGENERIC;
156
157 #elif defined(UNDER_CE)
158     msg_Warn( p_this, "CD-Rom ejection unsupported on this platform" );
159     return i_ret;
160
161 #elif defined(WIN32)
162     HANDLE h_drive ;
163     TCHAR  psz_drive_id[8] ;
164     DWORD  dw_access_flags = GENERIC_READ ;
165     DWORD  dw_result ;
166     LPTSTR psz_volume_format = TEXT("\\\\.\\%s") ;
167     BYTE   by_drive ;
168     DIOC_REGISTERS regs = {0} ;
169     
170     /* Win2K ejection code */
171     if ( GetVersion() < 0x80000000 )
172     {
173         wsprintf(psz_drive_id, psz_volume_format, psz_device) ;
174          
175         msg_Dbg( p_this, "ejecting drive %s", psz_drive_id );
176         
177         /* Create the file handle */ 
178         h_drive = CreateFile(  psz_drive_id, 
179                                dw_access_flags, 
180                                FILE_SHARE_READ | FILE_SHARE_WRITE,
181                                NULL,
182                                OPEN_EXISTING,
183                                0,
184                                NULL );
185
186         if (h_drive == INVALID_HANDLE_VALUE )
187         {
188             msg_Err( p_this, "could not create handle for device %s",
189                              psz_device );
190         }
191
192         i_ret = DeviceIoControl ( h_drive, 
193                                  IOCTL_STORAGE_EJECT_MEDIA,
194                                  NULL, 0,
195                                  NULL, 0, 
196                                  &dw_result, 
197                                  NULL);
198         return (i_ret) ;
199     }
200     else        /* Win95/98/ME */
201     {
202         /* Create the handle to VWIN32 */
203         h_drive = CreateFile ("\\\\.\\vwin32", 0, 0, NULL, 0,
204                               FILE_FLAG_DELETE_ON_CLOSE, NULL ) ;
205         
206         /* Convert logical disk name to DOS-like disk name */
207         by_drive = (toupper (*psz_device) - 'A') + 1;
208
209         /* Let's eject now : Int 21H function 440DH minor code 49h*/
210         regs.reg_EAX = 0x440D ;                        
211         regs.reg_EBX = by_drive ;
212         regs.reg_ECX = MAKEWORD(0x49 , 0x08) ;        // minor code
213
214         i_ret = DeviceIoControl (h_drive, VWIN32_DIOC_DOS_IOCTL,
215                                  &regs, sizeof(regs), &regs, sizeof(regs),
216                                  &dw_result, 0) ;
217
218         CloseHandle (h_drive) ;
219         return (i_ret) ;
220     }
221
222 #else   /* WIN32 */
223
224     int i_fd;
225
226     /* This code could be extended to support CD/DVD-ROM chargers */
227
228     i_fd = open( psz_device, O_RDONLY | O_NONBLOCK );
229    
230     if( i_fd == -1 )
231     {
232         msg_Err( p_this, "could not open device %s", psz_device );
233         return VLC_EGENERIC;
234     }
235
236 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
237     /* Try a simple ATAPI eject */
238     i_ret = ioctl( i_fd, CDROMEJECT, 0 );
239
240     if( i_ret != 0 )
241     {
242         i_ret = EjectSCSI( i_fd );
243     }
244
245     if( i_ret != 0 )
246     {
247         msg_Err( p_this, "could not eject %s", psz_device );
248     }
249
250 #elif defined (HAVE_DVD_H)
251     i_ret = ioctl( i_fd, CDROMEJECT, 0 );
252
253 #else
254     msg_Warn( p_this, "CD-Rom ejection unsupported on this platform" );
255     i_ret = -1;
256
257 #endif
258     close( i_fd );
259
260     return i_ret;
261 #endif
262 }
263
264 /* The following functions are local */
265
266 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
267 /*****************************************************************************
268  * Eject using SCSI commands. Return 0 if successful
269  *****************************************************************************/
270 static int EjectSCSI( int i_fd )
271 {
272     int i_status;
273
274     struct sdata
275     {
276         int  inlen;
277         int  outlen;
278         char cmd[256];
279     } scsi_cmd;
280
281     scsi_cmd.inlen  = 0;
282     scsi_cmd.outlen = 0;
283     scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
284     scsi_cmd.cmd[1] = 0;
285     scsi_cmd.cmd[2] = 0;
286     scsi_cmd.cmd[3] = 0;
287     scsi_cmd.cmd[4] = 0;
288     scsi_cmd.cmd[5] = 0;
289     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
290     if( i_status != 0 )
291     {
292         return VLC_EGENERIC;
293     }
294
295     scsi_cmd.inlen  = 0;
296     scsi_cmd.outlen = 0;
297     scsi_cmd.cmd[0] = START_STOP;
298     scsi_cmd.cmd[1] = 0;
299     scsi_cmd.cmd[2] = 0;
300     scsi_cmd.cmd[3] = 0;
301     scsi_cmd.cmd[4] = 1;
302     scsi_cmd.cmd[5] = 0;
303     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
304     if( i_status != 0 )
305     {
306         return VLC_EGENERIC;
307     }
308   
309     scsi_cmd.inlen  = 0;
310     scsi_cmd.outlen = 0;
311     scsi_cmd.cmd[0] = START_STOP;
312     scsi_cmd.cmd[1] = 0;
313     scsi_cmd.cmd[2] = 0;
314     scsi_cmd.cmd[3] = 0;
315     scsi_cmd.cmd[4] = 2;
316     scsi_cmd.cmd[5] = 0;
317     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
318     if( i_status != 0 )
319     {
320         return VLC_EGENERIC;
321     }
322   
323     /* Force kernel to reread partition table when new disc inserted */
324     i_status = ioctl( i_fd, BLKRRPART );
325   
326     return i_status;
327 }
328 #endif
329