]> git.sesse.net Git - vlc/blob - src/interface/intf_eject.c
Remember not to include anything before vlc/vlc.h
[vlc] / src / interface / intf_eject.c
1 #include <vlc/vlc.h>
2
3 #ifdef HAVE_UNISTD_H
4 #    include <unistd.h>
5 #endif
6
7 #include <string.h>
8
9 #ifdef HAVE_FCNTL_H
10 #   include <fcntl.h>
11 #endif
12
13 #ifdef HAVE_DVD_H
14 #   include <dvd.h>
15 #endif
16
17 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
18 #   include <linux/version.h>
19     /* handy macro found in 2.1 kernels, but not in older ones */
20 #   ifndef KERNEL_VERSION
21 #       define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
22 #   endif
23
24 #   include <sys/types.h>
25 #   include <sys/stat.h>
26 #   include <sys/ioctl.h>
27
28 #   include <sys/ioctl.h>
29 #   include <sys/mount.h>
30
31 #   include <linux/cdrom.h>
32 #   if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
33        include <linux/ucdrom.h>
34 #   endif
35
36 #   include <scsi/scsi.h>
37 #   include <scsi/sg.h>
38 #   include <scsi/scsi_ioctl.h>
39 #endif
40
41 #if defined( WIN32 ) && !defined( UNDER_CE )
42 #   include <mmsystem.h>
43 #endif
44
45 #include <vlc_interface.h>
46
47 /*****************************************************************************
48  * Local prototypes
49  *****************************************************************************/
50 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
51 static int EjectSCSI ( int i_fd );
52 #endif
53
54 /*****************************************************************************
55  * intf_Eject: eject the CDRom
56  *****************************************************************************
57  * returns 0 on success
58  * returns 1 on failure
59  * returns -1 if not implemented
60  *****************************************************************************/
61 /**
62  * \brief Ejects the CD /DVD
63  * \ingroup vlc_interface
64  * \param p_this the calling vlc_object_t
65  * \param psz_device the CD/DVD to eject
66  * \return 0 on success, 1 on failure, -1 if not implemented
67  */
68 int __intf_Eject( vlc_object_t *p_this, const char *psz_device )
69 {
70     int i_ret = VLC_SUCCESS;
71
72 #ifdef __APPLE__
73     FILE *p_eject;
74     char *psz_disk;
75     char sz_cmd[32];
76
77     /*
78      * The only way to cleanly unmount the disc under MacOS X
79      * is to use the 'disktool' command line utility. It uses
80      * the non-public Disk Arbitration API, which can not be
81      * used by Cocoa or Carbon applications.
82      */
83
84     if( ( psz_disk = (char *)strstr( psz_device, "disk" ) ) != NULL &&
85         strlen( psz_disk ) > 4 )
86     {
87 #define EJECT_CMD "/usr/sbin/disktool -e %s 0"
88         snprintf( sz_cmd, sizeof(sz_cmd), EJECT_CMD, psz_disk );
89 #undef EJECT_CMD
90
91         if( ( p_eject = popen( sz_cmd, "r" ) ) != NULL )
92         {
93             char psz_result[0x200];
94             i_ret = fread( psz_result, 1, sizeof(psz_result) - 1, p_eject );
95
96             if( i_ret == 0 && ferror( p_eject ) != 0 )
97             {
98                 pclose( p_eject );
99                 return VLC_EGENERIC;
100             }
101
102             pclose( p_eject );
103
104             psz_result[ i_ret ] = 0;
105
106             if( strstr( psz_result, "Disk Ejected" ) != NULL )
107             {
108                 return VLC_SUCCESS;
109             }
110         }
111     }
112
113     return VLC_EGENERIC;
114
115 #elif defined(UNDER_CE)
116     msg_Warn( p_this, "CD-Rom ejection unsupported on this platform" );
117     return i_ret;
118
119 #elif defined(WIN32)
120     MCI_OPEN_PARMS op;
121     MCI_STATUS_PARMS st;
122     DWORD i_flags;
123     char psz_drive[4];
124
125     memset( &op, 0, sizeof(MCI_OPEN_PARMS) );
126     op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
127
128     strcpy( psz_drive, "X:" );
129     psz_drive[0] = psz_device[0];
130     op.lpstrElementName = psz_drive;
131
132     /* Set the flags for the device type */
133     i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
134               MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE;
135
136     if( !mciSendCommand( 0, MCI_OPEN, i_flags, (unsigned long)&op ) )
137     {
138         st.dwItem = MCI_STATUS_READY;
139         /* Eject disc */
140         i_ret = mciSendCommand( op.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0 );
141         /* Release access to the device */
142         mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
143     }
144     else i_ret = VLC_EGENERIC;
145
146     return i_ret;
147 #else   /* WIN32 */
148
149     int i_fd;
150
151     /* This code could be extended to support CD/DVD-ROM chargers */
152
153     i_fd = open( psz_device, O_RDONLY | O_NONBLOCK );
154
155     if( i_fd == -1 )
156     {
157         msg_Err( p_this, "could not open device %s", psz_device );
158         return VLC_EGENERIC;
159     }
160
161 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
162     /* Try a simple ATAPI eject */
163     i_ret = ioctl( i_fd, CDROMEJECT, 0 );
164
165     if( i_ret != 0 )
166     {
167         i_ret = EjectSCSI( i_fd );
168     }
169
170     if( i_ret != 0 )
171     {
172         msg_Err( p_this, "could not eject %s", psz_device );
173     }
174
175 #elif defined (HAVE_DVD_H)
176     i_ret = ioctl( i_fd, CDROMEJECT, 0 );
177
178 #else
179     msg_Warn( p_this, "CD-ROM ejection unsupported on this platform" );
180     i_ret = -1;
181
182 #endif
183     close( i_fd );
184
185     return i_ret;
186 #endif
187 }
188
189 /* The following functions are local */
190
191 #if defined(SYS_LINUX) && defined(HAVE_LINUX_VERSION_H)
192 /*****************************************************************************
193  * Eject using SCSI commands. Return 0 if successful
194  *****************************************************************************/
195 /**
196  * \brief Ejects the CD /DVD using SCSI commands
197  * \ingroup vlc_interface
198  * This function is local
199  * \param i_fd a device nummber
200  * \return 0 on success, VLC_EGENERIC on failure
201  */
202 static int EjectSCSI( int i_fd )
203 {
204     int i_status;
205
206     struct sdata
207     {
208         int  inlen;
209         int  outlen;
210         char cmd[256];
211     } scsi_cmd;
212
213     scsi_cmd.inlen  = 0;
214     scsi_cmd.outlen = 0;
215     scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
216     scsi_cmd.cmd[1] = 0;
217     scsi_cmd.cmd[2] = 0;
218     scsi_cmd.cmd[3] = 0;
219     scsi_cmd.cmd[4] = 0;
220     scsi_cmd.cmd[5] = 0;
221     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
222     if( i_status != 0 )
223     {
224         return VLC_EGENERIC;
225     }
226
227     scsi_cmd.inlen  = 0;
228     scsi_cmd.outlen = 0;
229     scsi_cmd.cmd[0] = START_STOP;
230     scsi_cmd.cmd[1] = 0;
231     scsi_cmd.cmd[2] = 0;
232     scsi_cmd.cmd[3] = 0;
233     scsi_cmd.cmd[4] = 1;
234     scsi_cmd.cmd[5] = 0;
235     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
236     if( i_status != 0 )
237     {
238         return VLC_EGENERIC;
239     }
240
241     scsi_cmd.inlen  = 0;
242     scsi_cmd.outlen = 0;
243     scsi_cmd.cmd[0] = START_STOP;
244     scsi_cmd.cmd[1] = 0;
245     scsi_cmd.cmd[2] = 0;
246     scsi_cmd.cmd[3] = 0;
247     scsi_cmd.cmd[4] = 2;
248     scsi_cmd.cmd[5] = 0;
249     i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
250     if( i_status != 0 )
251     {
252         return VLC_EGENERIC;
253     }
254
255     /* Force kernel to reread partition table when new disc inserted */
256     i_status = ioctl( i_fd, BLKRRPART );
257
258     return i_status;
259 }
260 #endif
261