Mercurial > sdl-ios-xcode
annotate src/cdrom/freebsd/SDL_syscdrom.c @ 4167:a6f635e5eaa6 SDL-1.2
Fixed bug #611
From Tim Angus 2008-08-12 11:18:06
I'm one of the maintainers of ioquake3.org, an updated version of the
Quake 3 engine. Relatively recently, we moved ioq3 to use SDL as a
replacement for 95% of the platform specific code that was there. On the
whole it's doing a great job but unfortunately since the move we've been
getting complaints about the quality of the mouse input on the Windows
platform to the point where for many the game is unplayable. Put in
other terms, the current stable SDL 1.2 is basically not fit for purpose
if you need high quality mouse input as you do in a first person shooter.
Over the weekend I decided to pull my finger out and actually figure out
what's going on. There are basically two major problems. Firstly, when
using the "windib" driver, mouse input is gathered via the WM_MOUSEMOVE
message. Googling for this indicates that often this is known to result
in "spurious" and/or "missing" mouse movement events; this is the
primary cause of the poor mouse input. The second problem is that the
"directx" driver does not work at all in combination with OpenGL meaning
that you can't use DirectInput if your application also uses OpenGL. In
other words you're locked into using the "windib" driver and its poor
mouse input.
In order to address these problems I've done the following:
* Remove WM_MOUSEMOVE based motion event generation and replace with
calls to GetCursorPos which seems much more reliable. In order to
achieve this I've moved mouse motion out into a separate function that
is called once per DIB_PumpEvents.
* Remove the restriction on the "directx" driver being inoperable in
combination with OpenGL. There is a bug for this issues that I've
hijacked to a certain extent
(http://bugzilla.libsdl.org/show_bug.cgi?id=265). I'm the first to admit
I don't really understand why this restriction is there in the first
place. The commit message for the bug fix that introduced this
restriction (r581) isn't very elaborate and I couldn't see any other bug
tracking the issue. If anyone has more information on the bug that was
avoided by r581 it would be helpful as I/someone could then look into
addressing the problem without disabling the "directx" driver.
* I've also removed the restriction on not being allowed to use
DirectInput in windowed mode. I couldn't see any reason for this, at
least not from our perspective. I have my suspicions that it'll be
something like matching up the cursor with the mouse coordinates...
* I bumped up the DirectInput API used to version 7 in order to get
access to mouse buttons 4-7. I've had to inject a little bit of the DX7
headers into SDL there as the MinGW ones aren't up to date in this respect.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 02 Apr 2009 04:43:36 +0000 |
parents | a1b03ba2fcd0 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
4159 | 3 Copyright (C) 1997-2009 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 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 | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1379
diff
changeset
|
22 #include "SDL_config.h" |
0 | 23 |
1635
92947e3a18db
Make sure code is only compiled if the appropriate subsystem is enabled
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
24 #ifdef SDL_CDROM_FREEBSD |
92947e3a18db
Make sure code is only compiled if the appropriate subsystem is enabled
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
25 |
0 | 26 /* Functions for system-level CD-ROM audio control */ |
27 | |
28 #include <sys/types.h> | |
29 #include <sys/stat.h> | |
30 #include <fcntl.h> | |
31 #include <errno.h> | |
32 #include <unistd.h> | |
33 #include <sys/cdio.h> | |
34 | |
35 #include "SDL_cdrom.h" | |
1361
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
36 #include "../SDL_syscdrom.h" |
0 | 37 |
38 | |
39 /* The maximum number of CD-ROM drives we'll detect */ | |
40 #define MAX_DRIVES 16 | |
41 | |
42 /* A list of available CD-ROM drives */ | |
43 static char *SDL_cdlist[MAX_DRIVES]; | |
44 static dev_t SDL_cdmode[MAX_DRIVES]; | |
45 | |
46 /* The system-dependent CD control functions */ | |
47 static const char *SDL_SYS_CDName(int drive); | |
48 static int SDL_SYS_CDOpen(int drive); | |
49 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | |
50 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | |
51 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | |
52 static int SDL_SYS_CDPause(SDL_CD *cdrom); | |
53 static int SDL_SYS_CDResume(SDL_CD *cdrom); | |
54 static int SDL_SYS_CDStop(SDL_CD *cdrom); | |
55 static int SDL_SYS_CDEject(SDL_CD *cdrom); | |
56 static void SDL_SYS_CDClose(SDL_CD *cdrom); | |
57 | |
58 /* Some ioctl() errno values which occur when the tray is empty */ | |
59 #define ERRNO_TRAYEMPTY(errno) \ | |
60 ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL)) | |
61 | |
62 /* Check a drive to see if it is a CD-ROM */ | |
63 static int CheckDrive(char *drive, struct stat *stbuf) | |
64 { | |
65 int is_cd, cdfd; | |
66 struct ioc_read_subchannel info; | |
67 | |
68 /* If it doesn't exist, return -1 */ | |
69 if ( stat(drive, stbuf) < 0 ) { | |
70 return(-1); | |
71 } | |
72 | |
73 /* If it does exist, verify that it's an available CD-ROM */ | |
74 is_cd = 0; | |
75 if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | |
76 cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | |
77 if ( cdfd >= 0 ) { | |
78 info.address_format = CD_MSF_FORMAT; | |
79 info.data_format = CD_CURRENT_POSITION; | |
80 info.data_len = 0; | |
81 info.data = NULL; | |
82 /* Under Linux, EIO occurs when a disk is not present. | |
83 This isn't 100% reliable, so we use the USE_MNTENT | |
84 code above instead. | |
85 */ | |
86 if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) || | |
87 ERRNO_TRAYEMPTY(errno) ) { | |
88 is_cd = 1; | |
89 } | |
90 close(cdfd); | |
91 } | |
92 } | |
93 return(is_cd); | |
94 } | |
95 | |
96 /* Add a CD-ROM drive to our list of valid drives */ | |
97 static void AddDrive(char *drive, struct stat *stbuf) | |
98 { | |
99 int i; | |
100 | |
101 if ( SDL_numcds < MAX_DRIVES ) { | |
102 /* Check to make sure it's not already in our list. | |
103 This can happen when we see a drive via symbolic link. | |
104 */ | |
105 for ( i=0; i<SDL_numcds; ++i ) { | |
106 if ( stbuf->st_rdev == SDL_cdmode[i] ) { | |
107 #ifdef DEBUG_CDROM | |
108 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | |
109 #endif | |
110 return; | |
111 } | |
112 } | |
113 | |
114 /* Add this drive to our list */ | |
115 i = SDL_numcds; | |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
116 SDL_cdlist[i] = SDL_strdup(drive); |
0 | 117 if ( SDL_cdlist[i] == NULL ) { |
118 SDL_OutOfMemory(); | |
119 return; | |
120 } | |
121 SDL_cdmode[i] = stbuf->st_rdev; | |
122 ++SDL_numcds; | |
123 #ifdef DEBUG_CDROM | |
124 fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | |
125 #endif | |
126 } | |
127 } | |
128 | |
129 int SDL_SYS_CDInit(void) | |
130 { | |
131 /* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c | |
132 /dev/matcd?c /dev/mcd?c /dev/scd?c */ | |
133 static char *checklist[] = { | |
134 "cdrom", "?0 cd?", "?0 acd?", "?0 matcd?", "?0 mcd?", "?0 scd?",NULL | |
135 }; | |
136 char *SDLcdrom; | |
137 int i, j, exists; | |
138 char drive[32]; | |
139 struct stat stbuf; | |
140 | |
141 /* Fill in our driver capabilities */ | |
142 SDL_CDcaps.Name = SDL_SYS_CDName; | |
143 SDL_CDcaps.Open = SDL_SYS_CDOpen; | |
144 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | |
145 SDL_CDcaps.Status = SDL_SYS_CDStatus; | |
146 SDL_CDcaps.Play = SDL_SYS_CDPlay; | |
147 SDL_CDcaps.Pause = SDL_SYS_CDPause; | |
148 SDL_CDcaps.Resume = SDL_SYS_CDResume; | |
149 SDL_CDcaps.Stop = SDL_SYS_CDStop; | |
150 SDL_CDcaps.Eject = SDL_SYS_CDEject; | |
151 SDL_CDcaps.Close = SDL_SYS_CDClose; | |
152 | |
153 /* Look in the environment for our CD-ROM drive list */ | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
154 SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ |
0 | 155 if ( SDLcdrom != NULL ) { |
156 char *cdpath, *delim; | |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
157 size_t len = SDL_strlen(SDLcdrom)+1; |
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
158 cdpath = SDL_stack_alloc(char, len); |
0 | 159 if ( cdpath != NULL ) { |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
160 SDL_strlcpy(cdpath, SDLcdrom, len); |
0 | 161 SDLcdrom = cdpath; |
162 do { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
163 delim = SDL_strchr(SDLcdrom, ':'); |
0 | 164 if ( delim ) { |
165 *delim++ = '\0'; | |
166 } | |
167 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | |
168 AddDrive(SDLcdrom, &stbuf); | |
169 } | |
170 if ( delim ) { | |
171 SDLcdrom = delim; | |
172 } else { | |
173 SDLcdrom = NULL; | |
174 } | |
175 } while ( SDLcdrom ); | |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
176 SDL_stack_free(cdpath); |
0 | 177 } |
178 | |
179 /* If we found our drives, there's nothing left to do */ | |
180 if ( SDL_numcds > 0 ) { | |
181 return(0); | |
182 } | |
183 } | |
184 | |
185 /* Scan the system for CD-ROM drives */ | |
186 for ( i=0; checklist[i]; ++i ) { | |
187 if ( checklist[i][0] == '?' ) { | |
188 char *insert; | |
189 exists = 1; | |
190 for ( j=checklist[i][1]; exists; ++j ) { | |
1338
604d73db6802
Removed uses of stdlib.h and string.h
Sam Lantinga <slouken@libsdl.org>
parents:
1336
diff
changeset
|
191 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]); |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
192 insert = SDL_strchr(drive, '?'); |
0 | 193 if ( insert != NULL ) { |
194 *insert = j; | |
195 } | |
196 switch (CheckDrive(drive, &stbuf)) { | |
197 /* Drive exists and is a CD-ROM */ | |
198 case 1: | |
199 AddDrive(drive, &stbuf); | |
200 break; | |
201 /* Drive exists, but isn't a CD-ROM */ | |
202 case 0: | |
203 break; | |
204 /* Drive doesn't exist */ | |
205 case -1: | |
206 exists = 0; | |
207 break; | |
208 } | |
209 } | |
210 } else { | |
1338
604d73db6802
Removed uses of stdlib.h and string.h
Sam Lantinga <slouken@libsdl.org>
parents:
1336
diff
changeset
|
211 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); |
0 | 212 if ( CheckDrive(drive, &stbuf) > 0 ) { |
213 AddDrive(drive, &stbuf); | |
214 } | |
215 } | |
216 } | |
217 return(0); | |
218 } | |
219 | |
220 /* General ioctl() CD-ROM command function */ | |
221 static int SDL_SYS_CDioctl(int id, int command, void *arg) | |
222 { | |
223 int retval; | |
224 | |
225 retval = ioctl(id, command, arg); | |
226 if ( retval < 0 ) { | |
227 SDL_SetError("ioctl() error: %s", strerror(errno)); | |
228 } | |
229 return(retval); | |
230 } | |
231 | |
232 static const char *SDL_SYS_CDName(int drive) | |
233 { | |
234 return(SDL_cdlist[drive]); | |
235 } | |
236 | |
237 static int SDL_SYS_CDOpen(int drive) | |
238 { | |
239 return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0)); | |
240 } | |
241 | |
242 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | |
243 { | |
244 struct ioc_toc_header toc; | |
245 int i, okay; | |
246 struct ioc_read_toc_entry entry; | |
247 struct cd_toc_entry data; | |
248 | |
249 okay = 0; | |
250 if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) { | |
251 cdrom->numtracks = toc.ending_track-toc.starting_track+1; | |
252 if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | |
253 cdrom->numtracks = SDL_MAX_TRACKS; | |
254 } | |
255 /* Read all the track TOC entries */ | |
256 for ( i=0; i<=cdrom->numtracks; ++i ) { | |
257 if ( i == cdrom->numtracks ) { | |
258 cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */ | |
259 } else { | |
260 cdrom->track[i].id = toc.starting_track+i; | |
261 } | |
262 entry.starting_track = cdrom->track[i].id; | |
263 entry.address_format = CD_MSF_FORMAT; | |
264 entry.data_len = sizeof(data); | |
265 entry.data = &data; | |
266 if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, | |
267 &entry) < 0 ) { | |
268 break; | |
269 } else { | |
270 cdrom->track[i].type = data.control; | |
271 cdrom->track[i].offset = MSF_TO_FRAMES( | |
272 data.addr.msf.minute, | |
273 data.addr.msf.second, | |
274 data.addr.msf.frame); | |
275 cdrom->track[i].length = 0; | |
276 if ( i > 0 ) { | |
277 cdrom->track[i-1].length = | |
278 cdrom->track[i].offset- | |
279 cdrom->track[i-1].offset; | |
280 } | |
281 } | |
282 } | |
283 if ( i == (cdrom->numtracks+1) ) { | |
284 okay = 1; | |
285 } | |
286 } | |
287 return(okay ? 0 : -1); | |
288 } | |
289 | |
290 /* Get CD-ROM status */ | |
291 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | |
292 { | |
293 CDstatus status; | |
294 struct ioc_toc_header toc; | |
295 struct ioc_read_subchannel info; | |
296 struct cd_sub_channel_info data; | |
297 | |
298 info.address_format = CD_MSF_FORMAT; | |
299 info.data_format = CD_CURRENT_POSITION; | |
300 info.track = 0; | |
301 info.data_len = sizeof(data); | |
302 info.data = &data; | |
303 if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) { | |
304 if ( ERRNO_TRAYEMPTY(errno) ) { | |
305 status = CD_TRAYEMPTY; | |
306 } else { | |
307 status = CD_ERROR; | |
308 } | |
309 } else { | |
310 switch (data.header.audio_status) { | |
311 case CD_AS_AUDIO_INVALID: | |
312 case CD_AS_NO_STATUS: | |
313 /* Try to determine if there's a CD available */ | |
314 if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0) | |
315 status = CD_STOPPED; | |
316 else | |
317 status = CD_TRAYEMPTY; | |
318 break; | |
319 case CD_AS_PLAY_COMPLETED: | |
320 status = CD_STOPPED; | |
321 break; | |
322 case CD_AS_PLAY_IN_PROGRESS: | |
323 status = CD_PLAYING; | |
324 break; | |
325 case CD_AS_PLAY_PAUSED: | |
326 status = CD_PAUSED; | |
327 break; | |
328 default: | |
329 status = CD_ERROR; | |
330 break; | |
331 } | |
332 } | |
333 if ( position ) { | |
334 if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | |
335 *position = MSF_TO_FRAMES( | |
336 data.what.position.absaddr.msf.minute, | |
337 data.what.position.absaddr.msf.second, | |
338 data.what.position.absaddr.msf.frame); | |
339 } else { | |
340 *position = 0; | |
341 } | |
342 } | |
343 return(status); | |
344 } | |
345 | |
346 /* Start play */ | |
347 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | |
348 { | |
349 struct ioc_play_msf playtime; | |
350 | |
351 FRAMES_TO_MSF(start, | |
352 &playtime.start_m, &playtime.start_s, &playtime.start_f); | |
353 FRAMES_TO_MSF(start+length, | |
354 &playtime.end_m, &playtime.end_s, &playtime.end_f); | |
355 #ifdef DEBUG_CDROM | |
356 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | |
357 playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | |
358 playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | |
359 #endif | |
360 ioctl(cdrom->id, CDIOCSTART, 0); | |
361 return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime)); | |
362 } | |
363 | |
364 /* Pause play */ | |
365 static int SDL_SYS_CDPause(SDL_CD *cdrom) | |
366 { | |
367 return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0)); | |
368 } | |
369 | |
370 /* Resume play */ | |
371 static int SDL_SYS_CDResume(SDL_CD *cdrom) | |
372 { | |
373 return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0)); | |
374 } | |
375 | |
376 /* Stop play */ | |
377 static int SDL_SYS_CDStop(SDL_CD *cdrom) | |
378 { | |
379 return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0)); | |
380 } | |
381 | |
382 /* Eject the CD-ROM */ | |
383 static int SDL_SYS_CDEject(SDL_CD *cdrom) | |
384 { | |
385 return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0)); | |
386 } | |
387 | |
388 /* Close the CD-ROM handle */ | |
389 static void SDL_SYS_CDClose(SDL_CD *cdrom) | |
390 { | |
391 close(cdrom->id); | |
392 } | |
393 | |
394 void SDL_SYS_CDQuit(void) | |
395 { | |
396 int i; | |
397 | |
398 if ( SDL_numcds > 0 ) { | |
399 for ( i=0; i<SDL_numcds; ++i ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
400 SDL_free(SDL_cdlist[i]); |
0 | 401 } |
402 SDL_numcds = 0; | |
403 } | |
404 } | |
405 | |
1635
92947e3a18db
Make sure code is only compiled if the appropriate subsystem is enabled
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
406 #endif /* SDL_CDROM_FREEBSD */ |