1 /*
2  * This file is part of WorkMan, the civilized CD player library
3  * Copyright (C) 1991-1997 by Steven Grimm <koreth@midwinter.com>
4  * Copyright (C) by Dirk Försterling <milliByte@DeathsDoor.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  *
21  * SVR4 specific.  Much of this is similar to plat_hpux.c.
22  */
23 
24 #if (defined(SVR4) || defined(__SVR4)) && !defined(sun) && !defined(__sun) && !defined(sony_news) && !defined(__sony_news)
25 
26 
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <sys/mkdev.h>
36 #include <sys/stat.h>
37 #include <sys/sdi.h>
38 #include <sys/sdi_edt.h>
39 #include <sys/scsi.h>
40 #include <errno.h>
41 
42 #include "include/wm_config.h"
43 #include "include/wm_struct.h"
44 #include "include/wm_cdtext.h"
45 
46 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
47 
48 
49 void *malloc();
50 char *strchr();
51 
52 int	min_volume = 0;
53 int	max_volume = 255;
54 
55 static int
create_cdrom_node(char * dev_name)56 create_cdrom_node(char *dev_name)
57 {
58   char pass_through[100];
59   int file_des;
60   dev_t pass_thru_device;
61   int err;
62   int ccode;
63 
64 
65   strncpy(pass_through, dev_name, sizeof(pass_through) - 2);
66   pass_through[sizeof(pass_through) - 2] = '\0';
67   strcat(pass_through, "p" );
68 
69   if (setreuid(-1,0) < 0)
70     {
71       perror("setregid/setreuid/access");
72       return -1;
73     }
74 
75   ccode = access(pass_through, F_OK);
76 
77   if (ccode < 0)
78     {
79       if ((file_des = open(dev_name, O_RDONLY)) < 0)
80 	{
81 	  perror("open cdrom devices failed");
82 	  return -1;
83 	}
84 
85       if (ioctl(file_des, B_GETDEV, &pass_thru_device) < 0)
86 	{
87 	  perror("Call to get pass-through device number failed");
88 	  return -1;
89 	}
90 
91       (void)close(file_des);
92 
93       if (mknod(pass_through, (S_IFCHR | S_IREAD | S_IWRITE),
94 		pass_thru_device) < 0)
95 	{
96 	  perror("Unable to make pass-through node");
97 	  return -1;
98 	}
99 
100       if (chown(pass_through, 0 , 0) < 0)
101 	{
102 	  perror("chown");
103 	  return -1;
104 	}
105 
106       if (chmod(pass_through, 0660 ) < 0)
107 	{
108 	  perror("chmod");
109 	  return -1;
110 	}
111     }
112 
113   file_des = open( pass_through, O_RDWR);
114   err = errno;
115 
116   if ( (setreuid(-1,getuid()) < 0) || (setregid(-1,getgid()) < 0) )
117     {
118       perror("setreuid/setregid");
119       return -1;
120     }
121   errno = err;
122   return file_des;
123 } /* create_cdrom_node() */
124 
125 const char*
find_cdrom()126 find_cdrom()
127 {
128   /*
129   ** the path of the device has to start w/ /dev
130   ** otherwise we are vulnerable to race conditions
131   ** Thomas Biege <thomas@suse.de>
132   */
133   const char* device = NULL;
134 
135   device = getenv("CDROM");
136   if ( (device != NULL) &&
137        !(strncmp("/dev/", device, 5) ||
138 	 strstr(_device, "/../") ))
139     return device;
140 
141   if (access("/dev/cdrom/cdrom1", F_OK) == 0)
142     {
143       return "/dev/cdrom/cdrom1";
144     }
145   else if (access("/dev/cdrom/cdrom2", F_OK) == 0)
146     {
147       return "/dev/cdrom/cdrom2";
148     }
149   else
150     {
151       fprintf(stderr, "Could not find a CD device!\n");
152       return NULL;
153     }
154 } /* find_cdrom() */
155 
156 /*
157  * Initialize the drive.  A no-op for the generic driver.
158  */
159 int
gen_init(struct wm_drive * d)160 gen_init(struct wm_drive *d)
161 {
162   return 0;
163 } /* gen_init() */
164 
165 /*
166  * Open the CD and figure out which kind of drive is attached.
167  */
168 int
gen_open(struct wm_drive * d)169 gen_open(struct wm_drive *d)
170 {
171 	if (d->fd >= 0) {		/* Device already open? */
172 		wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "gen_open(): [device is open (fd=%d)]\n", d->fd);
173 		return 0;
174     }
175 
176   	d->fd = create_cdrom_node(d->cd_device); /* this will do open */
177 	if (d->fd < 0) {
178 		if (errno == EACCES)
179 		else if (errno != EINTR)
180 			return -6;
181 
182 		/* No CD in drive. (Is this true also for svr4 ? XXX ) */
183 		return 1;
184     }
185 
186 	return 0;
187 } /* gen_open() */
188 
189 /*
190  * Send a SCSI command out the bus.
191  */
192 int
gen_scsi(struct wm_drive * d,unsigned char * xcdb,int cdblen,char * retbuf,int retbuflen,int getreply)193 gen_scsi( struct wm_drive *d, unsigned char *xcdb, int cdblen,
194 	 char *retbuf, int retbuflen, int getreply)
195 {
196   int ccode;
197   int file_des = d->fd;
198   int i,j;
199   unsigned char sense_buffer[ SENSE_SZ ];
200   int errno_save;
201 
202   /* getreply == 1 is read, == 0 is write */
203 
204   struct sb sb;
205   struct scs scs;
206 
207   sb.sb_type = ISCB_TYPE;
208 
209   sb.SCB.sc_comp_code = SDI_PROGRES;
210   sb.SCB.sc_int = NULL;
211   sb.SCB.sc_wd = 0;
212   sb.SCB.sc_dev.sa_major = 0;
213   sb.SCB.sc_dev.sa_minor = 0;
214   sb.SCB.sc_dev.sa_lun = 0;
215   sb.SCB.sc_dev.sa_exlun = 0;
216   sb.SCB.sc_status = 0;
217   sb.SCB.sc_link = (struct sb *) NULL;
218   sb.SCB.sc_resid = 0;
219 
220   sb.SCB.sc_cmdpt = (void *)xcdb;
221   sb.SCB.sc_cmdsz = cdblen;
222 
223   sb.SCB.sc_datapt = retbuf ;
224   sb.SCB.sc_datasz = retbuflen ;
225 
226   if (getreply == 1)
227     sb.SCB.sc_mode = SCB_READ;
228   else
229     sb.SCB.sc_mode = SCB_WRITE;
230 
231   sb.SCB.sc_time = 500;
232 
233   ccode =  ioctl(file_des, SDI_SEND,  &sb);
234 
235   if ( (sb.SCB.sc_comp_code != 0xd000000e ) ||
236        ( sb.SCB.sc_status != 02) )
237     return ccode;
238 
239   errno_save = errno;
240 
241   sb.SCB.sc_comp_code = SDI_PROGRES;
242   sb.SCB.sc_int = NULL;
243   sb.SCB.sc_wd = 0;
244   sb.SCB.sc_dev.sa_major = 0;
245   sb.SCB.sc_dev.sa_minor = 0;
246   sb.SCB.sc_dev.sa_lun = 0;
247   sb.SCB.sc_dev.sa_exlun = 0;
248   sb.SCB.sc_status = 0;
249   sb.SCB.sc_link = (struct sb *) NULL;
250   sb.SCB.sc_resid = 0;
251 
252   scs.ss_op	=	SS_REQSEN;
253   scs.ss_lun	=	0;
254   scs.ss_addr1	=	0;
255   scs.ss_addr	=	0;
256   scs.ss_len	=	SENSE_SZ;
257   scs.ss_cont	=	0;
258 
259   sb.SCB.sc_cmdpt = SCS_AD(&scs);
260   sb.SCB.sc_cmdsz = SCS_SZ;
261   sb.SCB.sc_datapt = sense_buffer;
262   sb.SCB.sc_datasz = 18;
263   sb.SCB.sc_mode = SCB_READ;
264   sb.SCB.sc_time = 5000;
265 
266   if (ioctl(file_des, SDI_SEND,  &sb) < 0)
267     {
268       fprintf(stderr,"Cannot read sense.\n");
269       exit(-1);
270     }
271 
272   errno=errno_save;
273   return -1;
274 } /* gen_scsi() */
275 
276 int
gen_close(struct wm_drive * d)277 gen_close( struct wm_drive *d )
278 {
279   if(d->fd != -1) {
280     wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "closing the device\n");
281     close(d->fd);
282     d->fd = -1;
283   }
284   return 0;
285 }
286 
287 /*
288  * Get the current status of the drive: the current play mode, the absolute
289  * position from start of disc (in frames), and the current track and index
290  * numbers if the CD is playing or paused.
291  */
292 int
gen_get_drive_status(struct wm_drive * d,int oldmode,int * mode,int * pos,int * track,int * index)293 gen_get_drive_status(struct wm_drive *d, int oldmode,
294 		     int *mode, int *pos, int *track, int *index)
295 {
296   return wm_scsi2_get_drive_status(d, oldmode, mode, pos, track, index);
297 } /* gen_get_drive_status() */
298 
299 /*
300  * Get the number of tracks on the CD.
301  */
302 int
gen_get_trackcount(struct wm_drive * d,int * tracks)303 gen_get_trackcount(struct wm_drive *d, int *tracks)
304 {
305   return wm_scsi2_get_trackcount(d, tracks);
306 } /* gen_get_trackcount() */
307 
308 /*
309  * Get the start time and mode (data or audio) of a track.
310  */
311 int
gen_get_trackinfo(struct wm_drive * d,int track,int * data,int * startframe)312 gen_get_trackinfo(struct wm_drive *d, int track, int *data, int *startframe)
313 {
314   return wm_scsi2_get_trackinfo(d, track, data, startframe);
315 } /* gen_get_trackinfo() */
316 
317 /*
318  * Get the number of frames on the CD.
319  */
320 int
gen_get_cdlen(struct wm_drive * d,int * frames)321 gen_get_cdlen(struct wm_drive *d, int *frames)
322 {
323   int tmp;
324 
325   return wm_scsi2_get_cdlen(d, frames);
326 } /* gen_get_cdlen() */
327 
328 /*
329  * Play the CD from one position to another (both in frames.)
330  */
331 int
gen_play(struct wm_drive * d,int start,int end)332 gen_play(struct wm_drive *d, int start, int end)
333 {
334   return wm_scsi2_play(d, start, end);
335 } /* gen_play() */
336 
337 /*
338  * Pause the CD.
339  */
340 int
gen_pause(struct wm_drive * d)341 gen_pause(struct wm_drive *d)
342 {
343   return wm_scsi2_pause(d);
344 } /* gen_pause() */
345 
346 /*
347  * Resume playing the CD (assuming it was paused.)
348  */
349 int
gen_resume(struct wm_drive * d)350 gen_resume(struct wm_drive *d)
351 {
352   return wm_scsi2_resume(d);
353 } /* gen_resume() */
354 
355 /*
356  * Stop the CD.
357  */
358 int
gen_stop(struct wm_drive * d)359 gen_stop(struct wm_drive *d)
360 {
361   return wm_scsi2_stop(d);
362 } /* gen_stop() */
363 
364 
365 /*
366  * Eject the current CD, if there is one.
367  */
368 int
gen_eject(struct wm_drive * d)369 gen_eject(struct wm_drive *d)
370 {
371   return wm_scsi2_eject(d);
372 } /* gen_eject() */
373 
374 /*
375  * Close the tray.
376  * please review scsi.c / wm_scsi2_closetray()
377  * and send changes to milliByte@DeathsDoor.com
378  */
379 int
gen_closetray(struct wm_drive * d)380 gen_closetray( struct wm_drive *d )
381 {
382   return wm_scsi2_closetray(d);
383 } /* gen_closetray() */
384 
385 
386 /*
387  * Set the volume level for the left and right channels.  Their values
388  * range from 0 to 100.
389  */
390 int
gen_set_volume(struct wm_drive * d,int left,int right)391 gen_set_volume(struct wm_drive *d, int left, int right)
392 {
393   return wm_scsi2_set_volume(d, left, right);
394 } /* gen_set_volume() */
395 
396 /*
397  * Read the initial volume from the drive, if available.  Each channel
398  * ranges from 0 to 100, with -1 indicating data not available.
399  */
400 int
gen_get_volume(struct wm_drive * d,int * left,int * right)401 gen_get_volume(struct wm_drive *d, int *left, int *right)
402 {
403   return wm_scsi2_get_volume(d, left, right);
404 } /* gen_get_volume() */
405 
406 #endif
407