diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/cdrom |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/cdrom')
-rw-r--r-- | drivers/cdrom/Kconfig | 213 | ||||
-rw-r--r-- | drivers/cdrom/Makefile | 23 | ||||
-rw-r--r-- | drivers/cdrom/aztcd.c | 2494 | ||||
-rw-r--r-- | drivers/cdrom/aztcd.h | 162 | ||||
-rw-r--r-- | drivers/cdrom/cdrom.c | 3397 | ||||
-rw-r--r-- | drivers/cdrom/cdu31a.c | 3248 | ||||
-rw-r--r-- | drivers/cdrom/cdu31a.h | 411 | ||||
-rw-r--r-- | drivers/cdrom/cm206.c | 1626 | ||||
-rw-r--r-- | drivers/cdrom/cm206.h | 171 | ||||
-rw-r--r-- | drivers/cdrom/gscd.c | 1031 | ||||
-rw-r--r-- | drivers/cdrom/gscd.h | 108 | ||||
-rw-r--r-- | drivers/cdrom/isp16.c | 374 | ||||
-rw-r--r-- | drivers/cdrom/isp16.h | 72 | ||||
-rw-r--r-- | drivers/cdrom/mcdx.c | 1952 | ||||
-rw-r--r-- | drivers/cdrom/mcdx.h | 185 | ||||
-rw-r--r-- | drivers/cdrom/optcd.c | 2106 | ||||
-rw-r--r-- | drivers/cdrom/optcd.h | 52 | ||||
-rw-r--r-- | drivers/cdrom/sbpcd.c | 5978 | ||||
-rw-r--r-- | drivers/cdrom/sbpcd.h | 839 | ||||
-rw-r--r-- | drivers/cdrom/sjcd.c | 1817 | ||||
-rw-r--r-- | drivers/cdrom/sjcd.h | 181 | ||||
-rw-r--r-- | drivers/cdrom/sonycd535.c | 1692 | ||||
-rw-r--r-- | drivers/cdrom/sonycd535.h | 183 | ||||
-rw-r--r-- | drivers/cdrom/viocd.c | 809 |
24 files changed, 29124 insertions, 0 deletions
diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig new file mode 100644 index 000000000000..ff5652d40619 --- /dev/null +++ b/drivers/cdrom/Kconfig | |||
@@ -0,0 +1,213 @@ | |||
1 | # | ||
2 | # CDROM driver configuration | ||
3 | # | ||
4 | |||
5 | menu "Old CD-ROM drivers (not SCSI, not IDE)" | ||
6 | depends on ISA | ||
7 | |||
8 | config CD_NO_IDESCSI | ||
9 | bool "Support non-SCSI/IDE/ATAPI CDROM drives" | ||
10 | ---help--- | ||
11 | If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y | ||
12 | here, otherwise N. Read the CD-ROM-HOWTO, available from | ||
13 | <http://www.tldp.org/docs.html#howto>. | ||
14 | |||
15 | Note that the answer to this question doesn't directly affect the | ||
16 | kernel: saying N will just cause the configurator to skip all | ||
17 | the questions about these CD-ROM drives. If you are unsure what you | ||
18 | have, say Y and find out whether you have one of the following | ||
19 | drives. | ||
20 | |||
21 | For each of these drivers, a <file:Documentation/cdrom/{driver_name}> | ||
22 | exists. Especially in cases where you do not know exactly which kind | ||
23 | of drive you have you should read there. Most of these drivers use a | ||
24 | file drivers/cdrom/{driver_name}.h where you can define your | ||
25 | interface parameters and switch some internal goodies. | ||
26 | |||
27 | To compile these CD-ROM drivers as a module, choose M instead of Y. | ||
28 | |||
29 | If you want to use any of these CD-ROM drivers, you also have to | ||
30 | answer Y or M to "ISO 9660 CD-ROM file system support" below (this | ||
31 | answer will get "defaulted" for you if you enable any of the Linux | ||
32 | CD-ROM drivers). | ||
33 | |||
34 | config AZTCD | ||
35 | tristate "Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support" | ||
36 | depends on CD_NO_IDESCSI | ||
37 | ---help--- | ||
38 | This is your driver if you have an Aztech CDA268-01A, Orchid | ||
39 | CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or | ||
40 | CR540 CD-ROM drive. This driver -- just like all these CD-ROM | ||
41 | drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such | ||
42 | as Aztech CDA269-031SE. Please read the file | ||
43 | <file:Documentation/cdrom/aztcd>. | ||
44 | |||
45 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
46 | file system support" below, because that's the file system used on | ||
47 | CD-ROMs. | ||
48 | |||
49 | To compile this driver as a module, choose M here: the | ||
50 | module will be called aztcd. | ||
51 | |||
52 | config GSCD | ||
53 | tristate "Goldstar R420 CDROM support" | ||
54 | depends on CD_NO_IDESCSI | ||
55 | ---help--- | ||
56 | If this is your CD-ROM drive, say Y here. As described in the file | ||
57 | <file:Documentation/cdrom/gscd>, you might have to change a setting | ||
58 | in the file <file:drivers/cdrom/gscd.h> before compiling the | ||
59 | kernel. Please read the file <file:Documentation/cdrom/gscd>. | ||
60 | |||
61 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
62 | file system support" below, because that's the file system used on | ||
63 | CD-ROMs. | ||
64 | |||
65 | To compile this driver as a module, choose M here: the | ||
66 | module will be called gscd. | ||
67 | |||
68 | config SBPCD | ||
69 | tristate "Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support" | ||
70 | depends on CD_NO_IDESCSI && BROKEN_ON_SMP | ||
71 | ---help--- | ||
72 | This driver supports most of the drives which use the Panasonic or | ||
73 | Sound Blaster interface. Please read the file | ||
74 | <file:Documentation/cdrom/sbpcd>. | ||
75 | |||
76 | The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives | ||
77 | (sometimes labeled "Creative"), the Creative Labs CD200, the | ||
78 | Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x | ||
79 | model), the TEAC CD-55A fall under this category. Some other | ||
80 | "electrically compatible" drives (Vertos, Genoa, some Funai models) | ||
81 | are currently not supported; for the Sanyo H94A drive currently a | ||
82 | separate driver (asked later) is responsible. Most drives have a | ||
83 | uniquely shaped faceplate, with a caddyless motorized drawer, but | ||
84 | without external brand markings. The older CR-52x drives have a | ||
85 | caddy and manual loading/eject, but still no external markings. The | ||
86 | driver is able to do an extended auto-probing for interface | ||
87 | addresses and drive types; this can help to find facts in cases you | ||
88 | are not sure, but can consume some time during the boot process if | ||
89 | none of the supported drives gets found. Once your drive got found, | ||
90 | you should enter the reported parameters into | ||
91 | <file:drivers/cdrom/sbpcd.h> and set "DISTRIBUTION 0" there. | ||
92 | |||
93 | This driver can support up to four CD-ROM controller cards, and each | ||
94 | card can support up to four CD-ROM drives; if you say Y here, you | ||
95 | will be asked how many controller cards you have. If compiled as a | ||
96 | module, only one controller card (but with up to four drives) is | ||
97 | usable. | ||
98 | |||
99 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
100 | file system support" below, because that's the file system used on | ||
101 | CD-ROMs. | ||
102 | |||
103 | To compile this driver as a module, choose M here: the | ||
104 | module will be called sbpcd. | ||
105 | |||
106 | config MCDX | ||
107 | tristate "Mitsumi CDROM support" | ||
108 | depends on CD_NO_IDESCSI | ||
109 | ---help--- | ||
110 | Use this driver if you want to be able to use your Mitsumi LU-005, | ||
111 | FX-001 or FX-001D CD-ROM drive. | ||
112 | |||
113 | Please read the file <file:Documentation/cdrom/mcdx>. | ||
114 | |||
115 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
116 | file system support" below, because that's the file system used on | ||
117 | CD-ROMs. | ||
118 | |||
119 | To compile this driver as a module, choose M here: the | ||
120 | module will be called mcdx. | ||
121 | |||
122 | config OPTCD | ||
123 | tristate "Optics Storage DOLPHIN 8000AT CDROM support" | ||
124 | depends on CD_NO_IDESCSI | ||
125 | ---help--- | ||
126 | This is the driver for the 'DOLPHIN' drive with a 34-pin Sony | ||
127 | compatible interface. It also works with the Lasermate CR328A. If | ||
128 | you have one of those, say Y. This driver does not work for the | ||
129 | Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that | ||
130 | one. Please read the file <file:Documentation/cdrom/optcd>. | ||
131 | |||
132 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
133 | file system support" below, because that's the file system used on | ||
134 | CD-ROMs. | ||
135 | |||
136 | To compile this driver as a module, choose M here: the | ||
137 | module will be called optcd. | ||
138 | |||
139 | config CM206 | ||
140 | tristate "Philips/LMS CM206 CDROM support" | ||
141 | depends on CD_NO_IDESCSI && BROKEN_ON_SMP | ||
142 | ---help--- | ||
143 | If you have a Philips/LMS CD-ROM drive cm206 in combination with a | ||
144 | cm260 host adapter card, say Y here. Please also read the file | ||
145 | <file:Documentation/cdrom/cm206>. | ||
146 | |||
147 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
148 | file system support" below, because that's the file system used on | ||
149 | CD-ROMs. | ||
150 | |||
151 | To compile this driver as a module, choose M here: the | ||
152 | module will be called cm206. | ||
153 | |||
154 | config SJCD | ||
155 | tristate "Sanyo CDR-H94A CDROM support" | ||
156 | depends on CD_NO_IDESCSI | ||
157 | help | ||
158 | If this is your CD-ROM drive, say Y here and read the file | ||
159 | <file:Documentation/cdrom/sjcd>. You should then also say Y or M to | ||
160 | "ISO 9660 CD-ROM file system support" below, because that's the | ||
161 | file system used on CD-ROMs. | ||
162 | |||
163 | To compile this driver as a module, choose M here: the | ||
164 | module will be called sjcd. | ||
165 | |||
166 | config ISP16_CDI | ||
167 | tristate "ISP16/MAD16/Mozart soft configurable cdrom interface support" | ||
168 | depends on CD_NO_IDESCSI | ||
169 | ---help--- | ||
170 | These are sound cards with built-in cdrom interfaces using the OPTi | ||
171 | 82C928 or 82C929 chips. Say Y here to have them detected and | ||
172 | possibly configured at boot time. In addition, You'll have to say Y | ||
173 | to a driver for the particular cdrom drive you have attached to the | ||
174 | card. Read <file:Documentation/cdrom/isp16> for details. | ||
175 | |||
176 | To compile this driver as a module, choose M here: the | ||
177 | module will be called isp16. | ||
178 | |||
179 | config CDU31A | ||
180 | tristate "Sony CDU31A/CDU33A CDROM support" | ||
181 | depends on CD_NO_IDESCSI && BROKEN_ON_SMP | ||
182 | ---help--- | ||
183 | These CD-ROM drives have a spring-pop-out caddyless drawer, and a | ||
184 | rectangular green LED centered beneath it. NOTE: these CD-ROM | ||
185 | drives will not be auto detected by the kernel at boot time; you | ||
186 | have to provide the interface address as an option to the kernel at | ||
187 | boot time as described in <file:Documentation/cdrom/cdu31a> or fill | ||
188 | in your parameters into <file:drivers/cdrom/cdu31a.c>. Try "man | ||
189 | bootparam" or see the documentation of your boot loader (lilo or | ||
190 | loadlin) about how to pass options to the kernel. | ||
191 | |||
192 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
193 | file system support" below, because that's the file system used on | ||
194 | CD-ROMs. | ||
195 | |||
196 | To compile this driver as a module, choose M here: the | ||
197 | module will be called cdu31a. | ||
198 | |||
199 | config CDU535 | ||
200 | tristate "Sony CDU535 CDROM support" | ||
201 | depends on CD_NO_IDESCSI | ||
202 | ---help--- | ||
203 | This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM | ||
204 | drives. Please read the file <file:Documentation/cdrom/sonycd535>. | ||
205 | |||
206 | If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM | ||
207 | file system support" below, because that's the file system used on | ||
208 | CD-ROMs. | ||
209 | |||
210 | To compile this driver as a module, choose M here: the | ||
211 | module will be called sonycd535. | ||
212 | |||
213 | endmenu | ||
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile new file mode 100644 index 000000000000..d1d1e5a4be73 --- /dev/null +++ b/drivers/cdrom/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | # Makefile for the kernel cdrom device drivers. | ||
2 | # | ||
3 | # 30 Jan 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net> | ||
4 | # Rewritten to use lists instead of if-statements. | ||
5 | |||
6 | # Each configuration option enables a list of files. | ||
7 | |||
8 | obj-$(CONFIG_BLK_DEV_IDECD) += cdrom.o | ||
9 | obj-$(CONFIG_BLK_DEV_SR) += cdrom.o | ||
10 | obj-$(CONFIG_PARIDE_PCD) += cdrom.o | ||
11 | obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o | ||
12 | |||
13 | obj-$(CONFIG_AZTCD) += aztcd.o | ||
14 | obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o | ||
15 | obj-$(CONFIG_CM206) += cm206.o cdrom.o | ||
16 | obj-$(CONFIG_GSCD) += gscd.o | ||
17 | obj-$(CONFIG_ISP16_CDI) += isp16.o | ||
18 | obj-$(CONFIG_MCDX) += mcdx.o cdrom.o | ||
19 | obj-$(CONFIG_OPTCD) += optcd.o | ||
20 | obj-$(CONFIG_SBPCD) += sbpcd.o cdrom.o | ||
21 | obj-$(CONFIG_SJCD) += sjcd.o | ||
22 | obj-$(CONFIG_CDU535) += sonycd535.o | ||
23 | obj-$(CONFIG_VIOCD) += viocd.o cdrom.o | ||
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c new file mode 100644 index 000000000000..43bf1e5dc38a --- /dev/null +++ b/drivers/cdrom/aztcd.c | |||
@@ -0,0 +1,2494 @@ | |||
1 | #define AZT_VERSION "2.60" | ||
2 | |||
3 | /* $Id: aztcd.c,v 2.60 1997/11/29 09:51:19 root Exp root $ | ||
4 | linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver | ||
5 | |||
6 | Copyright (C) 1994-98 Werner Zimmermann(Werner.Zimmermann@fht-esslingen.de) | ||
7 | |||
8 | based on Mitsumi CDROM driver by Martin Hariss and preworks by | ||
9 | Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby | ||
10 | Schirmer. | ||
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, or (at your option) | ||
15 | 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | |||
26 | HISTORY | ||
27 | V0.0 Adaption to Aztech CD268-01A Version 1.3 | ||
28 | Version is PRE_ALPHA, unresolved points: | ||
29 | 1. I use busy wait instead of timer wait in STEN_LOW,DTEN_LOW | ||
30 | thus driver causes CPU overhead and is very slow | ||
31 | 2. could not find a way to stop the drive, when it is | ||
32 | in data read mode, therefore I had to set | ||
33 | msf.end.min/sec/frame to 0:0:1 (in azt_poll); so only one | ||
34 | frame can be read in sequence, this is also the reason for | ||
35 | 3. getting 'timeout in state 4' messages, but nevertheless | ||
36 | it works | ||
37 | W.Zimmermann, Oct. 31, 1994 | ||
38 | V0.1 Version is ALPHA, problems #2 and #3 resolved. | ||
39 | W.Zimmermann, Nov. 3, 1994 | ||
40 | V0.2 Modification to some comments, debugging aids for partial test | ||
41 | with Borland C under DOS eliminated. Timer interrupt wait | ||
42 | STEN_LOW_WAIT additionally to busy wait for STEN_LOW implemented; | ||
43 | use it only for the 'slow' commands (ACMD_GET_Q_CHANNEL, ACMD_ | ||
44 | SEEK_TO_LEAD_IN), all other commands are so 'fast', that busy | ||
45 | waiting seems better to me than interrupt rescheduling. | ||
46 | Besides that, when used in the wrong place, STEN_LOW_WAIT causes | ||
47 | kernel panic. | ||
48 | In function aztPlay command ACMD_PLAY_AUDIO added, should make | ||
49 | audio functions work. The Aztech drive needs different commands | ||
50 | to read data tracks and play audio tracks. | ||
51 | W.Zimmermann, Nov. 8, 1994 | ||
52 | V0.3 Recognition of missing drive during boot up improved (speeded up). | ||
53 | W.Zimmermann, Nov. 13, 1994 | ||
54 | V0.35 Rewrote the control mechanism in azt_poll (formerly mcd_poll) | ||
55 | including removal of all 'goto' commands. :-); | ||
56 | J. Nardone, Nov. 14, 1994 | ||
57 | V0.4 Renamed variables and constants to 'azt' instead of 'mcd'; had | ||
58 | to make some "compatibility" defines in azt.h; please note, | ||
59 | that the source file was renamed to azt.c, the include file to | ||
60 | azt.h | ||
61 | Speeded up drive recognition during init (will be a little bit | ||
62 | slower than before if no drive is installed!); suggested by | ||
63 | Robby Schirmer. | ||
64 | read_count declared volatile and set to AZT_BUF_SIZ to make | ||
65 | drive faster (now 300kB/sec, was 60kB/sec before, measured | ||
66 | by 'time dd if=/dev/cdrom of=/dev/null bs=2048 count=4096'; | ||
67 | different AZT_BUF_SIZes were test, above 16 no further im- | ||
68 | provement seems to be possible; suggested by E.Moenkeberg. | ||
69 | W.Zimmermann, Nov. 18, 1994 | ||
70 | V0.42 Included getAztStatus command in GetQChannelInfo() to allow | ||
71 | reading Q-channel info on audio disks, if drive is stopped, | ||
72 | and some other bug fixes in the audio stuff, suggested by | ||
73 | Robby Schirmer. | ||
74 | Added more ioctls (reading data in mode 1 and mode 2). | ||
75 | Completely removed the old azt_poll() routine. | ||
76 | Detection of ORCHID CDS-3110 in aztcd_init implemented. | ||
77 | Additional debugging aids (see the readme file). | ||
78 | W.Zimmermann, Dec. 9, 1994 | ||
79 | V0.50 Autodetection of drives implemented. | ||
80 | W.Zimmermann, Dec. 12, 1994 | ||
81 | V0.52 Prepared for including in the standard kernel, renamed most | ||
82 | variables to contain 'azt', included autoconf.h | ||
83 | W.Zimmermann, Dec. 16, 1994 | ||
84 | V0.6 Version for being included in the standard Linux kernel. | ||
85 | Renamed source and header file to aztcd.c and aztcd.h | ||
86 | W.Zimmermann, Dec. 24, 1994 | ||
87 | V0.7 Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case | ||
88 | CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl, | ||
89 | which causes kernel crashes when playing audio, changed | ||
90 | include-files (config.h instead of autoconf.h, removed | ||
91 | delay.h) | ||
92 | W.Zimmermann, Jan. 8, 1995 | ||
93 | V0.72 Some more modifications for adaption to the standard kernel. | ||
94 | W.Zimmermann, Jan. 16, 1995 | ||
95 | V0.80 aztcd is now part of the standard kernel since version 1.1.83. | ||
96 | Modified the SET_TIMER and CLEAR_TIMER macros to comply with | ||
97 | the new timer scheme. | ||
98 | W.Zimmermann, Jan. 21, 1995 | ||
99 | V0.90 Included CDROMVOLCTRL, but with my Aztech drive I can only turn | ||
100 | the channels on and off. If it works better with your drive, | ||
101 | please mail me. Also implemented ACMD_CLOSE for CDROMSTART. | ||
102 | W.Zimmermann, Jan. 24, 1995 | ||
103 | V1.00 Implemented close and lock tray commands. Patches supplied by | ||
104 | Frank Racis | ||
105 | Added support for loadable MODULEs, so aztcd can now also be | ||
106 | loaded by insmod and removed by rmmod during run time | ||
107 | Werner Zimmermann, Mar. 24, 95 | ||
108 | V1.10 Implemented soundcard configuration for Orchid CDS-3110 drives | ||
109 | connected to Soundwave32 cards. Release for LST 2.1. | ||
110 | (still experimental) | ||
111 | Werner Zimmermann, May 8, 95 | ||
112 | V1.20 Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but | ||
113 | sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver- | ||
114 | sion needs an update of Dosemu0.60's cdrom.c, which will come with the | ||
115 | next revision of Dosemu. | ||
116 | Also Soundwave32 support now works. | ||
117 | Werner Zimmermann, May 22, 95 | ||
118 | V1.30 Auto-eject feature. Inspired by Franc Racis (racis@psu.edu) | ||
119 | Werner Zimmermann, July 4, 95 | ||
120 | V1.40 Started multisession support. Implementation copied from mcdx.c | ||
121 | by Heiko Schlittermann. Not tested yet. | ||
122 | Werner Zimmermann, July 15, 95 | ||
123 | V1.50 Implementation of ioctl CDROMRESET, continued multisession, began | ||
124 | XA, but still untested. Heavy modifications to drive status de- | ||
125 | tection. | ||
126 | Werner Zimmermann, July 25, 95 | ||
127 | V1.60 XA support now should work. Speeded up drive recognition in cases, | ||
128 | where no drive is installed. | ||
129 | Werner Zimmermann, August 8, 1995 | ||
130 | V1.70 Multisession support now is completed, but there is still not | ||
131 | enough testing done. If you can test it, please contact me. For | ||
132 | details please read Documentation/cdrom/aztcd | ||
133 | Werner Zimmermann, August 19, 1995 | ||
134 | V1.80 Modification to suit the new kernel boot procedure introduced | ||
135 | with kernel 1.3.33. Will definitely not work with older kernels. | ||
136 | Programming done by Linus himself. | ||
137 | Werner Zimmermann, October 11, 1995 | ||
138 | V1.90 Support for Conrad TXC drives, thank's to Jochen Kunz and Olaf Kaluza. | ||
139 | Werner Zimmermann, October 21, 1995 | ||
140 | V2.00 Changed #include "blk.h" to <linux/blk.h> as the directory | ||
141 | structure was changed. README.aztcd is now /usr/src/docu- | ||
142 | mentation/cdrom/aztcd | ||
143 | Werner Zimmermann, November 10, 95 | ||
144 | V2.10 Started to modify azt_poll to prevent reading beyond end of | ||
145 | tracks. | ||
146 | Werner Zimmermann, December 3, 95 | ||
147 | V2.20 Changed some comments | ||
148 | Werner Zimmermann, April 1, 96 | ||
149 | V2.30 Implemented support for CyCDROM CR520, CR940, Code for CR520 | ||
150 | delivered by H.Berger with preworks by E.Moenkeberg. | ||
151 | Werner Zimmermann, April 29, 96 | ||
152 | V2.40 Reorganized the placement of functions in the source code file | ||
153 | to reflect the layered approach; did not actually change code | ||
154 | Werner Zimmermann, May 1, 96 | ||
155 | V2.50 Heiko Eissfeldt suggested to remove some VERIFY_READs in | ||
156 | aztcd_ioctl; check_aztcd_media_change modified | ||
157 | Werner Zimmermann, May 16, 96 | ||
158 | V2.60 Implemented Auto-Probing; made changes for kernel's 2.1.xx blocksize | ||
159 | Adaption to linux kernel > 2.1.0 | ||
160 | Werner Zimmermann, Nov 29, 97 | ||
161 | |||
162 | November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
163 | Removed init_module & cleanup_module in favor of | ||
164 | module_init & module_exit. | ||
165 | Torben Mathiasen <tmm@image.dk> | ||
166 | */ | ||
167 | |||
168 | #include <linux/blkdev.h> | ||
169 | #include "aztcd.h" | ||
170 | |||
171 | #include <linux/module.h> | ||
172 | #include <linux/errno.h> | ||
173 | #include <linux/sched.h> | ||
174 | #include <linux/mm.h> | ||
175 | #include <linux/timer.h> | ||
176 | #include <linux/fs.h> | ||
177 | #include <linux/kernel.h> | ||
178 | #include <linux/cdrom.h> | ||
179 | #include <linux/ioport.h> | ||
180 | #include <linux/string.h> | ||
181 | #include <linux/major.h> | ||
182 | |||
183 | #include <linux/init.h> | ||
184 | |||
185 | #include <asm/system.h> | ||
186 | #include <asm/io.h> | ||
187 | |||
188 | #include <asm/uaccess.h> | ||
189 | |||
190 | /*########################################################################### | ||
191 | Defines | ||
192 | ########################################################################### | ||
193 | */ | ||
194 | |||
195 | #define MAJOR_NR AZTECH_CDROM_MAJOR | ||
196 | #define QUEUE (azt_queue) | ||
197 | #define CURRENT elv_next_request(azt_queue) | ||
198 | #define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \ | ||
199 | delay_timer.function = (void *) (func); \ | ||
200 | add_timer(&delay_timer); | ||
201 | |||
202 | #define CLEAR_TIMER del_timer(&delay_timer); | ||
203 | |||
204 | #define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\ | ||
205 | return value;} | ||
206 | #define RETURN(message) {printk("aztcd: Warning: %s failed\n",message);\ | ||
207 | return;} | ||
208 | |||
209 | /* Macros to switch the IDE-interface to the slave device and back to the master*/ | ||
210 | #define SWITCH_IDE_SLAVE outb_p(0xa0,azt_port+6); \ | ||
211 | outb_p(0x10,azt_port+6); \ | ||
212 | outb_p(0x00,azt_port+7); \ | ||
213 | outb_p(0x10,azt_port+6); | ||
214 | #define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6); | ||
215 | |||
216 | |||
217 | #if 0 | ||
218 | #define AZT_TEST | ||
219 | #define AZT_TEST1 /* <int-..> */ | ||
220 | #define AZT_TEST2 /* do_aztcd_request */ | ||
221 | #define AZT_TEST3 /* AZT_S_state */ | ||
222 | #define AZT_TEST4 /* QUICK_LOOP-counter */ | ||
223 | #define AZT_TEST5 /* port(1) state */ | ||
224 | #define AZT_DEBUG | ||
225 | #define AZT_DEBUG_MULTISESSION | ||
226 | #endif | ||
227 | |||
228 | static struct request_queue *azt_queue; | ||
229 | |||
230 | static int current_valid(void) | ||
231 | { | ||
232 | return CURRENT && | ||
233 | CURRENT->cmd == READ && | ||
234 | CURRENT->sector != -1; | ||
235 | } | ||
236 | |||
237 | #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA) | ||
238 | #define AZT_BUF_SIZ 16 | ||
239 | |||
240 | #define READ_TIMEOUT 3000 | ||
241 | |||
242 | #define azt_port aztcd /*needed for the modutils */ | ||
243 | |||
244 | /*########################################################################## | ||
245 | Type Definitions | ||
246 | ########################################################################## | ||
247 | */ | ||
248 | enum azt_state_e { AZT_S_IDLE, /* 0 */ | ||
249 | AZT_S_START, /* 1 */ | ||
250 | AZT_S_MODE, /* 2 */ | ||
251 | AZT_S_READ, /* 3 */ | ||
252 | AZT_S_DATA, /* 4 */ | ||
253 | AZT_S_STOP, /* 5 */ | ||
254 | AZT_S_STOPPING /* 6 */ | ||
255 | }; | ||
256 | enum azt_read_modes { AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware */ | ||
257 | AZT_MODE_1, /*read mode for normal CD-ROMs */ | ||
258 | AZT_MODE_2 /*read mode for XA CD-ROMs */ | ||
259 | }; | ||
260 | |||
261 | /*########################################################################## | ||
262 | Global Variables | ||
263 | ########################################################################## | ||
264 | */ | ||
265 | static int aztPresent = 0; | ||
266 | |||
267 | static volatile int azt_transfer_is_active = 0; | ||
268 | |||
269 | static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ]; /*buffer for block size conversion */ | ||
270 | #if AZT_PRIVATE_IOCTLS | ||
271 | static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls */ | ||
272 | #endif | ||
273 | |||
274 | static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn; | ||
275 | static volatile int azt_buf_in, azt_buf_out = -1; | ||
276 | static volatile int azt_error = 0; | ||
277 | static int azt_open_count = 0; | ||
278 | static volatile enum azt_state_e azt_state = AZT_S_IDLE; | ||
279 | #ifdef AZT_TEST3 | ||
280 | static volatile enum azt_state_e azt_state_old = AZT_S_STOP; | ||
281 | static volatile int azt_st_old = 0; | ||
282 | #endif | ||
283 | static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1; | ||
284 | |||
285 | static int azt_mode = -1; | ||
286 | static volatile int azt_read_count = 1; | ||
287 | |||
288 | static int azt_port = AZT_BASE_ADDR; | ||
289 | |||
290 | module_param(azt_port, int, 0); | ||
291 | |||
292 | static int azt_port_auto[16] = AZT_BASE_AUTO; | ||
293 | |||
294 | static char azt_cont = 0; | ||
295 | static char azt_init_end = 0; | ||
296 | static char azt_auto_eject = AZT_AUTO_EJECT; | ||
297 | |||
298 | static int AztTimeout, AztTries; | ||
299 | static DECLARE_WAIT_QUEUE_HEAD(azt_waitq); | ||
300 | static struct timer_list delay_timer = TIMER_INITIALIZER(NULL, 0, 0); | ||
301 | |||
302 | static struct azt_DiskInfo DiskInfo; | ||
303 | static struct azt_Toc Toc[MAX_TRACKS]; | ||
304 | static struct azt_Play_msf azt_Play; | ||
305 | |||
306 | static int aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
307 | static char aztDiskChanged = 1; | ||
308 | static char aztTocUpToDate = 0; | ||
309 | |||
310 | static unsigned char aztIndatum; | ||
311 | static unsigned long aztTimeOutCount; | ||
312 | static int aztCmd = 0; | ||
313 | |||
314 | static DEFINE_SPINLOCK(aztSpin); | ||
315 | |||
316 | /*########################################################################### | ||
317 | Function Prototypes | ||
318 | ########################################################################### | ||
319 | */ | ||
320 | /* CDROM Drive Low Level I/O Functions */ | ||
321 | static void aztStatTimer(void); | ||
322 | |||
323 | /* CDROM Drive Command Functions */ | ||
324 | static int aztGetDiskInfo(void); | ||
325 | #if AZT_MULTISESSION | ||
326 | static int aztGetMultiDiskInfo(void); | ||
327 | #endif | ||
328 | static int aztGetToc(int multi); | ||
329 | |||
330 | /* Kernel Interface Functions */ | ||
331 | static int check_aztcd_media_change(struct gendisk *disk); | ||
332 | static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | ||
333 | unsigned long arg); | ||
334 | static int aztcd_open(struct inode *ip, struct file *fp); | ||
335 | static int aztcd_release(struct inode *inode, struct file *file); | ||
336 | |||
337 | static struct block_device_operations azt_fops = { | ||
338 | .owner = THIS_MODULE, | ||
339 | .open = aztcd_open, | ||
340 | .release = aztcd_release, | ||
341 | .ioctl = aztcd_ioctl, | ||
342 | .media_changed = check_aztcd_media_change, | ||
343 | }; | ||
344 | |||
345 | /* Aztcd State Machine: Controls Drive Operating State */ | ||
346 | static void azt_poll(void); | ||
347 | |||
348 | /* Miscellaneous support functions */ | ||
349 | static void azt_hsg2msf(long hsg, struct msf *msf); | ||
350 | static long azt_msf2hsg(struct msf *mp); | ||
351 | static void azt_bin2bcd(unsigned char *p); | ||
352 | static int azt_bcd2bin(unsigned char bcd); | ||
353 | |||
354 | /*########################################################################## | ||
355 | CDROM Drive Low Level I/O Functions | ||
356 | ########################################################################## | ||
357 | */ | ||
358 | /* Macros for the drive hardware interface handshake, these macros use | ||
359 | busy waiting */ | ||
360 | /* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/ | ||
361 | # define OP_OK op_ok() | ||
362 | static void op_ok(void) | ||
363 | { | ||
364 | aztTimeOutCount = 0; | ||
365 | do { | ||
366 | aztIndatum = inb(DATA_PORT); | ||
367 | aztTimeOutCount++; | ||
368 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
369 | printk("aztcd: Error Wait OP_OK\n"); | ||
370 | break; | ||
371 | } | ||
372 | } while (aztIndatum != AFL_OP_OK); | ||
373 | } | ||
374 | |||
375 | /* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/ | ||
376 | #if 0 | ||
377 | # define PA_OK pa_ok() | ||
378 | static void pa_ok(void) | ||
379 | { | ||
380 | aztTimeOutCount = 0; | ||
381 | do { | ||
382 | aztIndatum = inb(DATA_PORT); | ||
383 | aztTimeOutCount++; | ||
384 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
385 | printk("aztcd: Error Wait PA_OK\n"); | ||
386 | break; | ||
387 | } | ||
388 | } while (aztIndatum != AFL_PA_OK); | ||
389 | } | ||
390 | #endif | ||
391 | |||
392 | /* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/ | ||
393 | # define STEN_LOW sten_low() | ||
394 | static void sten_low(void) | ||
395 | { | ||
396 | aztTimeOutCount = 0; | ||
397 | do { | ||
398 | aztIndatum = inb(STATUS_PORT); | ||
399 | aztTimeOutCount++; | ||
400 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
401 | if (azt_init_end) | ||
402 | printk | ||
403 | ("aztcd: Error Wait STEN_LOW commands:%x\n", | ||
404 | aztCmd); | ||
405 | break; | ||
406 | } | ||
407 | } while (aztIndatum & AFL_STATUS); | ||
408 | } | ||
409 | |||
410 | /* Wait for DTEN=Low = handshake signal 'Data available'*/ | ||
411 | # define DTEN_LOW dten_low() | ||
412 | static void dten_low(void) | ||
413 | { | ||
414 | aztTimeOutCount = 0; | ||
415 | do { | ||
416 | aztIndatum = inb(STATUS_PORT); | ||
417 | aztTimeOutCount++; | ||
418 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
419 | printk("aztcd: Error Wait DTEN_OK\n"); | ||
420 | break; | ||
421 | } | ||
422 | } while (aztIndatum & AFL_DATA); | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Macro for timer wait on STEN=Low, should only be used for 'slow' commands; | ||
427 | * may cause kernel panic when used in the wrong place | ||
428 | */ | ||
429 | #define STEN_LOW_WAIT statusAzt() | ||
430 | static void statusAzt(void) | ||
431 | { | ||
432 | AztTimeout = AZT_STATUS_DELAY; | ||
433 | SET_TIMER(aztStatTimer, HZ / 100); | ||
434 | sleep_on(&azt_waitq); | ||
435 | if (AztTimeout <= 0) | ||
436 | printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n", | ||
437 | aztCmd); | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | static void aztStatTimer(void) | ||
442 | { | ||
443 | if (!(inb(STATUS_PORT) & AFL_STATUS)) { | ||
444 | wake_up(&azt_waitq); | ||
445 | return; | ||
446 | } | ||
447 | AztTimeout--; | ||
448 | if (AztTimeout <= 0) { | ||
449 | wake_up(&azt_waitq); | ||
450 | printk("aztcd: Error aztStatTimer: Timeout\n"); | ||
451 | return; | ||
452 | } | ||
453 | SET_TIMER(aztStatTimer, HZ / 100); | ||
454 | } | ||
455 | |||
456 | /*########################################################################## | ||
457 | CDROM Drive Command Functions | ||
458 | ########################################################################## | ||
459 | */ | ||
460 | /* | ||
461 | * Send a single command, return -1 on error, else 0 | ||
462 | */ | ||
463 | static int aztSendCmd(int cmd) | ||
464 | { | ||
465 | unsigned char data; | ||
466 | int retry; | ||
467 | |||
468 | #ifdef AZT_DEBUG | ||
469 | printk("aztcd: Executing command %x\n", cmd); | ||
470 | #endif | ||
471 | |||
472 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) | ||
473 | SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */ | ||
474 | |||
475 | aztCmd = cmd; | ||
476 | outb(POLLED, MODE_PORT); | ||
477 | do { | ||
478 | if (inb(STATUS_PORT) & AFL_STATUS) | ||
479 | break; | ||
480 | inb(DATA_PORT); /* if status left from last command, read and */ | ||
481 | } while (1); /* discard it */ | ||
482 | do { | ||
483 | if (inb(STATUS_PORT) & AFL_DATA) | ||
484 | break; | ||
485 | inb(DATA_PORT); /* if data left from last command, read and */ | ||
486 | } while (1); /* discard it */ | ||
487 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
488 | outb((unsigned char) cmd, CMD_PORT); | ||
489 | STEN_LOW; | ||
490 | data = inb(DATA_PORT); | ||
491 | if (data == AFL_OP_OK) { | ||
492 | return 0; | ||
493 | } /*OP_OK? */ | ||
494 | if (data == AFL_OP_ERR) { | ||
495 | STEN_LOW; | ||
496 | data = inb(DATA_PORT); | ||
497 | printk | ||
498 | ("### Error 1 aztcd: aztSendCmd %x Error Code %x\n", | ||
499 | cmd, data); | ||
500 | } | ||
501 | } | ||
502 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
503 | printk("### Error 2 aztcd: aztSendCmd %x \n", cmd); | ||
504 | azt_error = 0xA5; | ||
505 | } | ||
506 | RETURNM("aztSendCmd", -1); | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * Send a play or read command to the drive, return -1 on error, else 0 | ||
511 | */ | ||
512 | static int sendAztCmd(int cmd, struct azt_Play_msf *params) | ||
513 | { | ||
514 | unsigned char data; | ||
515 | int retry; | ||
516 | |||
517 | #ifdef AZT_DEBUG | ||
518 | printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n", | ||
519 | params->start.min, params->start.sec, params->start.frame, | ||
520 | params->end.min, params->end.sec, params->end.frame); | ||
521 | #endif | ||
522 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
523 | aztSendCmd(cmd); | ||
524 | outb(params->start.min, CMD_PORT); | ||
525 | outb(params->start.sec, CMD_PORT); | ||
526 | outb(params->start.frame, CMD_PORT); | ||
527 | outb(params->end.min, CMD_PORT); | ||
528 | outb(params->end.sec, CMD_PORT); | ||
529 | outb(params->end.frame, CMD_PORT); | ||
530 | STEN_LOW; | ||
531 | data = inb(DATA_PORT); | ||
532 | if (data == AFL_PA_OK) { | ||
533 | return 0; | ||
534 | } /*PA_OK ? */ | ||
535 | if (data == AFL_PA_ERR) { | ||
536 | STEN_LOW; | ||
537 | data = inb(DATA_PORT); | ||
538 | printk | ||
539 | ("### Error 1 aztcd: sendAztCmd %x Error Code %x\n", | ||
540 | cmd, data); | ||
541 | } | ||
542 | } | ||
543 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
544 | printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd); | ||
545 | azt_error = 0xA5; | ||
546 | } | ||
547 | RETURNM("sendAztCmd", -1); | ||
548 | } | ||
549 | |||
550 | /* | ||
551 | * Send a seek command to the drive, return -1 on error, else 0 | ||
552 | */ | ||
553 | static int aztSeek(struct azt_Play_msf *params) | ||
554 | { | ||
555 | unsigned char data; | ||
556 | int retry; | ||
557 | |||
558 | #ifdef AZT_DEBUG | ||
559 | printk("aztcd: aztSeek %02x:%02x:%02x\n", | ||
560 | params->start.min, params->start.sec, params->start.frame); | ||
561 | #endif | ||
562 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
563 | aztSendCmd(ACMD_SEEK); | ||
564 | outb(params->start.min, CMD_PORT); | ||
565 | outb(params->start.sec, CMD_PORT); | ||
566 | outb(params->start.frame, CMD_PORT); | ||
567 | STEN_LOW; | ||
568 | data = inb(DATA_PORT); | ||
569 | if (data == AFL_PA_OK) { | ||
570 | return 0; | ||
571 | } /*PA_OK ? */ | ||
572 | if (data == AFL_PA_ERR) { | ||
573 | STEN_LOW; | ||
574 | data = inb(DATA_PORT); | ||
575 | printk("### Error 1 aztcd: aztSeek\n"); | ||
576 | } | ||
577 | } | ||
578 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
579 | printk("### Error 2 aztcd: aztSeek\n "); | ||
580 | azt_error = 0xA5; | ||
581 | } | ||
582 | RETURNM("aztSeek", -1); | ||
583 | } | ||
584 | |||
585 | /* Send a Set Disk Type command | ||
586 | does not seem to work with Aztech drives, behavior is completely indepen- | ||
587 | dent on which mode is set ??? | ||
588 | */ | ||
589 | static int aztSetDiskType(int type) | ||
590 | { | ||
591 | unsigned char data; | ||
592 | int retry; | ||
593 | |||
594 | #ifdef AZT_DEBUG | ||
595 | printk("aztcd: set disk type command: type= %i\n", type); | ||
596 | #endif | ||
597 | for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { | ||
598 | aztSendCmd(ACMD_SET_DISK_TYPE); | ||
599 | outb(type, CMD_PORT); | ||
600 | STEN_LOW; | ||
601 | data = inb(DATA_PORT); | ||
602 | if (data == AFL_PA_OK) { /*PA_OK ? */ | ||
603 | azt_read_mode = type; | ||
604 | return 0; | ||
605 | } | ||
606 | if (data == AFL_PA_ERR) { | ||
607 | STEN_LOW; | ||
608 | data = inb(DATA_PORT); | ||
609 | printk | ||
610 | ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n", | ||
611 | type, data); | ||
612 | } | ||
613 | } | ||
614 | if (retry >= AZT_RETRY_ATTEMPTS) { | ||
615 | printk("### Error 2 aztcd: aztSetDiskType %x\n ", type); | ||
616 | azt_error = 0xA5; | ||
617 | } | ||
618 | RETURNM("aztSetDiskType", -1); | ||
619 | } | ||
620 | |||
621 | |||
622 | /* used in azt_poll to poll the status, expects another program to issue a | ||
623 | * ACMD_GET_STATUS directly before | ||
624 | */ | ||
625 | static int aztStatus(void) | ||
626 | { | ||
627 | int st; | ||
628 | /* int i; | ||
629 | |||
630 | i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ??? | ||
631 | if (!i) | ||
632 | */ STEN_LOW; | ||
633 | if (aztTimeOutCount < AZT_TIMEOUT) { | ||
634 | st = inb(DATA_PORT) & 0xFF; | ||
635 | return st; | ||
636 | } else | ||
637 | RETURNM("aztStatus", -1); | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Get the drive status | ||
642 | */ | ||
643 | static int getAztStatus(void) | ||
644 | { | ||
645 | int st; | ||
646 | |||
647 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
648 | RETURNM("getAztStatus 1", -1); | ||
649 | STEN_LOW; | ||
650 | st = inb(DATA_PORT) & 0xFF; | ||
651 | #ifdef AZT_DEBUG | ||
652 | printk("aztcd: Status = %x\n", st); | ||
653 | #endif | ||
654 | if ((st == 0xFF) || (st & AST_CMD_CHECK)) { | ||
655 | printk | ||
656 | ("aztcd: AST_CMD_CHECK error or no status available\n"); | ||
657 | return -1; | ||
658 | } | ||
659 | |||
660 | if (((st & AST_MODE_BITS) != AST_BUSY) | ||
661 | && (aztAudioStatus == CDROM_AUDIO_PLAY)) | ||
662 | /* XXX might be an error? look at q-channel? */ | ||
663 | aztAudioStatus = CDROM_AUDIO_COMPLETED; | ||
664 | |||
665 | if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) { | ||
666 | aztDiskChanged = 1; | ||
667 | aztTocUpToDate = 0; | ||
668 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
669 | } | ||
670 | return st; | ||
671 | } | ||
672 | |||
673 | |||
674 | /* | ||
675 | * Send a 'Play' command and get the status. Use only from the top half. | ||
676 | */ | ||
677 | static int aztPlay(struct azt_Play_msf *arg) | ||
678 | { | ||
679 | if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) | ||
680 | RETURNM("aztPlay", -1); | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* | ||
685 | * Subroutines to automatically close the door (tray) and | ||
686 | * lock it closed when the cd is mounted. Leave the tray | ||
687 | * locking as an option | ||
688 | */ | ||
689 | static void aztCloseDoor(void) | ||
690 | { | ||
691 | aztSendCmd(ACMD_CLOSE); | ||
692 | STEN_LOW; | ||
693 | return; | ||
694 | } | ||
695 | |||
696 | static void aztLockDoor(void) | ||
697 | { | ||
698 | #if AZT_ALLOW_TRAY_LOCK | ||
699 | aztSendCmd(ACMD_LOCK); | ||
700 | STEN_LOW; | ||
701 | #endif | ||
702 | return; | ||
703 | } | ||
704 | |||
705 | static void aztUnlockDoor(void) | ||
706 | { | ||
707 | #if AZT_ALLOW_TRAY_LOCK | ||
708 | aztSendCmd(ACMD_UNLOCK); | ||
709 | STEN_LOW; | ||
710 | #endif | ||
711 | return; | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * Read a value from the drive. Should return quickly, so a busy wait | ||
716 | * is used to avoid excessive rescheduling. The read command itself must | ||
717 | * be issued with aztSendCmd() directly before | ||
718 | */ | ||
719 | static int aztGetValue(unsigned char *result) | ||
720 | { | ||
721 | int s; | ||
722 | |||
723 | STEN_LOW; | ||
724 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
725 | printk("aztcd: aztGetValue timeout\n"); | ||
726 | return -1; | ||
727 | } | ||
728 | s = inb(DATA_PORT) & 0xFF; | ||
729 | *result = (unsigned char) s; | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | /* | ||
734 | * Read the current Q-channel info. Also used for reading the | ||
735 | * table of contents. | ||
736 | */ | ||
737 | static int aztGetQChannelInfo(struct azt_Toc *qp) | ||
738 | { | ||
739 | unsigned char notUsed; | ||
740 | int st; | ||
741 | |||
742 | #ifdef AZT_DEBUG | ||
743 | printk("aztcd: starting aztGetQChannelInfo Time:%li\n", jiffies); | ||
744 | #endif | ||
745 | if ((st = getAztStatus()) == -1) | ||
746 | RETURNM("aztGetQChannelInfo 1", -1); | ||
747 | if (aztSendCmd(ACMD_GET_Q_CHANNEL)) | ||
748 | RETURNM("aztGetQChannelInfo 2", -1); | ||
749 | /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */ | ||
750 | if (aztGetValue(¬Used)) | ||
751 | RETURNM("aztGetQChannelInfo 3", -1); /*??? Nullbyte einlesen */ | ||
752 | if ((st & AST_MODE_BITS) == AST_INITIAL) { | ||
753 | qp->ctrl_addr = 0; /* when audio stop ACMD_GET_Q_CHANNEL returns */ | ||
754 | qp->track = 0; /* only one byte with Aztech drives */ | ||
755 | qp->pointIndex = 0; | ||
756 | qp->trackTime.min = 0; | ||
757 | qp->trackTime.sec = 0; | ||
758 | qp->trackTime.frame = 0; | ||
759 | qp->diskTime.min = 0; | ||
760 | qp->diskTime.sec = 0; | ||
761 | qp->diskTime.frame = 0; | ||
762 | return 0; | ||
763 | } else { | ||
764 | if (aztGetValue(&qp->ctrl_addr) < 0) | ||
765 | RETURNM("aztGetQChannelInfo 4", -1); | ||
766 | if (aztGetValue(&qp->track) < 0) | ||
767 | RETURNM("aztGetQChannelInfo 4", -1); | ||
768 | if (aztGetValue(&qp->pointIndex) < 0) | ||
769 | RETURNM("aztGetQChannelInfo 4", -1); | ||
770 | if (aztGetValue(&qp->trackTime.min) < 0) | ||
771 | RETURNM("aztGetQChannelInfo 4", -1); | ||
772 | if (aztGetValue(&qp->trackTime.sec) < 0) | ||
773 | RETURNM("aztGetQChannelInfo 4", -1); | ||
774 | if (aztGetValue(&qp->trackTime.frame) < 0) | ||
775 | RETURNM("aztGetQChannelInfo 4", -1); | ||
776 | if (aztGetValue(¬Used) < 0) | ||
777 | RETURNM("aztGetQChannelInfo 4", -1); | ||
778 | if (aztGetValue(&qp->diskTime.min) < 0) | ||
779 | RETURNM("aztGetQChannelInfo 4", -1); | ||
780 | if (aztGetValue(&qp->diskTime.sec) < 0) | ||
781 | RETURNM("aztGetQChannelInfo 4", -1); | ||
782 | if (aztGetValue(&qp->diskTime.frame) < 0) | ||
783 | RETURNM("aztGetQChannelInfo 4", -1); | ||
784 | } | ||
785 | #ifdef AZT_DEBUG | ||
786 | printk("aztcd: exiting aztGetQChannelInfo Time:%li\n", jiffies); | ||
787 | #endif | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | /* | ||
792 | * Read the table of contents (TOC) and TOC header if necessary | ||
793 | */ | ||
794 | static int aztUpdateToc(void) | ||
795 | { | ||
796 | int st; | ||
797 | |||
798 | #ifdef AZT_DEBUG | ||
799 | printk("aztcd: starting aztUpdateToc Time:%li\n", jiffies); | ||
800 | #endif | ||
801 | if (aztTocUpToDate) | ||
802 | return 0; | ||
803 | |||
804 | if (aztGetDiskInfo() < 0) | ||
805 | return -EIO; | ||
806 | |||
807 | if (aztGetToc(0) < 0) | ||
808 | return -EIO; | ||
809 | |||
810 | /*audio disk detection | ||
811 | with my Aztech drive there is no audio status bit, so I use the copy | ||
812 | protection bit of the first track. If this track is copy protected | ||
813 | (copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */ | ||
814 | if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) | ||
815 | DiskInfo.audio = 1; | ||
816 | else | ||
817 | DiskInfo.audio = 0; | ||
818 | |||
819 | /* XA detection */ | ||
820 | if (!DiskInfo.audio) { | ||
821 | azt_Play.start.min = 0; /*XA detection only seems to work */ | ||
822 | azt_Play.start.sec = 2; /*when we play a track */ | ||
823 | azt_Play.start.frame = 0; | ||
824 | azt_Play.end.min = 0; | ||
825 | azt_Play.end.sec = 0; | ||
826 | azt_Play.end.frame = 1; | ||
827 | if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) | ||
828 | return -1; | ||
829 | DTEN_LOW; | ||
830 | for (st = 0; st < CD_FRAMESIZE; st++) | ||
831 | inb(DATA_PORT); | ||
832 | } | ||
833 | DiskInfo.xa = getAztStatus() & AST_MODE; | ||
834 | if (DiskInfo.xa) { | ||
835 | printk | ||
836 | ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n"); | ||
837 | } | ||
838 | |||
839 | /*multisession detection | ||
840 | support for multisession CDs is done automatically with Aztech drives, | ||
841 | we don't have to take care about TOC redirection; if we want the isofs | ||
842 | to take care about redirection, we have to set AZT_MULTISESSION to 1 */ | ||
843 | DiskInfo.multi = 0; | ||
844 | #if AZT_MULTISESSION | ||
845 | if (DiskInfo.xa) { | ||
846 | aztGetMultiDiskInfo(); /*here Disk.Info.multi is set */ | ||
847 | } | ||
848 | #endif | ||
849 | if (DiskInfo.multi) { | ||
850 | DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min; | ||
851 | DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec; | ||
852 | DiskInfo.lastSession.frame = | ||
853 | Toc[DiskInfo.next].diskTime.frame; | ||
854 | printk("aztcd: Multisession support experimental\n"); | ||
855 | } else { | ||
856 | DiskInfo.lastSession.min = | ||
857 | Toc[DiskInfo.first].diskTime.min; | ||
858 | DiskInfo.lastSession.sec = | ||
859 | Toc[DiskInfo.first].diskTime.sec; | ||
860 | DiskInfo.lastSession.frame = | ||
861 | Toc[DiskInfo.first].diskTime.frame; | ||
862 | } | ||
863 | |||
864 | aztTocUpToDate = 1; | ||
865 | #ifdef AZT_DEBUG | ||
866 | printk("aztcd: exiting aztUpdateToc Time:%li\n", jiffies); | ||
867 | #endif | ||
868 | return 0; | ||
869 | } | ||
870 | |||
871 | |||
872 | /* Read the table of contents header, i.e. no. of tracks and start of first | ||
873 | * track | ||
874 | */ | ||
875 | static int aztGetDiskInfo(void) | ||
876 | { | ||
877 | int limit; | ||
878 | unsigned char test; | ||
879 | struct azt_Toc qInfo; | ||
880 | |||
881 | #ifdef AZT_DEBUG | ||
882 | printk("aztcd: starting aztGetDiskInfo Time:%li\n", jiffies); | ||
883 | #endif | ||
884 | if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) | ||
885 | RETURNM("aztGetDiskInfo 1", -1); | ||
886 | STEN_LOW_WAIT; | ||
887 | test = 0; | ||
888 | for (limit = 300; limit > 0; limit--) { | ||
889 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
890 | RETURNM("aztGetDiskInfo 2", -1); | ||
891 | if (qInfo.pointIndex == 0xA0) { /*Number of FirstTrack */ | ||
892 | DiskInfo.first = qInfo.diskTime.min; | ||
893 | DiskInfo.first = azt_bcd2bin(DiskInfo.first); | ||
894 | test = test | 0x01; | ||
895 | } | ||
896 | if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */ | ||
897 | DiskInfo.last = qInfo.diskTime.min; | ||
898 | DiskInfo.last = azt_bcd2bin(DiskInfo.last); | ||
899 | test = test | 0x02; | ||
900 | } | ||
901 | if (qInfo.pointIndex == 0xA2) { /*DiskLength */ | ||
902 | DiskInfo.diskLength.min = qInfo.diskTime.min; | ||
903 | DiskInfo.diskLength.sec = qInfo.diskTime.sec; | ||
904 | DiskInfo.diskLength.frame = qInfo.diskTime.frame; | ||
905 | test = test | 0x04; | ||
906 | } | ||
907 | if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) { /*StartTime of First Track */ | ||
908 | DiskInfo.firstTrack.min = qInfo.diskTime.min; | ||
909 | DiskInfo.firstTrack.sec = qInfo.diskTime.sec; | ||
910 | DiskInfo.firstTrack.frame = qInfo.diskTime.frame; | ||
911 | test = test | 0x08; | ||
912 | } | ||
913 | if (test == 0x0F) | ||
914 | break; | ||
915 | } | ||
916 | #ifdef AZT_DEBUG | ||
917 | printk("aztcd: exiting aztGetDiskInfo Time:%li\n", jiffies); | ||
918 | printk | ||
919 | ("Disk Info: first %d last %d length %02X:%02X.%02X dez first %02X:%02X.%02X dez\n", | ||
920 | DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min, | ||
921 | DiskInfo.diskLength.sec, DiskInfo.diskLength.frame, | ||
922 | DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec, | ||
923 | DiskInfo.firstTrack.frame); | ||
924 | #endif | ||
925 | if (test != 0x0F) | ||
926 | return -1; | ||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | #if AZT_MULTISESSION | ||
931 | /* | ||
932 | * Get Multisession Disk Info | ||
933 | */ | ||
934 | static int aztGetMultiDiskInfo(void) | ||
935 | { | ||
936 | int limit, k = 5; | ||
937 | unsigned char test; | ||
938 | struct azt_Toc qInfo; | ||
939 | |||
940 | #ifdef AZT_DEBUG | ||
941 | printk("aztcd: starting aztGetMultiDiskInfo\n"); | ||
942 | #endif | ||
943 | |||
944 | do { | ||
945 | azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min; | ||
946 | azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec; | ||
947 | azt_Play.start.frame = | ||
948 | Toc[DiskInfo.last + 1].diskTime.frame; | ||
949 | test = 0; | ||
950 | |||
951 | for (limit = 30; limit > 0; limit--) { /*Seek for LeadIn of next session */ | ||
952 | if (aztSeek(&azt_Play)) | ||
953 | RETURNM("aztGetMultiDiskInfo 1", -1); | ||
954 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
955 | RETURNM("aztGetMultiDiskInfo 2", -1); | ||
956 | if ((qInfo.track == 0) && (qInfo.pointIndex)) | ||
957 | break; /*LeadIn found */ | ||
958 | if ((azt_Play.start.sec += 10) > 59) { | ||
959 | azt_Play.start.sec = 0; | ||
960 | azt_Play.start.min++; | ||
961 | } | ||
962 | } | ||
963 | if (!limit) | ||
964 | break; /*Check, if a leadin track was found, if not we're | ||
965 | at the end of the disk */ | ||
966 | #ifdef AZT_DEBUG_MULTISESSION | ||
967 | printk("leadin found track %d pointIndex %x limit %d\n", | ||
968 | qInfo.track, qInfo.pointIndex, limit); | ||
969 | #endif | ||
970 | for (limit = 300; limit > 0; limit--) { | ||
971 | if (++azt_Play.start.frame > 74) { | ||
972 | azt_Play.start.frame = 0; | ||
973 | if (azt_Play.start.sec > 59) { | ||
974 | azt_Play.start.sec = 0; | ||
975 | azt_Play.start.min++; | ||
976 | } | ||
977 | } | ||
978 | if (aztSeek(&azt_Play)) | ||
979 | RETURNM("aztGetMultiDiskInfo 3", -1); | ||
980 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
981 | RETURNM("aztGetMultiDiskInfo 4", -1); | ||
982 | if (qInfo.pointIndex == 0xA0) { /*Number of NextTrack */ | ||
983 | DiskInfo.next = qInfo.diskTime.min; | ||
984 | DiskInfo.next = azt_bcd2bin(DiskInfo.next); | ||
985 | test = test | 0x01; | ||
986 | } | ||
987 | if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */ | ||
988 | DiskInfo.last = qInfo.diskTime.min; | ||
989 | DiskInfo.last = azt_bcd2bin(DiskInfo.last); | ||
990 | test = test | 0x02; | ||
991 | } | ||
992 | if (qInfo.pointIndex == 0xA2) { /*DiskLength */ | ||
993 | DiskInfo.diskLength.min = | ||
994 | qInfo.diskTime.min; | ||
995 | DiskInfo.diskLength.sec = | ||
996 | qInfo.diskTime.sec; | ||
997 | DiskInfo.diskLength.frame = | ||
998 | qInfo.diskTime.frame; | ||
999 | test = test | 0x04; | ||
1000 | } | ||
1001 | if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) { /*StartTime of Next Track */ | ||
1002 | DiskInfo.nextSession.min = | ||
1003 | qInfo.diskTime.min; | ||
1004 | DiskInfo.nextSession.sec = | ||
1005 | qInfo.diskTime.sec; | ||
1006 | DiskInfo.nextSession.frame = | ||
1007 | qInfo.diskTime.frame; | ||
1008 | test = test | 0x08; | ||
1009 | } | ||
1010 | if (test == 0x0F) | ||
1011 | break; | ||
1012 | } | ||
1013 | #ifdef AZT_DEBUG_MULTISESSION | ||
1014 | printk | ||
1015 | ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez first %02x:%02x.%02x dez next %02x:%02x.%02x dez\n", | ||
1016 | DiskInfo.first, DiskInfo.next, DiskInfo.last, | ||
1017 | DiskInfo.diskLength.min, DiskInfo.diskLength.sec, | ||
1018 | DiskInfo.diskLength.frame, DiskInfo.firstTrack.min, | ||
1019 | DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame, | ||
1020 | DiskInfo.nextSession.min, DiskInfo.nextSession.sec, | ||
1021 | DiskInfo.nextSession.frame); | ||
1022 | #endif | ||
1023 | if (test != 0x0F) | ||
1024 | break; | ||
1025 | else | ||
1026 | DiskInfo.multi = 1; /*found TOC of more than one session */ | ||
1027 | aztGetToc(1); | ||
1028 | } while (--k); | ||
1029 | |||
1030 | #ifdef AZT_DEBUG | ||
1031 | printk("aztcd: exiting aztGetMultiDiskInfo Time:%li\n", jiffies); | ||
1032 | #endif | ||
1033 | return 0; | ||
1034 | } | ||
1035 | #endif | ||
1036 | |||
1037 | /* | ||
1038 | * Read the table of contents (TOC) | ||
1039 | */ | ||
1040 | static int aztGetToc(int multi) | ||
1041 | { | ||
1042 | int i, px; | ||
1043 | int limit; | ||
1044 | struct azt_Toc qInfo; | ||
1045 | |||
1046 | #ifdef AZT_DEBUG | ||
1047 | printk("aztcd: starting aztGetToc Time:%li\n", jiffies); | ||
1048 | #endif | ||
1049 | if (!multi) { | ||
1050 | for (i = 0; i < MAX_TRACKS; i++) | ||
1051 | Toc[i].pointIndex = 0; | ||
1052 | i = DiskInfo.last + 3; | ||
1053 | } else { | ||
1054 | for (i = DiskInfo.next; i < MAX_TRACKS; i++) | ||
1055 | Toc[i].pointIndex = 0; | ||
1056 | i = DiskInfo.last + 4 - DiskInfo.next; | ||
1057 | } | ||
1058 | |||
1059 | /*Is there a good reason to stop motor before TOC read? | ||
1060 | if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1); | ||
1061 | STEN_LOW_WAIT; | ||
1062 | */ | ||
1063 | |||
1064 | if (!multi) { | ||
1065 | azt_mode = 0x05; | ||
1066 | if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) | ||
1067 | RETURNM("aztGetToc 2", -1); | ||
1068 | STEN_LOW_WAIT; | ||
1069 | } | ||
1070 | for (limit = 300; limit > 0; limit--) { | ||
1071 | if (multi) { | ||
1072 | if (++azt_Play.start.sec > 59) { | ||
1073 | azt_Play.start.sec = 0; | ||
1074 | azt_Play.start.min++; | ||
1075 | } | ||
1076 | if (aztSeek(&azt_Play)) | ||
1077 | RETURNM("aztGetToc 3", -1); | ||
1078 | } | ||
1079 | if (aztGetQChannelInfo(&qInfo) < 0) | ||
1080 | break; | ||
1081 | |||
1082 | px = azt_bcd2bin(qInfo.pointIndex); | ||
1083 | |||
1084 | if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) | ||
1085 | if (Toc[px].pointIndex == 0) { | ||
1086 | Toc[px] = qInfo; | ||
1087 | i--; | ||
1088 | } | ||
1089 | |||
1090 | if (i <= 0) | ||
1091 | break; | ||
1092 | } | ||
1093 | |||
1094 | Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; | ||
1095 | Toc[DiskInfo.last].trackTime = DiskInfo.diskLength; | ||
1096 | |||
1097 | #ifdef AZT_DEBUG_MULTISESSION | ||
1098 | printk("aztcd: exiting aztGetToc\n"); | ||
1099 | for (i = 1; i <= DiskInfo.last + 1; i++) | ||
1100 | printk | ||
1101 | ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n", | ||
1102 | i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, | ||
1103 | Toc[i].trackTime.min, Toc[i].trackTime.sec, | ||
1104 | Toc[i].trackTime.frame, Toc[i].diskTime.min, | ||
1105 | Toc[i].diskTime.sec, Toc[i].diskTime.frame); | ||
1106 | for (i = 100; i < 103; i++) | ||
1107 | printk | ||
1108 | ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n", | ||
1109 | i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, | ||
1110 | Toc[i].trackTime.min, Toc[i].trackTime.sec, | ||
1111 | Toc[i].trackTime.frame, Toc[i].diskTime.min, | ||
1112 | Toc[i].diskTime.sec, Toc[i].diskTime.frame); | ||
1113 | #endif | ||
1114 | |||
1115 | return limit > 0 ? 0 : -1; | ||
1116 | } | ||
1117 | |||
1118 | |||
1119 | /*########################################################################## | ||
1120 | Kernel Interface Functions | ||
1121 | ########################################################################## | ||
1122 | */ | ||
1123 | |||
1124 | #ifndef MODULE | ||
1125 | static int __init aztcd_setup(char *str) | ||
1126 | { | ||
1127 | int ints[4]; | ||
1128 | |||
1129 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
1130 | |||
1131 | if (ints[0] > 0) | ||
1132 | azt_port = ints[1]; | ||
1133 | if (ints[1] > 1) | ||
1134 | azt_cont = ints[2]; | ||
1135 | return 1; | ||
1136 | } | ||
1137 | |||
1138 | __setup("aztcd=", aztcd_setup); | ||
1139 | |||
1140 | #endif /* !MODULE */ | ||
1141 | |||
1142 | /* | ||
1143 | * Checking if the media has been changed | ||
1144 | */ | ||
1145 | static int check_aztcd_media_change(struct gendisk *disk) | ||
1146 | { | ||
1147 | if (aztDiskChanged) { /* disk changed */ | ||
1148 | aztDiskChanged = 0; | ||
1149 | return 1; | ||
1150 | } else | ||
1151 | return 0; /* no change */ | ||
1152 | } | ||
1153 | |||
1154 | /* | ||
1155 | * Kernel IO-controls | ||
1156 | */ | ||
1157 | static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | ||
1158 | unsigned long arg) | ||
1159 | { | ||
1160 | int i; | ||
1161 | struct azt_Toc qInfo; | ||
1162 | struct cdrom_ti ti; | ||
1163 | struct cdrom_tochdr tocHdr; | ||
1164 | struct cdrom_msf msf; | ||
1165 | struct cdrom_tocentry entry; | ||
1166 | struct azt_Toc *tocPtr; | ||
1167 | struct cdrom_subchnl subchnl; | ||
1168 | struct cdrom_volctrl volctrl; | ||
1169 | void __user *argp = (void __user *)arg; | ||
1170 | |||
1171 | #ifdef AZT_DEBUG | ||
1172 | printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n", | ||
1173 | cmd, jiffies); | ||
1174 | printk("aztcd Status %x\n", getAztStatus()); | ||
1175 | #endif | ||
1176 | if (!ip) | ||
1177 | RETURNM("aztcd_ioctl 1", -EINVAL); | ||
1178 | if (getAztStatus() < 0) | ||
1179 | RETURNM("aztcd_ioctl 2", -EIO); | ||
1180 | if ((!aztTocUpToDate) || (aztDiskChanged)) { | ||
1181 | if ((i = aztUpdateToc()) < 0) | ||
1182 | RETURNM("aztcd_ioctl 3", i); /* error reading TOC */ | ||
1183 | } | ||
1184 | |||
1185 | switch (cmd) { | ||
1186 | case CDROMSTART: /* Spin up the drive. Don't know, what to do, | ||
1187 | at least close the tray */ | ||
1188 | #if AZT_PRIVATE_IOCTLS | ||
1189 | if (aztSendCmd(ACMD_CLOSE)) | ||
1190 | RETURNM("aztcd_ioctl 4", -1); | ||
1191 | STEN_LOW_WAIT; | ||
1192 | #endif | ||
1193 | break; | ||
1194 | case CDROMSTOP: /* Spin down the drive */ | ||
1195 | if (aztSendCmd(ACMD_STOP)) | ||
1196 | RETURNM("aztcd_ioctl 5", -1); | ||
1197 | STEN_LOW_WAIT; | ||
1198 | /* should we do anything if it fails? */ | ||
1199 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1200 | break; | ||
1201 | case CDROMPAUSE: /* Pause the drive */ | ||
1202 | if (aztAudioStatus != CDROM_AUDIO_PLAY) | ||
1203 | return -EINVAL; | ||
1204 | |||
1205 | if (aztGetQChannelInfo(&qInfo) < 0) { /* didn't get q channel info */ | ||
1206 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1207 | RETURNM("aztcd_ioctl 7", 0); | ||
1208 | } | ||
1209 | azt_Play.start = qInfo.diskTime; /* remember restart point */ | ||
1210 | |||
1211 | if (aztSendCmd(ACMD_PAUSE)) | ||
1212 | RETURNM("aztcd_ioctl 8", -1); | ||
1213 | STEN_LOW_WAIT; | ||
1214 | aztAudioStatus = CDROM_AUDIO_PAUSED; | ||
1215 | break; | ||
1216 | case CDROMRESUME: /* Play it again, Sam */ | ||
1217 | if (aztAudioStatus != CDROM_AUDIO_PAUSED) | ||
1218 | return -EINVAL; | ||
1219 | /* restart the drive at the saved position. */ | ||
1220 | i = aztPlay(&azt_Play); | ||
1221 | if (i < 0) { | ||
1222 | aztAudioStatus = CDROM_AUDIO_ERROR; | ||
1223 | return -EIO; | ||
1224 | } | ||
1225 | aztAudioStatus = CDROM_AUDIO_PLAY; | ||
1226 | break; | ||
1227 | case CDROMMULTISESSION: /*multisession support -- experimental */ | ||
1228 | { | ||
1229 | struct cdrom_multisession ms; | ||
1230 | #ifdef AZT_DEBUG | ||
1231 | printk("aztcd ioctl MULTISESSION\n"); | ||
1232 | #endif | ||
1233 | if (copy_from_user(&ms, argp, | ||
1234 | sizeof(struct cdrom_multisession))) | ||
1235 | return -EFAULT; | ||
1236 | if (ms.addr_format == CDROM_MSF) { | ||
1237 | ms.addr.msf.minute = | ||
1238 | azt_bcd2bin(DiskInfo.lastSession.min); | ||
1239 | ms.addr.msf.second = | ||
1240 | azt_bcd2bin(DiskInfo.lastSession.sec); | ||
1241 | ms.addr.msf.frame = | ||
1242 | azt_bcd2bin(DiskInfo.lastSession. | ||
1243 | frame); | ||
1244 | } else if (ms.addr_format == CDROM_LBA) | ||
1245 | ms.addr.lba = | ||
1246 | azt_msf2hsg(&DiskInfo.lastSession); | ||
1247 | else | ||
1248 | return -EINVAL; | ||
1249 | ms.xa_flag = DiskInfo.xa; | ||
1250 | if (copy_to_user(argp, &ms, | ||
1251 | sizeof(struct cdrom_multisession))) | ||
1252 | return -EFAULT; | ||
1253 | #ifdef AZT_DEBUG | ||
1254 | if (ms.addr_format == CDROM_MSF) | ||
1255 | printk | ||
1256 | ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n", | ||
1257 | ms.xa_flag, ms.addr.msf.minute, | ||
1258 | ms.addr.msf.second, ms.addr.msf.frame, | ||
1259 | DiskInfo.lastSession.min, | ||
1260 | DiskInfo.lastSession.sec, | ||
1261 | DiskInfo.lastSession.frame); | ||
1262 | else | ||
1263 | printk | ||
1264 | ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n", | ||
1265 | ms.xa_flag, ms.addr.lba, | ||
1266 | DiskInfo.lastSession.min, | ||
1267 | DiskInfo.lastSession.sec, | ||
1268 | DiskInfo.lastSession.frame); | ||
1269 | #endif | ||
1270 | return 0; | ||
1271 | } | ||
1272 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
1273 | if (copy_from_user(&ti, argp, sizeof ti)) | ||
1274 | return -EFAULT; | ||
1275 | if (ti.cdti_trk0 < DiskInfo.first | ||
1276 | || ti.cdti_trk0 > DiskInfo.last | ||
1277 | || ti.cdti_trk1 < ti.cdti_trk0) { | ||
1278 | return -EINVAL; | ||
1279 | } | ||
1280 | if (ti.cdti_trk1 > DiskInfo.last) | ||
1281 | ti.cdti_trk1 = DiskInfo.last; | ||
1282 | azt_Play.start = Toc[ti.cdti_trk0].diskTime; | ||
1283 | azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime; | ||
1284 | #ifdef AZT_DEBUG | ||
1285 | printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n", | ||
1286 | azt_Play.start.min, azt_Play.start.sec, | ||
1287 | azt_Play.start.frame, azt_Play.end.min, | ||
1288 | azt_Play.end.sec, azt_Play.end.frame); | ||
1289 | #endif | ||
1290 | i = aztPlay(&azt_Play); | ||
1291 | if (i < 0) { | ||
1292 | aztAudioStatus = CDROM_AUDIO_ERROR; | ||
1293 | return -EIO; | ||
1294 | } | ||
1295 | aztAudioStatus = CDROM_AUDIO_PLAY; | ||
1296 | break; | ||
1297 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | ||
1298 | /* if (aztAudioStatus == CDROM_AUDIO_PLAY) | ||
1299 | { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1); | ||
1300 | STEN_LOW; | ||
1301 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1302 | } | ||
1303 | */ | ||
1304 | if (copy_from_user(&msf, argp, sizeof msf)) | ||
1305 | return -EFAULT; | ||
1306 | /* convert to bcd */ | ||
1307 | azt_bin2bcd(&msf.cdmsf_min0); | ||
1308 | azt_bin2bcd(&msf.cdmsf_sec0); | ||
1309 | azt_bin2bcd(&msf.cdmsf_frame0); | ||
1310 | azt_bin2bcd(&msf.cdmsf_min1); | ||
1311 | azt_bin2bcd(&msf.cdmsf_sec1); | ||
1312 | azt_bin2bcd(&msf.cdmsf_frame1); | ||
1313 | azt_Play.start.min = msf.cdmsf_min0; | ||
1314 | azt_Play.start.sec = msf.cdmsf_sec0; | ||
1315 | azt_Play.start.frame = msf.cdmsf_frame0; | ||
1316 | azt_Play.end.min = msf.cdmsf_min1; | ||
1317 | azt_Play.end.sec = msf.cdmsf_sec1; | ||
1318 | azt_Play.end.frame = msf.cdmsf_frame1; | ||
1319 | #ifdef AZT_DEBUG | ||
1320 | printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n", | ||
1321 | azt_Play.start.min, azt_Play.start.sec, | ||
1322 | azt_Play.start.frame, azt_Play.end.min, | ||
1323 | azt_Play.end.sec, azt_Play.end.frame); | ||
1324 | #endif | ||
1325 | i = aztPlay(&azt_Play); | ||
1326 | if (i < 0) { | ||
1327 | aztAudioStatus = CDROM_AUDIO_ERROR; | ||
1328 | return -EIO; | ||
1329 | } | ||
1330 | aztAudioStatus = CDROM_AUDIO_PLAY; | ||
1331 | break; | ||
1332 | |||
1333 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
1334 | tocHdr.cdth_trk0 = DiskInfo.first; | ||
1335 | tocHdr.cdth_trk1 = DiskInfo.last; | ||
1336 | if (copy_to_user(argp, &tocHdr, sizeof tocHdr)) | ||
1337 | return -EFAULT; | ||
1338 | break; | ||
1339 | case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ | ||
1340 | if (copy_from_user(&entry, argp, sizeof entry)) | ||
1341 | return -EFAULT; | ||
1342 | if ((!aztTocUpToDate) || aztDiskChanged) | ||
1343 | aztUpdateToc(); | ||
1344 | if (entry.cdte_track == CDROM_LEADOUT) | ||
1345 | tocPtr = &Toc[DiskInfo.last + 1]; | ||
1346 | else if (entry.cdte_track > DiskInfo.last | ||
1347 | || entry.cdte_track < DiskInfo.first) { | ||
1348 | return -EINVAL; | ||
1349 | } else | ||
1350 | tocPtr = &Toc[entry.cdte_track]; | ||
1351 | entry.cdte_adr = tocPtr->ctrl_addr; | ||
1352 | entry.cdte_ctrl = tocPtr->ctrl_addr >> 4; | ||
1353 | if (entry.cdte_format == CDROM_LBA) | ||
1354 | entry.cdte_addr.lba = | ||
1355 | azt_msf2hsg(&tocPtr->diskTime); | ||
1356 | else if (entry.cdte_format == CDROM_MSF) { | ||
1357 | entry.cdte_addr.msf.minute = | ||
1358 | azt_bcd2bin(tocPtr->diskTime.min); | ||
1359 | entry.cdte_addr.msf.second = | ||
1360 | azt_bcd2bin(tocPtr->diskTime.sec); | ||
1361 | entry.cdte_addr.msf.frame = | ||
1362 | azt_bcd2bin(tocPtr->diskTime.frame); | ||
1363 | } else { | ||
1364 | return -EINVAL; | ||
1365 | } | ||
1366 | if (copy_to_user(argp, &entry, sizeof entry)) | ||
1367 | return -EFAULT; | ||
1368 | break; | ||
1369 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
1370 | if (copy_from_user | ||
1371 | (&subchnl, argp, sizeof(struct cdrom_subchnl))) | ||
1372 | return -EFAULT; | ||
1373 | if (aztGetQChannelInfo(&qInfo) < 0) { | ||
1374 | #ifdef AZT_DEBUG | ||
1375 | printk | ||
1376 | ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n", | ||
1377 | cmd); | ||
1378 | #endif | ||
1379 | return -EIO; | ||
1380 | } | ||
1381 | subchnl.cdsc_audiostatus = aztAudioStatus; | ||
1382 | subchnl.cdsc_adr = qInfo.ctrl_addr; | ||
1383 | subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; | ||
1384 | subchnl.cdsc_trk = azt_bcd2bin(qInfo.track); | ||
1385 | subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex); | ||
1386 | if (subchnl.cdsc_format == CDROM_LBA) { | ||
1387 | subchnl.cdsc_absaddr.lba = | ||
1388 | azt_msf2hsg(&qInfo.diskTime); | ||
1389 | subchnl.cdsc_reladdr.lba = | ||
1390 | azt_msf2hsg(&qInfo.trackTime); | ||
1391 | } else { /*default */ | ||
1392 | subchnl.cdsc_format = CDROM_MSF; | ||
1393 | subchnl.cdsc_absaddr.msf.minute = | ||
1394 | azt_bcd2bin(qInfo.diskTime.min); | ||
1395 | subchnl.cdsc_absaddr.msf.second = | ||
1396 | azt_bcd2bin(qInfo.diskTime.sec); | ||
1397 | subchnl.cdsc_absaddr.msf.frame = | ||
1398 | azt_bcd2bin(qInfo.diskTime.frame); | ||
1399 | subchnl.cdsc_reladdr.msf.minute = | ||
1400 | azt_bcd2bin(qInfo.trackTime.min); | ||
1401 | subchnl.cdsc_reladdr.msf.second = | ||
1402 | azt_bcd2bin(qInfo.trackTime.sec); | ||
1403 | subchnl.cdsc_reladdr.msf.frame = | ||
1404 | azt_bcd2bin(qInfo.trackTime.frame); | ||
1405 | } | ||
1406 | if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl))) | ||
1407 | return -EFAULT; | ||
1408 | break; | ||
1409 | case CDROMVOLCTRL: /* Volume control | ||
1410 | * With my Aztech CD268-01A volume control does not work, I can only | ||
1411 | turn the channels on (any value !=0) or off (value==0). Maybe it | ||
1412 | works better with your drive */ | ||
1413 | if (copy_from_user(&volctrl, argp, sizeof(volctrl))) | ||
1414 | return -EFAULT; | ||
1415 | azt_Play.start.min = 0x21; | ||
1416 | azt_Play.start.sec = 0x84; | ||
1417 | azt_Play.start.frame = volctrl.channel0; | ||
1418 | azt_Play.end.min = volctrl.channel1; | ||
1419 | azt_Play.end.sec = volctrl.channel2; | ||
1420 | azt_Play.end.frame = volctrl.channel3; | ||
1421 | sendAztCmd(ACMD_SET_VOLUME, &azt_Play); | ||
1422 | STEN_LOW_WAIT; | ||
1423 | break; | ||
1424 | case CDROMEJECT: | ||
1425 | aztUnlockDoor(); /* Assume user knows what they're doing */ | ||
1426 | /* all drives can at least stop! */ | ||
1427 | if (aztAudioStatus == CDROM_AUDIO_PLAY) { | ||
1428 | if (aztSendCmd(ACMD_STOP)) | ||
1429 | RETURNM("azt_ioctl 10", -1); | ||
1430 | STEN_LOW_WAIT; | ||
1431 | } | ||
1432 | if (aztSendCmd(ACMD_EJECT)) | ||
1433 | RETURNM("azt_ioctl 11", -1); | ||
1434 | STEN_LOW_WAIT; | ||
1435 | aztAudioStatus = CDROM_AUDIO_NO_STATUS; | ||
1436 | break; | ||
1437 | case CDROMEJECT_SW: | ||
1438 | azt_auto_eject = (char) arg; | ||
1439 | break; | ||
1440 | case CDROMRESET: | ||
1441 | outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */ | ||
1442 | STEN_LOW; | ||
1443 | if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */ | ||
1444 | printk | ||
1445 | ("aztcd: AZTECH CD-ROM drive does not respond\n"); | ||
1446 | } | ||
1447 | break; | ||
1448 | /*Take care, the following code is not compatible with other CD-ROM drivers, | ||
1449 | use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h, | ||
1450 | if you do not want to use it! | ||
1451 | */ | ||
1452 | #if AZT_PRIVATE_IOCTLS | ||
1453 | case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes) */ | ||
1454 | case CDROMREADRAW: /*read data in mode 2 (2336 Bytes) */ | ||
1455 | { | ||
1456 | if (copy_from_user(&msf, argp, sizeof msf)) | ||
1457 | return -EFAULT; | ||
1458 | /* convert to bcd */ | ||
1459 | azt_bin2bcd(&msf.cdmsf_min0); | ||
1460 | azt_bin2bcd(&msf.cdmsf_sec0); | ||
1461 | azt_bin2bcd(&msf.cdmsf_frame0); | ||
1462 | msf.cdmsf_min1 = 0; | ||
1463 | msf.cdmsf_sec1 = 0; | ||
1464 | msf.cdmsf_frame1 = 1; /*read only one frame */ | ||
1465 | azt_Play.start.min = msf.cdmsf_min0; | ||
1466 | azt_Play.start.sec = msf.cdmsf_sec0; | ||
1467 | azt_Play.start.frame = msf.cdmsf_frame0; | ||
1468 | azt_Play.end.min = msf.cdmsf_min1; | ||
1469 | azt_Play.end.sec = msf.cdmsf_sec1; | ||
1470 | azt_Play.end.frame = msf.cdmsf_frame1; | ||
1471 | if (cmd == CDROMREADRAW) { | ||
1472 | if (DiskInfo.xa) { | ||
1473 | return -1; /*XA Disks can't be read raw */ | ||
1474 | } else { | ||
1475 | if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) | ||
1476 | return -1; | ||
1477 | DTEN_LOW; | ||
1478 | insb(DATA_PORT, buf, CD_FRAMESIZE_RAW); | ||
1479 | if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW)) | ||
1480 | return -EFAULT; | ||
1481 | } | ||
1482 | } else | ||
1483 | /*CDROMREADCOOKED*/ { | ||
1484 | if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) | ||
1485 | return -1; | ||
1486 | DTEN_LOW; | ||
1487 | insb(DATA_PORT, buf, CD_FRAMESIZE); | ||
1488 | if (copy_to_user(argp, &buf, CD_FRAMESIZE)) | ||
1489 | return -EFAULT; | ||
1490 | } | ||
1491 | } | ||
1492 | break; | ||
1493 | case CDROMSEEK: /*seek msf address */ | ||
1494 | if (copy_from_user(&msf, argp, sizeof msf)) | ||
1495 | return -EFAULT; | ||
1496 | /* convert to bcd */ | ||
1497 | azt_bin2bcd(&msf.cdmsf_min0); | ||
1498 | azt_bin2bcd(&msf.cdmsf_sec0); | ||
1499 | azt_bin2bcd(&msf.cdmsf_frame0); | ||
1500 | azt_Play.start.min = msf.cdmsf_min0; | ||
1501 | azt_Play.start.sec = msf.cdmsf_sec0; | ||
1502 | azt_Play.start.frame = msf.cdmsf_frame0; | ||
1503 | if (aztSeek(&azt_Play)) | ||
1504 | return -1; | ||
1505 | break; | ||
1506 | #endif /*end of incompatible code */ | ||
1507 | case CDROMREADMODE1: /*set read data in mode 1 */ | ||
1508 | return aztSetDiskType(AZT_MODE_1); | ||
1509 | case CDROMREADMODE2: /*set read data in mode 2 */ | ||
1510 | return aztSetDiskType(AZT_MODE_2); | ||
1511 | default: | ||
1512 | return -EINVAL; | ||
1513 | } | ||
1514 | #ifdef AZT_DEBUG | ||
1515 | printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n", cmd, | ||
1516 | jiffies); | ||
1517 | #endif | ||
1518 | return 0; | ||
1519 | } | ||
1520 | |||
1521 | /* | ||
1522 | * Take care of the different block sizes between cdrom and Linux. | ||
1523 | * When Linux gets variable block sizes this will probably go away. | ||
1524 | */ | ||
1525 | static void azt_transfer(void) | ||
1526 | { | ||
1527 | #ifdef AZT_TEST | ||
1528 | printk("aztcd: executing azt_transfer Time:%li\n", jiffies); | ||
1529 | #endif | ||
1530 | if (!current_valid()) | ||
1531 | return; | ||
1532 | |||
1533 | while (CURRENT->nr_sectors) { | ||
1534 | int bn = CURRENT->sector / 4; | ||
1535 | int i; | ||
1536 | for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i); | ||
1537 | if (i < AZT_BUF_SIZ) { | ||
1538 | int offs = (i * 4 + (CURRENT->sector & 3)) * 512; | ||
1539 | int nr_sectors = 4 - (CURRENT->sector & 3); | ||
1540 | if (azt_buf_out != i) { | ||
1541 | azt_buf_out = i; | ||
1542 | if (azt_buf_bn[i] != bn) { | ||
1543 | azt_buf_out = -1; | ||
1544 | continue; | ||
1545 | } | ||
1546 | } | ||
1547 | if (nr_sectors > CURRENT->nr_sectors) | ||
1548 | nr_sectors = CURRENT->nr_sectors; | ||
1549 | memcpy(CURRENT->buffer, azt_buf + offs, | ||
1550 | nr_sectors * 512); | ||
1551 | CURRENT->nr_sectors -= nr_sectors; | ||
1552 | CURRENT->sector += nr_sectors; | ||
1553 | CURRENT->buffer += nr_sectors * 512; | ||
1554 | } else { | ||
1555 | azt_buf_out = -1; | ||
1556 | break; | ||
1557 | } | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | static void do_aztcd_request(request_queue_t * q) | ||
1562 | { | ||
1563 | #ifdef AZT_TEST | ||
1564 | printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector, | ||
1565 | CURRENT->nr_sectors, jiffies); | ||
1566 | #endif | ||
1567 | if (DiskInfo.audio) { | ||
1568 | printk("aztcd: Error, tried to mount an Audio CD\n"); | ||
1569 | end_request(CURRENT, 0); | ||
1570 | return; | ||
1571 | } | ||
1572 | azt_transfer_is_active = 1; | ||
1573 | while (current_valid()) { | ||
1574 | azt_transfer(); | ||
1575 | if (CURRENT->nr_sectors == 0) { | ||
1576 | end_request(CURRENT, 1); | ||
1577 | } else { | ||
1578 | azt_buf_out = -1; /* Want to read a block not in buffer */ | ||
1579 | if (azt_state == AZT_S_IDLE) { | ||
1580 | if ((!aztTocUpToDate) || aztDiskChanged) { | ||
1581 | if (aztUpdateToc() < 0) { | ||
1582 | while (current_valid()) | ||
1583 | end_request(CURRENT, 0); | ||
1584 | break; | ||
1585 | } | ||
1586 | } | ||
1587 | azt_state = AZT_S_START; | ||
1588 | AztTries = 5; | ||
1589 | SET_TIMER(azt_poll, HZ / 100); | ||
1590 | } | ||
1591 | break; | ||
1592 | } | ||
1593 | } | ||
1594 | azt_transfer_is_active = 0; | ||
1595 | #ifdef AZT_TEST2 | ||
1596 | printk | ||
1597 | ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", | ||
1598 | azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]); | ||
1599 | printk(" do_aztcd_request ends Time:%li\n", jiffies); | ||
1600 | #endif | ||
1601 | } | ||
1602 | |||
1603 | |||
1604 | static void azt_invalidate_buffers(void) | ||
1605 | { | ||
1606 | int i; | ||
1607 | |||
1608 | #ifdef AZT_DEBUG | ||
1609 | printk("aztcd: executing azt_invalidate_buffers\n"); | ||
1610 | #endif | ||
1611 | for (i = 0; i < AZT_BUF_SIZ; ++i) | ||
1612 | azt_buf_bn[i] = -1; | ||
1613 | azt_buf_out = -1; | ||
1614 | } | ||
1615 | |||
1616 | /* | ||
1617 | * Open the device special file. Check that a disk is in. | ||
1618 | */ | ||
1619 | static int aztcd_open(struct inode *ip, struct file *fp) | ||
1620 | { | ||
1621 | int st; | ||
1622 | |||
1623 | #ifdef AZT_DEBUG | ||
1624 | printk("aztcd: starting aztcd_open\n"); | ||
1625 | #endif | ||
1626 | |||
1627 | if (aztPresent == 0) | ||
1628 | return -ENXIO; /* no hardware */ | ||
1629 | |||
1630 | if (!azt_open_count && azt_state == AZT_S_IDLE) { | ||
1631 | azt_invalidate_buffers(); | ||
1632 | |||
1633 | st = getAztStatus(); /* check drive status */ | ||
1634 | if (st == -1) | ||
1635 | goto err_out; /* drive doesn't respond */ | ||
1636 | |||
1637 | if (st & AST_DOOR_OPEN) { /* close door, then get the status again. */ | ||
1638 | printk("aztcd: Door Open?\n"); | ||
1639 | aztCloseDoor(); | ||
1640 | st = getAztStatus(); | ||
1641 | } | ||
1642 | |||
1643 | if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) { /*no disk in drive or changed */ | ||
1644 | printk | ||
1645 | ("aztcd: Disk Changed or No Disk in Drive?\n"); | ||
1646 | aztTocUpToDate = 0; | ||
1647 | } | ||
1648 | if (aztUpdateToc()) | ||
1649 | goto err_out; | ||
1650 | |||
1651 | } | ||
1652 | ++azt_open_count; | ||
1653 | aztLockDoor(); | ||
1654 | |||
1655 | #ifdef AZT_DEBUG | ||
1656 | printk("aztcd: exiting aztcd_open\n"); | ||
1657 | #endif | ||
1658 | return 0; | ||
1659 | |||
1660 | err_out: | ||
1661 | return -EIO; | ||
1662 | } | ||
1663 | |||
1664 | |||
1665 | /* | ||
1666 | * On close, we flush all azt blocks from the buffer cache. | ||
1667 | */ | ||
1668 | static int aztcd_release(struct inode *inode, struct file *file) | ||
1669 | { | ||
1670 | #ifdef AZT_DEBUG | ||
1671 | printk("aztcd: executing aztcd_release\n"); | ||
1672 | printk("inode: %p, device: %s file: %p\n", inode, | ||
1673 | inode->i_bdev->bd_disk->disk_name, file); | ||
1674 | #endif | ||
1675 | if (!--azt_open_count) { | ||
1676 | azt_invalidate_buffers(); | ||
1677 | aztUnlockDoor(); | ||
1678 | if (azt_auto_eject) | ||
1679 | aztSendCmd(ACMD_EJECT); | ||
1680 | CLEAR_TIMER; | ||
1681 | } | ||
1682 | return 0; | ||
1683 | } | ||
1684 | |||
1685 | static struct gendisk *azt_disk; | ||
1686 | |||
1687 | /* | ||
1688 | * Test for presence of drive and initialize it. Called at boot time. | ||
1689 | */ | ||
1690 | |||
1691 | static int __init aztcd_init(void) | ||
1692 | { | ||
1693 | long int count, max_count; | ||
1694 | unsigned char result[50]; | ||
1695 | int st; | ||
1696 | void* status = NULL; | ||
1697 | int i = 0; | ||
1698 | int ret = 0; | ||
1699 | |||
1700 | if (azt_port == 0) { | ||
1701 | printk(KERN_INFO "aztcd: no Aztech CD-ROM Initialization"); | ||
1702 | return -EIO; | ||
1703 | } | ||
1704 | |||
1705 | printk(KERN_INFO "aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM " | ||
1706 | "CD-ROM Driver\n"); | ||
1707 | printk(KERN_INFO "aztcd: (C) 1994-98 W.Zimmermann\n"); | ||
1708 | if (azt_port == -1) { | ||
1709 | printk | ||
1710 | ("aztcd: DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n", | ||
1711 | AZT_VERSION); | ||
1712 | } else | ||
1713 | printk | ||
1714 | ("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n", | ||
1715 | AZT_VERSION, azt_port); | ||
1716 | printk(KERN_INFO "aztcd: If you have problems, read /usr/src/linux/" | ||
1717 | "Documentation/cdrom/aztcd\n"); | ||
1718 | |||
1719 | |||
1720 | #ifdef AZT_SW32 /*CDROM connected to Soundwave32 card */ | ||
1721 | if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) { | ||
1722 | printk | ||
1723 | ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n", | ||
1724 | AZT_SW32_BASE_ADDR, AZT_SW32_INIT, | ||
1725 | AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG); | ||
1726 | return -EIO; | ||
1727 | } else { | ||
1728 | printk(KERN_INFO | ||
1729 | "aztcd: Soundwave32 card detected at %x Version %x\n", | ||
1730 | AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG)); | ||
1731 | outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG); | ||
1732 | for (count = 0; count < 10000; count++); /*delay a bit */ | ||
1733 | } | ||
1734 | #endif | ||
1735 | |||
1736 | /* check for presence of drive */ | ||
1737 | |||
1738 | if (azt_port == -1) { /* autoprobing for proprietary interface */ | ||
1739 | for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) { | ||
1740 | azt_port = azt_port_auto[i]; | ||
1741 | printk(KERN_INFO "aztcd: Autoprobing BaseAddress=0x%x" | ||
1742 | "\n", azt_port); | ||
1743 | /*proprietary interfaces need 4 bytes */ | ||
1744 | if (!request_region(azt_port, 4, "aztcd")) { | ||
1745 | continue; | ||
1746 | } | ||
1747 | outb(POLLED, MODE_PORT); | ||
1748 | inb(CMD_PORT); | ||
1749 | inb(CMD_PORT); | ||
1750 | outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */ | ||
1751 | |||
1752 | aztTimeOutCount = 0; | ||
1753 | do { | ||
1754 | aztIndatum = inb(STATUS_PORT); | ||
1755 | aztTimeOutCount++; | ||
1756 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1757 | break; | ||
1758 | } while (aztIndatum & AFL_STATUS); | ||
1759 | if (inb(DATA_PORT) == AFL_OP_OK) { /* OK drive found */ | ||
1760 | break; | ||
1761 | } | ||
1762 | else { /* Drive not found on this port - try next one */ | ||
1763 | release_region(azt_port, 4); | ||
1764 | } | ||
1765 | } | ||
1766 | if ((azt_port_auto[i] == 0) || (i == 16)) { | ||
1767 | printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n"); | ||
1768 | return -EIO; | ||
1769 | } | ||
1770 | } else { /* no autoprobing */ | ||
1771 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) | ||
1772 | status = request_region(azt_port, 8, "aztcd"); /*IDE-interfaces need 8 bytes */ | ||
1773 | else | ||
1774 | status = request_region(azt_port, 4, "aztcd"); /*proprietary interfaces need 4 bytes */ | ||
1775 | if (!status) { | ||
1776 | printk(KERN_WARNING "aztcd: conflict, I/O port (%X) " | ||
1777 | "already used\n", azt_port); | ||
1778 | return -EIO; | ||
1779 | } | ||
1780 | |||
1781 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) | ||
1782 | SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */ | ||
1783 | |||
1784 | outb(POLLED, MODE_PORT); | ||
1785 | inb(CMD_PORT); | ||
1786 | inb(CMD_PORT); | ||
1787 | outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */ | ||
1788 | |||
1789 | aztTimeOutCount = 0; | ||
1790 | do { | ||
1791 | aztIndatum = inb(STATUS_PORT); | ||
1792 | aztTimeOutCount++; | ||
1793 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1794 | break; | ||
1795 | } while (aztIndatum & AFL_STATUS); | ||
1796 | |||
1797 | if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? If not, reset and try again */ | ||
1798 | #ifndef MODULE | ||
1799 | if (azt_cont != 0x79) { | ||
1800 | printk(KERN_WARNING "aztcd: no AZTECH CD-ROM " | ||
1801 | "drive found-Try boot parameter aztcd=" | ||
1802 | "<BaseAddress>,0x79\n"); | ||
1803 | ret = -EIO; | ||
1804 | goto err_out; | ||
1805 | } | ||
1806 | #else | ||
1807 | if (0) { | ||
1808 | } | ||
1809 | #endif | ||
1810 | else { | ||
1811 | printk(KERN_INFO "aztcd: drive reset - " | ||
1812 | "please wait\n"); | ||
1813 | for (count = 0; count < 50; count++) { | ||
1814 | inb(STATUS_PORT); /*removing all data from earlier tries */ | ||
1815 | inb(DATA_PORT); | ||
1816 | } | ||
1817 | outb(POLLED, MODE_PORT); | ||
1818 | inb(CMD_PORT); | ||
1819 | inb(CMD_PORT); | ||
1820 | getAztStatus(); /*trap errors */ | ||
1821 | outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */ | ||
1822 | STEN_LOW; | ||
1823 | if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */ | ||
1824 | printk(KERN_WARNING "aztcd: no AZTECH " | ||
1825 | "CD-ROM drive found\n"); | ||
1826 | ret = -EIO; | ||
1827 | goto err_out; | ||
1828 | } | ||
1829 | |||
1830 | for (count = 0; count < AZT_TIMEOUT; | ||
1831 | count++) | ||
1832 | barrier(); /* Stop gcc 2.96 being smart */ | ||
1833 | /* use udelay(), damnit -- AV */ | ||
1834 | |||
1835 | if ((st = getAztStatus()) == -1) { | ||
1836 | printk(KERN_WARNING "aztcd: Drive Status" | ||
1837 | " Error Status=%x\n", st); | ||
1838 | ret = -EIO; | ||
1839 | goto err_out; | ||
1840 | } | ||
1841 | #ifdef AZT_DEBUG | ||
1842 | printk(KERN_DEBUG "aztcd: Status = %x\n", st); | ||
1843 | #endif | ||
1844 | outb(POLLED, MODE_PORT); | ||
1845 | inb(CMD_PORT); | ||
1846 | inb(CMD_PORT); | ||
1847 | outb(ACMD_GET_VERSION, CMD_PORT); /*GetVersion */ | ||
1848 | STEN_LOW; | ||
1849 | OP_OK; | ||
1850 | } | ||
1851 | } | ||
1852 | } | ||
1853 | |||
1854 | azt_init_end = 1; | ||
1855 | STEN_LOW; | ||
1856 | result[0] = inb(DATA_PORT); /*reading in a null byte??? */ | ||
1857 | for (count = 1; count < 50; count++) { /*Reading version string */ | ||
1858 | aztTimeOutCount = 0; /*here we must implement STEN_LOW differently */ | ||
1859 | do { | ||
1860 | aztIndatum = inb(STATUS_PORT); /*because we want to exit by timeout */ | ||
1861 | aztTimeOutCount++; | ||
1862 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1863 | break; | ||
1864 | } while (aztIndatum & AFL_STATUS); | ||
1865 | if (aztTimeOutCount >= AZT_FAST_TIMEOUT) | ||
1866 | break; /*all chars read? */ | ||
1867 | result[count] = inb(DATA_PORT); | ||
1868 | } | ||
1869 | if (count > 30) | ||
1870 | max_count = 30; /*print max.30 chars of the version string */ | ||
1871 | else | ||
1872 | max_count = count; | ||
1873 | printk(KERN_INFO "aztcd: FirmwareVersion="); | ||
1874 | for (count = 1; count < max_count; count++) | ||
1875 | printk("%c", result[count]); | ||
1876 | printk("<<>> "); | ||
1877 | |||
1878 | if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) { | ||
1879 | printk("AZTECH drive detected\n"); | ||
1880 | /*AZTECH*/} | ||
1881 | else if ((result[2] == 'C') && (result[3] == 'D') | ||
1882 | && (result[4] == 'D')) { | ||
1883 | printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES */ | ||
1884 | } else if ((result[1] == 0x03) && (result[2] == '5')) { | ||
1885 | printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM */ | ||
1886 | } else { /*OTHERS or none */ | ||
1887 | printk("\nunknown drive or firmware version detected\n"); | ||
1888 | printk | ||
1889 | ("aztcd may not run stable, if you want to try anyhow,\n"); | ||
1890 | printk("boot with: aztcd=<BaseAddress>,0x79\n"); | ||
1891 | if ((azt_cont != 0x79)) { | ||
1892 | printk("aztcd: FirmwareVersion="); | ||
1893 | for (count = 1; count < 5; count++) | ||
1894 | printk("%c", result[count]); | ||
1895 | printk("<<>> "); | ||
1896 | printk("Aborted\n"); | ||
1897 | ret = -EIO; | ||
1898 | goto err_out; | ||
1899 | } | ||
1900 | } | ||
1901 | azt_disk = alloc_disk(1); | ||
1902 | if (!azt_disk) | ||
1903 | goto err_out; | ||
1904 | |||
1905 | if (register_blkdev(MAJOR_NR, "aztcd")) { | ||
1906 | ret = -EIO; | ||
1907 | goto err_out2; | ||
1908 | } | ||
1909 | |||
1910 | azt_queue = blk_init_queue(do_aztcd_request, &aztSpin); | ||
1911 | if (!azt_queue) { | ||
1912 | ret = -ENOMEM; | ||
1913 | goto err_out3; | ||
1914 | } | ||
1915 | |||
1916 | blk_queue_hardsect_size(azt_queue, 2048); | ||
1917 | azt_disk->major = MAJOR_NR; | ||
1918 | azt_disk->first_minor = 0; | ||
1919 | azt_disk->fops = &azt_fops; | ||
1920 | sprintf(azt_disk->disk_name, "aztcd"); | ||
1921 | sprintf(azt_disk->devfs_name, "aztcd"); | ||
1922 | azt_disk->queue = azt_queue; | ||
1923 | add_disk(azt_disk); | ||
1924 | azt_invalidate_buffers(); | ||
1925 | aztPresent = 1; | ||
1926 | aztCloseDoor(); | ||
1927 | return 0; | ||
1928 | err_out3: | ||
1929 | unregister_blkdev(MAJOR_NR, "aztcd"); | ||
1930 | err_out2: | ||
1931 | put_disk(azt_disk); | ||
1932 | err_out: | ||
1933 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) { | ||
1934 | SWITCH_IDE_MASTER; | ||
1935 | release_region(azt_port, 8); /*IDE-interface */ | ||
1936 | } else | ||
1937 | release_region(azt_port, 4); /*proprietary interface */ | ||
1938 | return ret; | ||
1939 | |||
1940 | } | ||
1941 | |||
1942 | static void __exit aztcd_exit(void) | ||
1943 | { | ||
1944 | del_gendisk(azt_disk); | ||
1945 | put_disk(azt_disk); | ||
1946 | if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) { | ||
1947 | printk("What's that: can't unregister aztcd\n"); | ||
1948 | return; | ||
1949 | } | ||
1950 | blk_cleanup_queue(azt_queue); | ||
1951 | if ((azt_port == 0x1f0) || (azt_port == 0x170)) { | ||
1952 | SWITCH_IDE_MASTER; | ||
1953 | release_region(azt_port, 8); /*IDE-interface */ | ||
1954 | } else | ||
1955 | release_region(azt_port, 4); /*proprietary interface */ | ||
1956 | printk(KERN_INFO "aztcd module released.\n"); | ||
1957 | } | ||
1958 | |||
1959 | module_init(aztcd_init); | ||
1960 | module_exit(aztcd_exit); | ||
1961 | |||
1962 | /*########################################################################## | ||
1963 | Aztcd State Machine: Controls Drive Operating State | ||
1964 | ########################################################################## | ||
1965 | */ | ||
1966 | static void azt_poll(void) | ||
1967 | { | ||
1968 | int st = 0; | ||
1969 | int loop_ctl = 1; | ||
1970 | int skip = 0; | ||
1971 | |||
1972 | if (azt_error) { | ||
1973 | if (aztSendCmd(ACMD_GET_ERROR)) | ||
1974 | RETURN("azt_poll 1"); | ||
1975 | STEN_LOW; | ||
1976 | azt_error = inb(DATA_PORT) & 0xFF; | ||
1977 | printk("aztcd: I/O error 0x%02x\n", azt_error); | ||
1978 | azt_invalidate_buffers(); | ||
1979 | #ifdef WARN_IF_READ_FAILURE | ||
1980 | if (AztTries == 5) | ||
1981 | printk | ||
1982 | ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", | ||
1983 | azt_next_bn); | ||
1984 | #endif | ||
1985 | if (!AztTries--) { | ||
1986 | printk | ||
1987 | ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", | ||
1988 | azt_next_bn); | ||
1989 | if (azt_transfer_is_active) { | ||
1990 | AztTries = 0; | ||
1991 | loop_ctl = 0; | ||
1992 | } | ||
1993 | if (current_valid()) | ||
1994 | end_request(CURRENT, 0); | ||
1995 | AztTries = 5; | ||
1996 | } | ||
1997 | azt_error = 0; | ||
1998 | azt_state = AZT_S_STOP; | ||
1999 | } | ||
2000 | |||
2001 | while (loop_ctl) { | ||
2002 | loop_ctl = 0; /* each case must flip this back to 1 if we want | ||
2003 | to come back up here */ | ||
2004 | switch (azt_state) { | ||
2005 | |||
2006 | case AZT_S_IDLE: | ||
2007 | #ifdef AZT_TEST3 | ||
2008 | if (azt_state != azt_state_old) { | ||
2009 | azt_state_old = azt_state; | ||
2010 | printk("AZT_S_IDLE\n"); | ||
2011 | } | ||
2012 | #endif | ||
2013 | return; | ||
2014 | |||
2015 | case AZT_S_START: | ||
2016 | #ifdef AZT_TEST3 | ||
2017 | if (azt_state != azt_state_old) { | ||
2018 | azt_state_old = azt_state; | ||
2019 | printk("AZT_S_START\n"); | ||
2020 | } | ||
2021 | #endif | ||
2022 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
2023 | RETURN("azt_poll 2"); /*result will be checked by aztStatus() */ | ||
2024 | azt_state = | ||
2025 | azt_mode == 1 ? AZT_S_READ : AZT_S_MODE; | ||
2026 | AztTimeout = 3000; | ||
2027 | break; | ||
2028 | |||
2029 | case AZT_S_MODE: | ||
2030 | #ifdef AZT_TEST3 | ||
2031 | if (azt_state != azt_state_old) { | ||
2032 | azt_state_old = azt_state; | ||
2033 | printk("AZT_S_MODE\n"); | ||
2034 | } | ||
2035 | #endif | ||
2036 | if (!skip) { | ||
2037 | if ((st = aztStatus()) != -1) { | ||
2038 | if ((st & AST_DSK_CHG) | ||
2039 | || (st & AST_NOT_READY)) { | ||
2040 | aztDiskChanged = 1; | ||
2041 | aztTocUpToDate = 0; | ||
2042 | azt_invalidate_buffers(); | ||
2043 | end_request(CURRENT, 0); | ||
2044 | printk | ||
2045 | ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n"); | ||
2046 | } | ||
2047 | } else | ||
2048 | break; | ||
2049 | } | ||
2050 | skip = 0; | ||
2051 | |||
2052 | if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) { | ||
2053 | aztDiskChanged = 1; | ||
2054 | aztTocUpToDate = 0; | ||
2055 | printk | ||
2056 | ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n"); | ||
2057 | end_request(CURRENT, 0); | ||
2058 | printk((st & AST_DOOR_OPEN) ? | ||
2059 | "aztcd: door open\n" : | ||
2060 | "aztcd: disk removed\n"); | ||
2061 | if (azt_transfer_is_active) { | ||
2062 | azt_state = AZT_S_START; | ||
2063 | loop_ctl = 1; /* goto immediately */ | ||
2064 | break; | ||
2065 | } | ||
2066 | azt_state = AZT_S_IDLE; | ||
2067 | while (current_valid()) | ||
2068 | end_request(CURRENT, 0); | ||
2069 | return; | ||
2070 | } | ||
2071 | |||
2072 | /* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3"); | ||
2073 | outb(0x01, DATA_PORT); | ||
2074 | PA_OK; | ||
2075 | STEN_LOW; | ||
2076 | */ | ||
2077 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
2078 | RETURN("azt_poll 4"); | ||
2079 | STEN_LOW; | ||
2080 | azt_mode = 1; | ||
2081 | azt_state = AZT_S_READ; | ||
2082 | AztTimeout = 3000; | ||
2083 | |||
2084 | break; | ||
2085 | |||
2086 | |||
2087 | case AZT_S_READ: | ||
2088 | #ifdef AZT_TEST3 | ||
2089 | if (azt_state != azt_state_old) { | ||
2090 | azt_state_old = azt_state; | ||
2091 | printk("AZT_S_READ\n"); | ||
2092 | } | ||
2093 | #endif | ||
2094 | if (!skip) { | ||
2095 | if ((st = aztStatus()) != -1) { | ||
2096 | if ((st & AST_DSK_CHG) | ||
2097 | || (st & AST_NOT_READY)) { | ||
2098 | aztDiskChanged = 1; | ||
2099 | aztTocUpToDate = 0; | ||
2100 | azt_invalidate_buffers(); | ||
2101 | printk | ||
2102 | ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n"); | ||
2103 | end_request(CURRENT, 0); | ||
2104 | } | ||
2105 | } else | ||
2106 | break; | ||
2107 | } | ||
2108 | |||
2109 | skip = 0; | ||
2110 | if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) { | ||
2111 | aztDiskChanged = 1; | ||
2112 | aztTocUpToDate = 0; | ||
2113 | printk((st & AST_DOOR_OPEN) ? | ||
2114 | "aztcd: door open\n" : | ||
2115 | "aztcd: disk removed\n"); | ||
2116 | if (azt_transfer_is_active) { | ||
2117 | azt_state = AZT_S_START; | ||
2118 | loop_ctl = 1; | ||
2119 | break; | ||
2120 | } | ||
2121 | azt_state = AZT_S_IDLE; | ||
2122 | while (current_valid()) | ||
2123 | end_request(CURRENT, 0); | ||
2124 | return; | ||
2125 | } | ||
2126 | |||
2127 | if (current_valid()) { | ||
2128 | struct azt_Play_msf msf; | ||
2129 | int i; | ||
2130 | azt_next_bn = CURRENT->sector / 4; | ||
2131 | azt_hsg2msf(azt_next_bn, &msf.start); | ||
2132 | i = 0; | ||
2133 | /* find out in which track we are */ | ||
2134 | while (azt_msf2hsg(&msf.start) > | ||
2135 | azt_msf2hsg(&Toc[++i].trackTime)) { | ||
2136 | }; | ||
2137 | if (azt_msf2hsg(&msf.start) < | ||
2138 | azt_msf2hsg(&Toc[i].trackTime) - | ||
2139 | AZT_BUF_SIZ) { | ||
2140 | azt_read_count = AZT_BUF_SIZ; /*fast, because we read ahead */ | ||
2141 | /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead */ | ||
2142 | } else /* don't read beyond end of track */ | ||
2143 | #if AZT_MULTISESSION | ||
2144 | { | ||
2145 | azt_read_count = | ||
2146 | (azt_msf2hsg(&Toc[i].trackTime) | ||
2147 | / 4) * 4 - | ||
2148 | azt_msf2hsg(&msf.start); | ||
2149 | if (azt_read_count < 0) | ||
2150 | azt_read_count = 0; | ||
2151 | if (azt_read_count > AZT_BUF_SIZ) | ||
2152 | azt_read_count = | ||
2153 | AZT_BUF_SIZ; | ||
2154 | printk | ||
2155 | ("aztcd: warning - trying to read beyond end of track\n"); | ||
2156 | /* printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime)); | ||
2157 | */ } | ||
2158 | #else | ||
2159 | { | ||
2160 | azt_read_count = AZT_BUF_SIZ; | ||
2161 | } | ||
2162 | #endif | ||
2163 | msf.end.min = 0; | ||
2164 | msf.end.sec = 0; | ||
2165 | msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */ | ||
2166 | #ifdef AZT_TEST3 | ||
2167 | printk | ||
2168 | ("---reading msf-address %x:%x:%x %x:%x:%x\n", | ||
2169 | msf.start.min, msf.start.sec, | ||
2170 | msf.start.frame, msf.end.min, | ||
2171 | msf.end.sec, msf.end.frame); | ||
2172 | printk | ||
2173 | ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", | ||
2174 | azt_next_bn, azt_buf_in, azt_buf_out, | ||
2175 | azt_buf_bn[azt_buf_in]); | ||
2176 | #endif | ||
2177 | if (azt_read_mode == AZT_MODE_2) { | ||
2178 | sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode */ | ||
2179 | } else { | ||
2180 | sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode */ | ||
2181 | } | ||
2182 | azt_state = AZT_S_DATA; | ||
2183 | AztTimeout = READ_TIMEOUT; | ||
2184 | } else { | ||
2185 | azt_state = AZT_S_STOP; | ||
2186 | loop_ctl = 1; | ||
2187 | break; | ||
2188 | } | ||
2189 | |||
2190 | break; | ||
2191 | |||
2192 | |||
2193 | case AZT_S_DATA: | ||
2194 | #ifdef AZT_TEST3 | ||
2195 | if (azt_state != azt_state_old) { | ||
2196 | azt_state_old = azt_state; | ||
2197 | printk("AZT_S_DATA\n"); | ||
2198 | } | ||
2199 | #endif | ||
2200 | |||
2201 | st = inb(STATUS_PORT) & AFL_STATUSorDATA; | ||
2202 | |||
2203 | switch (st) { | ||
2204 | |||
2205 | case AFL_DATA: | ||
2206 | #ifdef AZT_TEST3 | ||
2207 | if (st != azt_st_old) { | ||
2208 | azt_st_old = st; | ||
2209 | printk("---AFL_DATA st:%x\n", st); | ||
2210 | } | ||
2211 | #endif | ||
2212 | if (!AztTries--) { | ||
2213 | printk | ||
2214 | ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", | ||
2215 | azt_next_bn); | ||
2216 | if (azt_transfer_is_active) { | ||
2217 | AztTries = 0; | ||
2218 | break; | ||
2219 | } | ||
2220 | if (current_valid()) | ||
2221 | end_request(CURRENT, 0); | ||
2222 | AztTries = 5; | ||
2223 | } | ||
2224 | azt_state = AZT_S_START; | ||
2225 | AztTimeout = READ_TIMEOUT; | ||
2226 | loop_ctl = 1; | ||
2227 | break; | ||
2228 | |||
2229 | case AFL_STATUSorDATA: | ||
2230 | #ifdef AZT_TEST3 | ||
2231 | if (st != azt_st_old) { | ||
2232 | azt_st_old = st; | ||
2233 | printk | ||
2234 | ("---AFL_STATUSorDATA st:%x\n", | ||
2235 | st); | ||
2236 | } | ||
2237 | #endif | ||
2238 | break; | ||
2239 | |||
2240 | default: | ||
2241 | #ifdef AZT_TEST3 | ||
2242 | if (st != azt_st_old) { | ||
2243 | azt_st_old = st; | ||
2244 | printk("---default: st:%x\n", st); | ||
2245 | } | ||
2246 | #endif | ||
2247 | AztTries = 5; | ||
2248 | if (!current_valid() && azt_buf_in == azt_buf_out) { | ||
2249 | azt_state = AZT_S_STOP; | ||
2250 | loop_ctl = 1; | ||
2251 | break; | ||
2252 | } | ||
2253 | if (azt_read_count <= 0) | ||
2254 | printk | ||
2255 | ("aztcd: warning - try to read 0 frames\n"); | ||
2256 | while (azt_read_count) { /*??? fast read ahead loop */ | ||
2257 | azt_buf_bn[azt_buf_in] = -1; | ||
2258 | DTEN_LOW; /*??? unsolved problem, very | ||
2259 | seldom we get timeouts | ||
2260 | here, don't now the real | ||
2261 | reason. With my drive this | ||
2262 | sometimes also happens with | ||
2263 | Aztech's original driver under | ||
2264 | DOS. Is it a hardware bug? | ||
2265 | I tried to recover from such | ||
2266 | situations here. Zimmermann */ | ||
2267 | if (aztTimeOutCount >= AZT_TIMEOUT) { | ||
2268 | printk | ||
2269 | ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", | ||
2270 | azt_read_count, | ||
2271 | CURRENT->nr_sectors, | ||
2272 | azt_buf_in); | ||
2273 | printk | ||
2274 | ("azt_transfer_is_active:%x\n", | ||
2275 | azt_transfer_is_active); | ||
2276 | azt_read_count = 0; | ||
2277 | azt_state = AZT_S_STOP; | ||
2278 | loop_ctl = 1; | ||
2279 | end_request(CURRENT, 1); /*should we have here (1) or (0)? */ | ||
2280 | } else { | ||
2281 | if (azt_read_mode == | ||
2282 | AZT_MODE_2) { | ||
2283 | insb(DATA_PORT, | ||
2284 | azt_buf + | ||
2285 | CD_FRAMESIZE_RAW | ||
2286 | * azt_buf_in, | ||
2287 | CD_FRAMESIZE_RAW); | ||
2288 | } else { | ||
2289 | insb(DATA_PORT, | ||
2290 | azt_buf + | ||
2291 | CD_FRAMESIZE * | ||
2292 | azt_buf_in, | ||
2293 | CD_FRAMESIZE); | ||
2294 | } | ||
2295 | azt_read_count--; | ||
2296 | #ifdef AZT_TEST3 | ||
2297 | printk | ||
2298 | ("AZT_S_DATA; ---I've read data- read_count: %d\n", | ||
2299 | azt_read_count); | ||
2300 | printk | ||
2301 | ("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n", | ||
2302 | azt_next_bn, | ||
2303 | azt_buf_in, | ||
2304 | azt_buf_out, | ||
2305 | azt_buf_bn | ||
2306 | [azt_buf_in]); | ||
2307 | #endif | ||
2308 | azt_buf_bn[azt_buf_in] = | ||
2309 | azt_next_bn++; | ||
2310 | if (azt_buf_out == -1) | ||
2311 | azt_buf_out = | ||
2312 | azt_buf_in; | ||
2313 | azt_buf_in = | ||
2314 | azt_buf_in + 1 == | ||
2315 | AZT_BUF_SIZ ? 0 : | ||
2316 | azt_buf_in + 1; | ||
2317 | } | ||
2318 | } | ||
2319 | if (!azt_transfer_is_active) { | ||
2320 | while (current_valid()) { | ||
2321 | azt_transfer(); | ||
2322 | if (CURRENT->nr_sectors == | ||
2323 | 0) | ||
2324 | end_request(CURRENT, 1); | ||
2325 | else | ||
2326 | break; | ||
2327 | } | ||
2328 | } | ||
2329 | |||
2330 | if (current_valid() | ||
2331 | && (CURRENT->sector / 4 < azt_next_bn | ||
2332 | || CURRENT->sector / 4 > | ||
2333 | azt_next_bn + AZT_BUF_SIZ)) { | ||
2334 | azt_state = AZT_S_STOP; | ||
2335 | loop_ctl = 1; | ||
2336 | break; | ||
2337 | } | ||
2338 | AztTimeout = READ_TIMEOUT; | ||
2339 | if (azt_read_count == 0) { | ||
2340 | azt_state = AZT_S_STOP; | ||
2341 | loop_ctl = 1; | ||
2342 | break; | ||
2343 | } | ||
2344 | break; | ||
2345 | } | ||
2346 | break; | ||
2347 | |||
2348 | |||
2349 | case AZT_S_STOP: | ||
2350 | #ifdef AZT_TEST3 | ||
2351 | if (azt_state != azt_state_old) { | ||
2352 | azt_state_old = azt_state; | ||
2353 | printk("AZT_S_STOP\n"); | ||
2354 | } | ||
2355 | #endif | ||
2356 | if (azt_read_count != 0) | ||
2357 | printk("aztcd: discard data=%x frames\n", | ||
2358 | azt_read_count); | ||
2359 | while (azt_read_count != 0) { | ||
2360 | int i; | ||
2361 | if (!(inb(STATUS_PORT) & AFL_DATA)) { | ||
2362 | if (azt_read_mode == AZT_MODE_2) | ||
2363 | for (i = 0; | ||
2364 | i < CD_FRAMESIZE_RAW; | ||
2365 | i++) | ||
2366 | inb(DATA_PORT); | ||
2367 | else | ||
2368 | for (i = 0; | ||
2369 | i < CD_FRAMESIZE; i++) | ||
2370 | inb(DATA_PORT); | ||
2371 | } | ||
2372 | azt_read_count--; | ||
2373 | } | ||
2374 | if (aztSendCmd(ACMD_GET_STATUS)) | ||
2375 | RETURN("azt_poll 5"); | ||
2376 | azt_state = AZT_S_STOPPING; | ||
2377 | AztTimeout = 1000; | ||
2378 | break; | ||
2379 | |||
2380 | case AZT_S_STOPPING: | ||
2381 | #ifdef AZT_TEST3 | ||
2382 | if (azt_state != azt_state_old) { | ||
2383 | azt_state_old = azt_state; | ||
2384 | printk("AZT_S_STOPPING\n"); | ||
2385 | } | ||
2386 | #endif | ||
2387 | |||
2388 | if ((st = aztStatus()) == -1 && AztTimeout) | ||
2389 | break; | ||
2390 | |||
2391 | if ((st != -1) | ||
2392 | && ((st & AST_DSK_CHG) | ||
2393 | || (st & AST_NOT_READY))) { | ||
2394 | aztDiskChanged = 1; | ||
2395 | aztTocUpToDate = 0; | ||
2396 | azt_invalidate_buffers(); | ||
2397 | printk | ||
2398 | ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n"); | ||
2399 | end_request(CURRENT, 0); | ||
2400 | } | ||
2401 | |||
2402 | #ifdef AZT_TEST3 | ||
2403 | printk("CURRENT_VALID %d azt_mode %d\n", | ||
2404 | current_valid(), azt_mode); | ||
2405 | #endif | ||
2406 | |||
2407 | if (current_valid()) { | ||
2408 | if (st != -1) { | ||
2409 | if (azt_mode == 1) { | ||
2410 | azt_state = AZT_S_READ; | ||
2411 | loop_ctl = 1; | ||
2412 | skip = 1; | ||
2413 | break; | ||
2414 | } else { | ||
2415 | azt_state = AZT_S_MODE; | ||
2416 | loop_ctl = 1; | ||
2417 | skip = 1; | ||
2418 | break; | ||
2419 | } | ||
2420 | } else { | ||
2421 | azt_state = AZT_S_START; | ||
2422 | AztTimeout = 1; | ||
2423 | } | ||
2424 | } else { | ||
2425 | azt_state = AZT_S_IDLE; | ||
2426 | return; | ||
2427 | } | ||
2428 | break; | ||
2429 | |||
2430 | default: | ||
2431 | printk("aztcd: invalid state %d\n", azt_state); | ||
2432 | return; | ||
2433 | } /* case */ | ||
2434 | } /* while */ | ||
2435 | |||
2436 | |||
2437 | if (!AztTimeout--) { | ||
2438 | printk("aztcd: timeout in state %d\n", azt_state); | ||
2439 | azt_state = AZT_S_STOP; | ||
2440 | if (aztSendCmd(ACMD_STOP)) | ||
2441 | RETURN("azt_poll 6"); | ||
2442 | STEN_LOW_WAIT; | ||
2443 | }; | ||
2444 | |||
2445 | SET_TIMER(azt_poll, HZ / 100); | ||
2446 | } | ||
2447 | |||
2448 | |||
2449 | /*########################################################################### | ||
2450 | * Miscellaneous support functions | ||
2451 | ########################################################################### | ||
2452 | */ | ||
2453 | static void azt_hsg2msf(long hsg, struct msf *msf) | ||
2454 | { | ||
2455 | hsg += 150; | ||
2456 | msf->min = hsg / 4500; | ||
2457 | hsg %= 4500; | ||
2458 | msf->sec = hsg / 75; | ||
2459 | msf->frame = hsg % 75; | ||
2460 | #ifdef AZT_DEBUG | ||
2461 | if (msf->min >= 70) | ||
2462 | printk("aztcd: Error hsg2msf address Minutes\n"); | ||
2463 | if (msf->sec >= 60) | ||
2464 | printk("aztcd: Error hsg2msf address Seconds\n"); | ||
2465 | if (msf->frame >= 75) | ||
2466 | printk("aztcd: Error hsg2msf address Frames\n"); | ||
2467 | #endif | ||
2468 | azt_bin2bcd(&msf->min); /* convert to BCD */ | ||
2469 | azt_bin2bcd(&msf->sec); | ||
2470 | azt_bin2bcd(&msf->frame); | ||
2471 | } | ||
2472 | |||
2473 | static long azt_msf2hsg(struct msf *mp) | ||
2474 | { | ||
2475 | return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75 | ||
2476 | + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET; | ||
2477 | } | ||
2478 | |||
2479 | static void azt_bin2bcd(unsigned char *p) | ||
2480 | { | ||
2481 | int u, t; | ||
2482 | |||
2483 | u = *p % 10; | ||
2484 | t = *p / 10; | ||
2485 | *p = u | (t << 4); | ||
2486 | } | ||
2487 | |||
2488 | static int azt_bcd2bin(unsigned char bcd) | ||
2489 | { | ||
2490 | return (bcd >> 4) * 10 + (bcd & 0xF); | ||
2491 | } | ||
2492 | |||
2493 | MODULE_LICENSE("GPL"); | ||
2494 | MODULE_ALIAS_BLOCKDEV_MAJOR(AZTECH_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/aztcd.h b/drivers/cdrom/aztcd.h new file mode 100644 index 000000000000..057501e31628 --- /dev/null +++ b/drivers/cdrom/aztcd.h | |||
@@ -0,0 +1,162 @@ | |||
1 | /* $Id: aztcd.h,v 2.60 1997/11/29 09:51:22 root Exp root $ | ||
2 | * | ||
3 | * Definitions for a AztechCD268 CD-ROM interface | ||
4 | * Copyright (C) 1994-98 Werner Zimmermann | ||
5 | * | ||
6 | * based on Mitsumi CDROM driver by Martin Harriss | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * History: W.Zimmermann adaption to Aztech CD268-01A Version 1.3 | ||
23 | * October 1994 Email: Werner.Zimmermann@fht-esslingen.de | ||
24 | */ | ||
25 | |||
26 | /* *** change this to set the I/O port address of your CD-ROM drive, | ||
27 | set to '-1', if you want autoprobing */ | ||
28 | #define AZT_BASE_ADDR -1 | ||
29 | |||
30 | /* list of autoprobing addresses (not more than 15), last value must be 0x000 | ||
31 | Note: Autoprobing is only enabled, if AZT_BASE_ADDR is set to '-1' ! */ | ||
32 | #define AZT_BASE_AUTO { 0x320, 0x300, 0x310, 0x330, 0x000 } | ||
33 | |||
34 | /* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard | ||
35 | and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */ | ||
36 | /*#define AZT_SW32 1 | ||
37 | */ | ||
38 | |||
39 | #ifdef AZT_SW32 | ||
40 | #define AZT_SW32_BASE_ADDR 0x220 /*I/O port base address of your soundcard*/ | ||
41 | #endif | ||
42 | |||
43 | /* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray | ||
44 | from locking */ | ||
45 | #define AZT_ALLOW_TRAY_LOCK 1 | ||
46 | |||
47 | /*Set this to 1 to allow auto-eject when unmounting a disk, set to 0, if you | ||
48 | don't want the auto-eject feature*/ | ||
49 | #define AZT_AUTO_EJECT 0 | ||
50 | |||
51 | /*Set this to 1, if you want to use incompatible ioctls for reading in raw and | ||
52 | cooked mode */ | ||
53 | #define AZT_PRIVATE_IOCTLS 1 | ||
54 | |||
55 | /*Set this to 1, if you want multisession support by the ISO fs. Even if you set | ||
56 | this value to '0' you can use multisession CDs. In that case the drive's firm- | ||
57 | ware will do the appropriate redirection automatically. The CD will then look | ||
58 | like a single session CD (but nevertheless all data may be read). Please read | ||
59 | chapter '5.1 Multisession support' in README.aztcd for details. Normally it's | ||
60 | uncritical to leave this setting untouched */ | ||
61 | #define AZT_MULTISESSION 1 | ||
62 | |||
63 | /*Uncomment this, if you are using a linux kernel version prior to 2.1.0 */ | ||
64 | /*#define AZT_KERNEL_PRIOR_2_1 */ | ||
65 | |||
66 | /*---------------------------------------------------------------------------*/ | ||
67 | /*-----nothing to be configured for normal applications below this line------*/ | ||
68 | |||
69 | |||
70 | /* Increase this if you get lots of timeouts; if you get kernel panic, replace | ||
71 | STEN_LOW_WAIT by STEN_LOW in the source code */ | ||
72 | #define AZT_STATUS_DELAY 400 /*for timer wait, STEN_LOW_WAIT*/ | ||
73 | #define AZT_TIMEOUT 8000000 /*for busy wait STEN_LOW, DTEN_LOW*/ | ||
74 | #define AZT_FAST_TIMEOUT 10000 /*for reading the version string*/ | ||
75 | |||
76 | /* number of times to retry a command before giving up */ | ||
77 | #define AZT_RETRY_ATTEMPTS 3 | ||
78 | |||
79 | /* port access macros */ | ||
80 | #define CMD_PORT azt_port | ||
81 | #define DATA_PORT azt_port | ||
82 | #define STATUS_PORT azt_port+1 | ||
83 | #define MODE_PORT azt_port+2 | ||
84 | #ifdef AZT_SW32 | ||
85 | #define AZT_SW32_INIT (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16)) | ||
86 | #define AZT_SW32_CONFIG_REG AZT_SW32_BASE_ADDR+0x16 /*Soundwave32 Config. Register*/ | ||
87 | #define AZT_SW32_ID_REG AZT_SW32_BASE_ADDR+0x04 /*Soundwave32 ID Version Register*/ | ||
88 | #endif | ||
89 | |||
90 | /* status bits */ | ||
91 | #define AST_CMD_CHECK 0x80 /* 1 = command error */ | ||
92 | #define AST_DOOR_OPEN 0x40 /* 1 = door is open */ | ||
93 | #define AST_NOT_READY 0x20 /* 1 = no disk in the drive */ | ||
94 | #define AST_DSK_CHG 0x02 /* 1 = disk removed or changed */ | ||
95 | #define AST_MODE 0x01 /* 0=MODE1, 1=MODE2 */ | ||
96 | #define AST_MODE_BITS 0x1C /* Mode Bits */ | ||
97 | #define AST_INITIAL 0x0C /* initial, only valid ... */ | ||
98 | #define AST_BUSY 0x04 /* now playing, only valid | ||
99 | in combination with mode | ||
100 | bits */ | ||
101 | /* flag bits */ | ||
102 | #define AFL_DATA 0x02 /* data available if low */ | ||
103 | #define AFL_STATUS 0x04 /* status available if low */ | ||
104 | #define AFL_OP_OK 0x01 /* OP_OK command correct*/ | ||
105 | #define AFL_PA_OK 0x02 /* PA_OK parameter correct*/ | ||
106 | #define AFL_OP_ERR 0x05 /* error in command*/ | ||
107 | #define AFL_PA_ERR 0x06 /* error in parameters*/ | ||
108 | #define POLLED 0x04 /* polled mode */ | ||
109 | |||
110 | /* commands */ | ||
111 | #define ACMD_SOFT_RESET 0x10 /* reset drive */ | ||
112 | #define ACMD_PLAY_READ 0x20 /* read data track in cooked mode */ | ||
113 | #define ACMD_PLAY_READ_RAW 0x21 /* reading in raw mode*/ | ||
114 | #define ACMD_SEEK 0x30 /* seek msf address*/ | ||
115 | #define ACMD_SEEK_TO_LEADIN 0x31 /* seek to leadin track*/ | ||
116 | #define ACMD_GET_ERROR 0x40 /* get error code */ | ||
117 | #define ACMD_GET_STATUS 0x41 /* get status */ | ||
118 | #define ACMD_GET_Q_CHANNEL 0x50 /* read info from q channel */ | ||
119 | #define ACMD_EJECT 0x60 /* eject/open tray */ | ||
120 | #define ACMD_CLOSE 0x61 /* close tray */ | ||
121 | #define ACMD_LOCK 0x71 /* lock tray closed */ | ||
122 | #define ACMD_UNLOCK 0x72 /* unlock tray */ | ||
123 | #define ACMD_PAUSE 0x80 /* pause */ | ||
124 | #define ACMD_STOP 0x81 /* stop play */ | ||
125 | #define ACMD_PLAY_AUDIO 0x90 /* play audio track */ | ||
126 | #define ACMD_SET_VOLUME 0x93 /* set audio level */ | ||
127 | #define ACMD_GET_VERSION 0xA0 /* get firmware version */ | ||
128 | #define ACMD_SET_DISK_TYPE 0xA1 /* set disk data mode */ | ||
129 | |||
130 | #define MAX_TRACKS 104 | ||
131 | |||
132 | struct msf { | ||
133 | unsigned char min; | ||
134 | unsigned char sec; | ||
135 | unsigned char frame; | ||
136 | }; | ||
137 | |||
138 | struct azt_Play_msf { | ||
139 | struct msf start; | ||
140 | struct msf end; | ||
141 | }; | ||
142 | |||
143 | struct azt_DiskInfo { | ||
144 | unsigned char first; | ||
145 | unsigned char next; | ||
146 | unsigned char last; | ||
147 | struct msf diskLength; | ||
148 | struct msf firstTrack; | ||
149 | unsigned char multi; | ||
150 | struct msf nextSession; | ||
151 | struct msf lastSession; | ||
152 | unsigned char xa; | ||
153 | unsigned char audio; | ||
154 | }; | ||
155 | |||
156 | struct azt_Toc { | ||
157 | unsigned char ctrl_addr; | ||
158 | unsigned char track; | ||
159 | unsigned char pointIndex; | ||
160 | struct msf trackTime; | ||
161 | struct msf diskTime; | ||
162 | }; | ||
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c new file mode 100644 index 000000000000..9deca49c71f0 --- /dev/null +++ b/drivers/cdrom/cdrom.c | |||
@@ -0,0 +1,3397 @@ | |||
1 | /* linux/drivers/cdrom/cdrom.c. | ||
2 | Copyright (c) 1996, 1997 David A. van Leeuwen. | ||
3 | Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org> | ||
4 | Copyright (c) 1998, 1999 Jens Axboe <axboe@image.dk> | ||
5 | |||
6 | May be copied or modified under the terms of the GNU General Public | ||
7 | License. See linux/COPYING for more information. | ||
8 | |||
9 | Uniform CD-ROM driver for Linux. | ||
10 | See Documentation/cdrom/cdrom-standard.tex for usage information. | ||
11 | |||
12 | The routines in the file provide a uniform interface between the | ||
13 | software that uses CD-ROMs and the various low-level drivers that | ||
14 | actually talk to the hardware. Suggestions are welcome. | ||
15 | Patches that work are more welcome though. ;-) | ||
16 | |||
17 | To Do List: | ||
18 | ---------------------------------- | ||
19 | |||
20 | -- Modify sysctl/proc interface. I plan on having one directory per | ||
21 | drive, with entries for outputing general drive information, and sysctl | ||
22 | based tunable parameters such as whether the tray should auto-close for | ||
23 | that drive. Suggestions (or patches) for this welcome! | ||
24 | |||
25 | |||
26 | Revision History | ||
27 | ---------------------------------- | ||
28 | 1.00 Date Unknown -- David van Leeuwen <david@tm.tno.nl> | ||
29 | -- Initial version by David A. van Leeuwen. I don't have a detailed | ||
30 | changelog for the 1.x series, David? | ||
31 | |||
32 | 2.00 Dec 2, 1997 -- Erik Andersen <andersee@debian.org> | ||
33 | -- New maintainer! As David A. van Leeuwen has been too busy to activly | ||
34 | maintain and improve this driver, I am now carrying on the torch. If | ||
35 | you have a problem with this driver, please feel free to contact me. | ||
36 | |||
37 | -- Added (rudimentary) sysctl interface. I realize this is really weak | ||
38 | right now, and is _very_ badly implemented. It will be improved... | ||
39 | |||
40 | -- Modified CDROM_DISC_STATUS so that it is now incorporated into | ||
41 | the Uniform CD-ROM driver via the cdrom_count_tracks function. | ||
42 | The cdrom_count_tracks function helps resolve some of the false | ||
43 | assumptions of the CDROM_DISC_STATUS ioctl, and is also used to check | ||
44 | for the correct media type when mounting or playing audio from a CD. | ||
45 | |||
46 | -- Remove the calls to verify_area and only use the copy_from_user and | ||
47 | copy_to_user stuff, since these calls now provide their own memory | ||
48 | checking with the 2.1.x kernels. | ||
49 | |||
50 | -- Major update to return codes so that errors from low-level drivers | ||
51 | are passed on through (thanks to Gerd Knorr for pointing out this | ||
52 | problem). | ||
53 | |||
54 | -- Made it so if a function isn't implemented in a low-level driver, | ||
55 | ENOSYS is now returned instead of EINVAL. | ||
56 | |||
57 | -- Simplified some complex logic so that the source code is easier to read. | ||
58 | |||
59 | -- Other stuff I probably forgot to mention (lots of changes). | ||
60 | |||
61 | 2.01 to 2.11 Dec 1997-Jan 1998 | ||
62 | -- TO-DO! Write changelogs for 2.01 to 2.12. | ||
63 | |||
64 | 2.12 Jan 24, 1998 -- Erik Andersen <andersee@debian.org> | ||
65 | -- Fixed a bug in the IOCTL_IN and IOCTL_OUT macros. It turns out that | ||
66 | copy_*_user does not return EFAULT on error, but instead returns the number | ||
67 | of bytes not copied. I was returning whatever non-zero stuff came back from | ||
68 | the copy_*_user functions directly, which would result in strange errors. | ||
69 | |||
70 | 2.13 July 17, 1998 -- Erik Andersen <andersee@debian.org> | ||
71 | -- Fixed a bug in CDROM_SELECT_SPEED where you couldn't lower the speed | ||
72 | of the drive. Thanks to Tobias Ringstr|m <tori@prosolvia.se> for pointing | ||
73 | this out and providing a simple fix. | ||
74 | -- Fixed the procfs-unload-module bug with the fill_inode procfs callback. | ||
75 | thanks to Andrea Arcangeli | ||
76 | -- Fixed it so that the /proc entry now also shows up when cdrom is | ||
77 | compiled into the kernel. Before it only worked when loaded as a module. | ||
78 | |||
79 | 2.14 August 17, 1998 -- Erik Andersen <andersee@debian.org> | ||
80 | -- Fixed a bug in cdrom_media_changed and handling of reporting that | ||
81 | the media had changed for devices that _don't_ implement media_changed. | ||
82 | Thanks to Grant R. Guenther <grant@torque.net> for spotting this bug. | ||
83 | -- Made a few things more pedanticly correct. | ||
84 | |||
85 | 2.50 Oct 19, 1998 - Jens Axboe <axboe@image.dk> | ||
86 | -- New maintainers! Erik was too busy to continue the work on the driver, | ||
87 | so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@image.dk> | ||
88 | will do their best to follow in his footsteps | ||
89 | |||
90 | 2.51 Dec 20, 1998 - Jens Axboe <axboe@image.dk> | ||
91 | -- Check if drive is capable of doing what we ask before blindly changing | ||
92 | cdi->options in various ioctl. | ||
93 | -- Added version to proc entry. | ||
94 | |||
95 | 2.52 Jan 16, 1999 - Jens Axboe <axboe@image.dk> | ||
96 | -- Fixed an error in open_for_data where we would sometimes not return | ||
97 | the correct error value. Thanks Huba Gaspar <huba@softcell.hu>. | ||
98 | -- Fixed module usage count - usage was based on /proc/sys/dev | ||
99 | instead of /proc/sys/dev/cdrom. This could lead to an oops when other | ||
100 | modules had entries in dev. Feb 02 - real bug was in sysctl.c where | ||
101 | dev would be removed even though it was used. cdrom.c just illuminated | ||
102 | that bug. | ||
103 | |||
104 | 2.53 Feb 22, 1999 - Jens Axboe <axboe@image.dk> | ||
105 | -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has | ||
106 | been "rewritten" because capabilities and options aren't in sync. They | ||
107 | should be... | ||
108 | -- Added CDROM_LOCKDOOR ioctl. Locks the door and keeps it that way. | ||
109 | -- Added CDROM_RESET ioctl. | ||
110 | -- Added CDROM_DEBUG ioctl. Enable debug messages on-the-fly. | ||
111 | -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs | ||
112 | from parsing /proc/sys/dev/cdrom/info. | ||
113 | |||
114 | 2.54 Mar 15, 1999 - Jens Axboe <axboe@image.dk> | ||
115 | -- Check capability mask from low level driver when counting tracks as | ||
116 | per suggestion from Corey J. Scotts <cstotts@blue.weeg.uiowa.edu>. | ||
117 | |||
118 | 2.55 Apr 25, 1999 - Jens Axboe <axboe@image.dk> | ||
119 | -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of | ||
120 | CDC_CLOSE_TRAY. | ||
121 | -- proc info didn't mask against capabilities mask. | ||
122 | |||
123 | 3.00 Aug 5, 1999 - Jens Axboe <axboe@image.dk> | ||
124 | -- Unified audio ioctl handling across CD-ROM drivers. A lot of the | ||
125 | code was duplicated before. Drives that support the generic packet | ||
126 | interface are now being fed packets from here instead. | ||
127 | -- First attempt at adding support for MMC2 commands - for DVD and | ||
128 | CD-R(W) drives. Only the DVD parts are in now - the interface used is | ||
129 | the same as for the audio ioctls. | ||
130 | -- ioctl cleanups. if a drive couldn't play audio, it didn't get | ||
131 | a change to perform device specific ioctls as well. | ||
132 | -- Defined CDROM_CAN(CDC_XXX) for checking the capabilities. | ||
133 | -- Put in sysctl files for autoclose, autoeject, check_media, debug, | ||
134 | and lock. | ||
135 | -- /proc/sys/dev/cdrom/info has been updated to also contain info about | ||
136 | CD-Rx and DVD capabilities. | ||
137 | -- Now default to checking media type. | ||
138 | -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for | ||
139 | doing this anyway, with the generic_packet addition. | ||
140 | |||
141 | 3.01 Aug 6, 1999 - Jens Axboe <axboe@image.dk> | ||
142 | -- Fix up the sysctl handling so that the option flags get set | ||
143 | correctly. | ||
144 | -- Fix up ioctl handling so the device specific ones actually get | ||
145 | called :). | ||
146 | |||
147 | 3.02 Aug 8, 1999 - Jens Axboe <axboe@image.dk> | ||
148 | -- Fixed volume control on SCSI drives (or others with longer audio | ||
149 | page). | ||
150 | -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath | ||
151 | <andrewtv@usa.net> for telling me and for having defined the various | ||
152 | DVD structures and ioctls in the first place! He designed the original | ||
153 | DVD patches for ide-cd and while I rearranged and unified them, the | ||
154 | interface is still the same. | ||
155 | |||
156 | 3.03 Sep 1, 1999 - Jens Axboe <axboe@image.dk> | ||
157 | -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only | ||
158 | CDROMREADTOCENTRY and CDROMREADTOCHDR are left. | ||
159 | -- Moved the CDROMREADxxx ioctls in here. | ||
160 | -- Defined the cdrom_get_last_written and cdrom_get_next_block as ioctls | ||
161 | and exported functions. | ||
162 | -- Erik Andersen <andersen@xmission.com> modified all SCMD_ commands | ||
163 | to now read GPCMD_ for the new generic packet interface. All low level | ||
164 | drivers are updated as well. | ||
165 | -- Various other cleanups. | ||
166 | |||
167 | 3.04 Sep 12, 1999 - Jens Axboe <axboe@image.dk> | ||
168 | -- Fixed a couple of possible memory leaks (if an operation failed and | ||
169 | we didn't free the buffer before returning the error). | ||
170 | -- Integrated Uniform CD Changer handling from Richard Sharman | ||
171 | <rsharman@pobox.com>. | ||
172 | -- Defined CD_DVD and CD_CHANGER log levels. | ||
173 | -- Fixed the CDROMREADxxx ioctls. | ||
174 | -- CDROMPLAYTRKIND uses the GPCMD_PLAY_AUDIO_MSF command - too few | ||
175 | drives supported it. We lose the index part, however. | ||
176 | -- Small modifications to accommodate opens of /dev/hdc1, required | ||
177 | for ide-cd to handle multisession discs. | ||
178 | -- Export cdrom_mode_sense and cdrom_mode_select. | ||
179 | -- init_cdrom_command() for setting up a cgc command. | ||
180 | |||
181 | 3.05 Oct 24, 1999 - Jens Axboe <axboe@image.dk> | ||
182 | -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually | ||
183 | impossible to send the drive data in a sensible way. | ||
184 | -- Lowered stack usage in mmc_ioctl(), dvd_read_disckey(), and | ||
185 | dvd_read_manufact. | ||
186 | -- Added setup of write mode for packet writing. | ||
187 | -- Fixed CDDA ripping with cdda2wav - accept much larger requests of | ||
188 | number of frames and split the reads in blocks of 8. | ||
189 | |||
190 | 3.06 Dec 13, 1999 - Jens Axboe <axboe@image.dk> | ||
191 | -- Added support for changing the region of DVD drives. | ||
192 | -- Added sense data to generic command. | ||
193 | |||
194 | 3.07 Feb 2, 2000 - Jens Axboe <axboe@suse.de> | ||
195 | -- Do same "read header length" trick in cdrom_get_disc_info() as | ||
196 | we do in cdrom_get_track_info() -- some drive don't obey specs and | ||
197 | fail if they can't supply the full Mt Fuji size table. | ||
198 | -- Deleted stuff related to setting up write modes. It has a different | ||
199 | home now. | ||
200 | -- Clear header length in mode_select unconditionally. | ||
201 | -- Removed the register_disk() that was added, not needed here. | ||
202 | |||
203 | 3.08 May 1, 2000 - Jens Axboe <axboe@suse.de> | ||
204 | -- Fix direction flag in setup_send_key and setup_report_key. This | ||
205 | gave some SCSI adapters problems. | ||
206 | -- Always return -EROFS for write opens | ||
207 | -- Convert to module_init/module_exit style init and remove some | ||
208 | of the #ifdef MODULE stuff | ||
209 | -- Fix several dvd errors - DVD_LU_SEND_ASF should pass agid, | ||
210 | DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and | ||
211 | dvd_do_auth passed uninitialized data to drive because init_cdrom_command | ||
212 | did not clear a 0 sized buffer. | ||
213 | |||
214 | 3.09 May 12, 2000 - Jens Axboe <axboe@suse.de> | ||
215 | -- Fix Video-CD on SCSI drives that don't support READ_CD command. In | ||
216 | that case switch block size and issue plain READ_10 again, then switch | ||
217 | back. | ||
218 | |||
219 | 3.10 Jun 10, 2000 - Jens Axboe <axboe@suse.de> | ||
220 | -- Fix volume control on CD's - old SCSI-II drives now use their own | ||
221 | code, as doing MODE6 stuff in here is really not my intention. | ||
222 | -- Use READ_DISC_INFO for more reliable end-of-disc. | ||
223 | |||
224 | 3.11 Jun 12, 2000 - Jens Axboe <axboe@suse.de> | ||
225 | -- Fix bug in getting rpc phase 2 region info. | ||
226 | -- Reinstate "correct" CDROMPLAYTRKIND | ||
227 | |||
228 | 3.12 Oct 18, 2000 - Jens Axboe <axboe@suse.de> | ||
229 | -- Use quiet bit on packet commands not known to work | ||
230 | |||
231 | 3.20 Dec 17, 2003 - Jens Axboe <axboe@suse.de> | ||
232 | -- Various fixes and lots of cleanups not listed :-) | ||
233 | -- Locking fixes | ||
234 | -- Mt Rainier support | ||
235 | -- DVD-RAM write open fixes | ||
236 | |||
237 | Nov 5 2001, Aug 8 2002. Modified by Andy Polyakov | ||
238 | <appro@fy.chalmers.se> to support MMC-3 compliant DVD+RW units. | ||
239 | |||
240 | Modified by Nigel Kukard <nkukard@lbsd.net> - support DVD+RW | ||
241 | 2.4.x patch by Andy Polyakov <appro@fy.chalmers.se> | ||
242 | |||
243 | -------------------------------------------------------------------------*/ | ||
244 | |||
245 | #define REVISION "Revision: 3.20" | ||
246 | #define VERSION "Id: cdrom.c 3.20 2003/12/17" | ||
247 | |||
248 | /* I use an error-log mask to give fine grain control over the type of | ||
249 | messages dumped to the system logs. The available masks include: */ | ||
250 | #define CD_NOTHING 0x0 | ||
251 | #define CD_WARNING 0x1 | ||
252 | #define CD_REG_UNREG 0x2 | ||
253 | #define CD_DO_IOCTL 0x4 | ||
254 | #define CD_OPEN 0x8 | ||
255 | #define CD_CLOSE 0x10 | ||
256 | #define CD_COUNT_TRACKS 0x20 | ||
257 | #define CD_CHANGER 0x40 | ||
258 | #define CD_DVD 0x80 | ||
259 | |||
260 | /* Define this to remove _all_ the debugging messages */ | ||
261 | /* #define ERRLOGMASK CD_NOTHING */ | ||
262 | #define ERRLOGMASK CD_WARNING | ||
263 | /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ | ||
264 | /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */ | ||
265 | |||
266 | #include <linux/config.h> | ||
267 | #include <linux/module.h> | ||
268 | #include <linux/fs.h> | ||
269 | #include <linux/buffer_head.h> | ||
270 | #include <linux/major.h> | ||
271 | #include <linux/types.h> | ||
272 | #include <linux/errno.h> | ||
273 | #include <linux/kernel.h> | ||
274 | #include <linux/mm.h> | ||
275 | #include <linux/slab.h> | ||
276 | #include <linux/cdrom.h> | ||
277 | #include <linux/sysctl.h> | ||
278 | #include <linux/proc_fs.h> | ||
279 | #include <linux/blkpg.h> | ||
280 | #include <linux/init.h> | ||
281 | #include <linux/fcntl.h> | ||
282 | #include <linux/blkdev.h> | ||
283 | #include <linux/times.h> | ||
284 | |||
285 | #include <asm/uaccess.h> | ||
286 | |||
287 | /* used to tell the module to turn on full debugging messages */ | ||
288 | static int debug; | ||
289 | /* used to keep tray locked at all times */ | ||
290 | static int keeplocked; | ||
291 | /* default compatibility mode */ | ||
292 | static int autoclose=1; | ||
293 | static int autoeject; | ||
294 | static int lockdoor = 1; | ||
295 | /* will we ever get to use this... sigh. */ | ||
296 | static int check_media_type; | ||
297 | /* automatically restart mrw format */ | ||
298 | static int mrw_format_restart = 1; | ||
299 | module_param(debug, bool, 0); | ||
300 | module_param(autoclose, bool, 0); | ||
301 | module_param(autoeject, bool, 0); | ||
302 | module_param(lockdoor, bool, 0); | ||
303 | module_param(check_media_type, bool, 0); | ||
304 | module_param(mrw_format_restart, bool, 0); | ||
305 | |||
306 | static DEFINE_SPINLOCK(cdrom_lock); | ||
307 | |||
308 | static const char *mrw_format_status[] = { | ||
309 | "not mrw", | ||
310 | "bgformat inactive", | ||
311 | "bgformat active", | ||
312 | "mrw complete", | ||
313 | }; | ||
314 | |||
315 | static const char *mrw_address_space[] = { "DMA", "GAA" }; | ||
316 | |||
317 | #if (ERRLOGMASK!=CD_NOTHING) | ||
318 | #define cdinfo(type, fmt, args...) \ | ||
319 | if ((ERRLOGMASK & type) || debug==1 ) \ | ||
320 | printk(KERN_INFO "cdrom: " fmt, ## args) | ||
321 | #else | ||
322 | #define cdinfo(type, fmt, args...) | ||
323 | #endif | ||
324 | |||
325 | /* These are used to simplify getting data in from and back to user land */ | ||
326 | #define IOCTL_IN(arg, type, in) \ | ||
327 | if (copy_from_user(&(in), (type __user *) (arg), sizeof (in))) \ | ||
328 | return -EFAULT; | ||
329 | |||
330 | #define IOCTL_OUT(arg, type, out) \ | ||
331 | if (copy_to_user((type __user *) (arg), &(out), sizeof (out))) \ | ||
332 | return -EFAULT; | ||
333 | |||
334 | /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in | ||
335 | a lot of places. This macro makes the code more clear. */ | ||
336 | #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type)) | ||
337 | |||
338 | /* used in the audio ioctls */ | ||
339 | #define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret | ||
340 | |||
341 | /* Not-exported routines. */ | ||
342 | static int open_for_data(struct cdrom_device_info * cdi); | ||
343 | static int check_for_audio_disc(struct cdrom_device_info * cdi, | ||
344 | struct cdrom_device_ops * cdo); | ||
345 | static void sanitize_format(union cdrom_addr *addr, | ||
346 | u_char * curr, u_char requested); | ||
347 | static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | ||
348 | unsigned long arg); | ||
349 | |||
350 | int cdrom_get_last_written(struct cdrom_device_info *, long *); | ||
351 | static int cdrom_get_next_writable(struct cdrom_device_info *, long *); | ||
352 | static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*); | ||
353 | |||
354 | static int cdrom_mrw_exit(struct cdrom_device_info *cdi); | ||
355 | |||
356 | static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di); | ||
357 | |||
358 | #ifdef CONFIG_SYSCTL | ||
359 | static void cdrom_sysctl_register(void); | ||
360 | #endif /* CONFIG_SYSCTL */ | ||
361 | static struct cdrom_device_info *topCdromPtr; | ||
362 | |||
363 | static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, | ||
364 | struct packet_command *cgc) | ||
365 | { | ||
366 | if (cgc->sense) { | ||
367 | cgc->sense->sense_key = 0x05; | ||
368 | cgc->sense->asc = 0x20; | ||
369 | cgc->sense->ascq = 0x00; | ||
370 | } | ||
371 | |||
372 | cgc->stat = -EIO; | ||
373 | return -EIO; | ||
374 | } | ||
375 | |||
376 | /* This macro makes sure we don't have to check on cdrom_device_ops | ||
377 | * existence in the run-time routines below. Change_capability is a | ||
378 | * hack to have the capability flags defined const, while we can still | ||
379 | * change it here without gcc complaining at every line. | ||
380 | */ | ||
381 | #define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits) | ||
382 | |||
383 | int register_cdrom(struct cdrom_device_info *cdi) | ||
384 | { | ||
385 | static char banner_printed; | ||
386 | struct cdrom_device_ops *cdo = cdi->ops; | ||
387 | int *change_capability = (int *)&cdo->capability; /* hack */ | ||
388 | |||
389 | cdinfo(CD_OPEN, "entering register_cdrom\n"); | ||
390 | |||
391 | if (cdo->open == NULL || cdo->release == NULL) | ||
392 | return -2; | ||
393 | if (!banner_printed) { | ||
394 | printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n"); | ||
395 | banner_printed = 1; | ||
396 | #ifdef CONFIG_SYSCTL | ||
397 | cdrom_sysctl_register(); | ||
398 | #endif /* CONFIG_SYSCTL */ | ||
399 | } | ||
400 | |||
401 | ENSURE(drive_status, CDC_DRIVE_STATUS ); | ||
402 | ENSURE(media_changed, CDC_MEDIA_CHANGED); | ||
403 | ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); | ||
404 | ENSURE(lock_door, CDC_LOCK); | ||
405 | ENSURE(select_speed, CDC_SELECT_SPEED); | ||
406 | ENSURE(get_last_session, CDC_MULTI_SESSION); | ||
407 | ENSURE(get_mcn, CDC_MCN); | ||
408 | ENSURE(reset, CDC_RESET); | ||
409 | ENSURE(audio_ioctl, CDC_PLAY_AUDIO); | ||
410 | ENSURE(dev_ioctl, CDC_IOCTLS); | ||
411 | ENSURE(generic_packet, CDC_GENERIC_PACKET); | ||
412 | cdi->mc_flags = 0; | ||
413 | cdo->n_minors = 0; | ||
414 | cdi->options = CDO_USE_FFLAGS; | ||
415 | |||
416 | if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY)) | ||
417 | cdi->options |= (int) CDO_AUTO_CLOSE; | ||
418 | if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY)) | ||
419 | cdi->options |= (int) CDO_AUTO_EJECT; | ||
420 | if (lockdoor==1) | ||
421 | cdi->options |= (int) CDO_LOCK; | ||
422 | if (check_media_type==1) | ||
423 | cdi->options |= (int) CDO_CHECK_TYPE; | ||
424 | |||
425 | if (CDROM_CAN(CDC_MRW_W)) | ||
426 | cdi->exit = cdrom_mrw_exit; | ||
427 | |||
428 | if (cdi->disk) | ||
429 | cdi->cdda_method = CDDA_BPC_FULL; | ||
430 | else | ||
431 | cdi->cdda_method = CDDA_OLD; | ||
432 | |||
433 | if (!cdo->generic_packet) | ||
434 | cdo->generic_packet = cdrom_dummy_generic_packet; | ||
435 | |||
436 | cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); | ||
437 | spin_lock(&cdrom_lock); | ||
438 | cdi->next = topCdromPtr; | ||
439 | topCdromPtr = cdi; | ||
440 | spin_unlock(&cdrom_lock); | ||
441 | return 0; | ||
442 | } | ||
443 | #undef ENSURE | ||
444 | |||
445 | int unregister_cdrom(struct cdrom_device_info *unreg) | ||
446 | { | ||
447 | struct cdrom_device_info *cdi, *prev; | ||
448 | cdinfo(CD_OPEN, "entering unregister_cdrom\n"); | ||
449 | |||
450 | prev = NULL; | ||
451 | spin_lock(&cdrom_lock); | ||
452 | cdi = topCdromPtr; | ||
453 | while (cdi && cdi != unreg) { | ||
454 | prev = cdi; | ||
455 | cdi = cdi->next; | ||
456 | } | ||
457 | |||
458 | if (cdi == NULL) { | ||
459 | spin_unlock(&cdrom_lock); | ||
460 | return -2; | ||
461 | } | ||
462 | if (prev) | ||
463 | prev->next = cdi->next; | ||
464 | else | ||
465 | topCdromPtr = cdi->next; | ||
466 | |||
467 | spin_unlock(&cdrom_lock); | ||
468 | |||
469 | if (cdi->exit) | ||
470 | cdi->exit(cdi); | ||
471 | |||
472 | cdi->ops->n_minors--; | ||
473 | cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | int cdrom_get_media_event(struct cdrom_device_info *cdi, | ||
478 | struct media_event_desc *med) | ||
479 | { | ||
480 | struct packet_command cgc; | ||
481 | unsigned char buffer[8]; | ||
482 | struct event_header *eh = (struct event_header *) buffer; | ||
483 | |||
484 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
485 | cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; | ||
486 | cgc.cmd[1] = 1; /* IMMED */ | ||
487 | cgc.cmd[4] = 1 << 4; /* media event */ | ||
488 | cgc.cmd[8] = sizeof(buffer); | ||
489 | cgc.quiet = 1; | ||
490 | |||
491 | if (cdi->ops->generic_packet(cdi, &cgc)) | ||
492 | return 1; | ||
493 | |||
494 | if (be16_to_cpu(eh->data_len) < sizeof(*med)) | ||
495 | return 1; | ||
496 | |||
497 | if (eh->nea || eh->notification_class != 0x4) | ||
498 | return 1; | ||
499 | |||
500 | memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * the first prototypes used 0x2c as the page code for the mrw mode page, | ||
506 | * subsequently this was changed to 0x03. probe the one used by this drive | ||
507 | */ | ||
508 | static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi) | ||
509 | { | ||
510 | struct packet_command cgc; | ||
511 | char buffer[16]; | ||
512 | |||
513 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
514 | |||
515 | cgc.timeout = HZ; | ||
516 | cgc.quiet = 1; | ||
517 | |||
518 | if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { | ||
519 | cdi->mrw_mode_page = MRW_MODE_PC; | ||
520 | return 0; | ||
521 | } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { | ||
522 | cdi->mrw_mode_page = MRW_MODE_PC_PRE1; | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | return 1; | ||
527 | } | ||
528 | |||
529 | static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write) | ||
530 | { | ||
531 | struct packet_command cgc; | ||
532 | struct mrw_feature_desc *mfd; | ||
533 | unsigned char buffer[16]; | ||
534 | int ret; | ||
535 | |||
536 | *write = 0; | ||
537 | |||
538 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
539 | |||
540 | cgc.cmd[0] = GPCMD_GET_CONFIGURATION; | ||
541 | cgc.cmd[3] = CDF_MRW; | ||
542 | cgc.cmd[8] = sizeof(buffer); | ||
543 | cgc.quiet = 1; | ||
544 | |||
545 | if ((ret = cdi->ops->generic_packet(cdi, &cgc))) | ||
546 | return ret; | ||
547 | |||
548 | mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; | ||
549 | if (be16_to_cpu(mfd->feature_code) != CDF_MRW) | ||
550 | return 1; | ||
551 | *write = mfd->write; | ||
552 | |||
553 | if ((ret = cdrom_mrw_probe_pc(cdi))) { | ||
554 | *write = 0; | ||
555 | return ret; | ||
556 | } | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) | ||
562 | { | ||
563 | struct packet_command cgc; | ||
564 | unsigned char buffer[12]; | ||
565 | int ret; | ||
566 | |||
567 | printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); | ||
568 | |||
569 | /* | ||
570 | * FmtData bit set (bit 4), format type is 1 | ||
571 | */ | ||
572 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); | ||
573 | cgc.cmd[0] = GPCMD_FORMAT_UNIT; | ||
574 | cgc.cmd[1] = (1 << 4) | 1; | ||
575 | |||
576 | cgc.timeout = 5 * 60 * HZ; | ||
577 | |||
578 | /* | ||
579 | * 4 byte format list header, 8 byte format list descriptor | ||
580 | */ | ||
581 | buffer[1] = 1 << 1; | ||
582 | buffer[3] = 8; | ||
583 | |||
584 | /* | ||
585 | * nr_blocks field | ||
586 | */ | ||
587 | buffer[4] = 0xff; | ||
588 | buffer[5] = 0xff; | ||
589 | buffer[6] = 0xff; | ||
590 | buffer[7] = 0xff; | ||
591 | |||
592 | buffer[8] = 0x24 << 2; | ||
593 | buffer[11] = cont; | ||
594 | |||
595 | ret = cdi->ops->generic_packet(cdi, &cgc); | ||
596 | if (ret) | ||
597 | printk(KERN_INFO "cdrom: bgformat failed\n"); | ||
598 | |||
599 | return ret; | ||
600 | } | ||
601 | |||
602 | static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed) | ||
603 | { | ||
604 | struct packet_command cgc; | ||
605 | |||
606 | init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | ||
607 | cgc.cmd[0] = GPCMD_CLOSE_TRACK; | ||
608 | |||
609 | /* | ||
610 | * Session = 1, Track = 0 | ||
611 | */ | ||
612 | cgc.cmd[1] = !!immed; | ||
613 | cgc.cmd[2] = 1 << 1; | ||
614 | |||
615 | cgc.timeout = 5 * 60 * HZ; | ||
616 | |||
617 | return cdi->ops->generic_packet(cdi, &cgc); | ||
618 | } | ||
619 | |||
620 | static int cdrom_flush_cache(struct cdrom_device_info *cdi) | ||
621 | { | ||
622 | struct packet_command cgc; | ||
623 | |||
624 | init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | ||
625 | cgc.cmd[0] = GPCMD_FLUSH_CACHE; | ||
626 | |||
627 | cgc.timeout = 5 * 60 * HZ; | ||
628 | |||
629 | return cdi->ops->generic_packet(cdi, &cgc); | ||
630 | } | ||
631 | |||
632 | static int cdrom_mrw_exit(struct cdrom_device_info *cdi) | ||
633 | { | ||
634 | disc_information di; | ||
635 | int ret; | ||
636 | |||
637 | ret = cdrom_get_disc_info(cdi, &di); | ||
638 | if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type)) | ||
639 | return 1; | ||
640 | |||
641 | ret = 0; | ||
642 | if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { | ||
643 | printk(KERN_INFO "cdrom: issuing MRW back ground " | ||
644 | "format suspend\n"); | ||
645 | ret = cdrom_mrw_bgformat_susp(cdi, 0); | ||
646 | } | ||
647 | |||
648 | if (!ret) | ||
649 | ret = cdrom_flush_cache(cdi); | ||
650 | |||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) | ||
655 | { | ||
656 | struct packet_command cgc; | ||
657 | struct mode_page_header *mph; | ||
658 | char buffer[16]; | ||
659 | int ret, offset, size; | ||
660 | |||
661 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
662 | |||
663 | cgc.buffer = buffer; | ||
664 | cgc.buflen = sizeof(buffer); | ||
665 | |||
666 | if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) | ||
667 | return ret; | ||
668 | |||
669 | mph = (struct mode_page_header *) buffer; | ||
670 | offset = be16_to_cpu(mph->desc_length); | ||
671 | size = be16_to_cpu(mph->mode_data_length) + 2; | ||
672 | |||
673 | buffer[offset + 3] = space; | ||
674 | cgc.buflen = size; | ||
675 | |||
676 | if ((ret = cdrom_mode_select(cdi, &cgc))) | ||
677 | return ret; | ||
678 | |||
679 | printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static int cdrom_get_random_writable(struct cdrom_device_info *cdi, | ||
684 | struct rwrt_feature_desc *rfd) | ||
685 | { | ||
686 | struct packet_command cgc; | ||
687 | char buffer[24]; | ||
688 | int ret; | ||
689 | |||
690 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
691 | |||
692 | cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */ | ||
693 | cgc.cmd[3] = CDF_RWRT; /* often 0x0020 */ | ||
694 | cgc.cmd[8] = sizeof(buffer); /* often 0x18 */ | ||
695 | cgc.quiet = 1; | ||
696 | |||
697 | if ((ret = cdi->ops->generic_packet(cdi, &cgc))) | ||
698 | return ret; | ||
699 | |||
700 | memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd)); | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) | ||
705 | { | ||
706 | struct packet_command cgc; | ||
707 | char buffer[16]; | ||
708 | __u16 *feature_code; | ||
709 | int ret; | ||
710 | |||
711 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
712 | |||
713 | cgc.cmd[0] = GPCMD_GET_CONFIGURATION; | ||
714 | cgc.cmd[3] = CDF_HWDM; | ||
715 | cgc.cmd[8] = sizeof(buffer); | ||
716 | cgc.quiet = 1; | ||
717 | |||
718 | if ((ret = cdi->ops->generic_packet(cdi, &cgc))) | ||
719 | return ret; | ||
720 | |||
721 | feature_code = (__u16 *) &buffer[sizeof(struct feature_header)]; | ||
722 | if (be16_to_cpu(*feature_code) == CDF_HWDM) | ||
723 | return 0; | ||
724 | |||
725 | return 1; | ||
726 | } | ||
727 | |||
728 | |||
729 | static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) | ||
730 | { | ||
731 | struct rwrt_feature_desc rfd; | ||
732 | int ret; | ||
733 | |||
734 | *write = 0; | ||
735 | |||
736 | if ((ret = cdrom_get_random_writable(cdi, &rfd))) | ||
737 | return ret; | ||
738 | |||
739 | if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) | ||
740 | *write = 1; | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static int cdrom_media_erasable(struct cdrom_device_info *cdi) | ||
746 | { | ||
747 | disc_information di; | ||
748 | int ret; | ||
749 | |||
750 | ret = cdrom_get_disc_info(cdi, &di); | ||
751 | if (ret < 0 || ret < offsetof(typeof(di), n_first_track)) | ||
752 | return -1; | ||
753 | |||
754 | return di.erasable; | ||
755 | } | ||
756 | |||
757 | /* | ||
758 | * FIXME: check RO bit | ||
759 | */ | ||
760 | static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi) | ||
761 | { | ||
762 | int ret = cdrom_media_erasable(cdi); | ||
763 | |||
764 | /* | ||
765 | * allow writable open if media info read worked and media is | ||
766 | * erasable, _or_ if it fails since not all drives support it | ||
767 | */ | ||
768 | if (!ret) | ||
769 | return 1; | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) | ||
775 | { | ||
776 | disc_information di; | ||
777 | int ret; | ||
778 | |||
779 | /* | ||
780 | * always reset to DMA lba space on open | ||
781 | */ | ||
782 | if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) { | ||
783 | printk(KERN_ERR "cdrom: failed setting lba address space\n"); | ||
784 | return 1; | ||
785 | } | ||
786 | |||
787 | ret = cdrom_get_disc_info(cdi, &di); | ||
788 | if (ret < 0 || ret < offsetof(typeof(di),disc_type)) | ||
789 | return 1; | ||
790 | |||
791 | if (!di.erasable) | ||
792 | return 1; | ||
793 | |||
794 | /* | ||
795 | * mrw_status | ||
796 | * 0 - not MRW formatted | ||
797 | * 1 - MRW bgformat started, but not running or complete | ||
798 | * 2 - MRW bgformat in progress | ||
799 | * 3 - MRW formatting complete | ||
800 | */ | ||
801 | ret = 0; | ||
802 | printk(KERN_INFO "cdrom open: mrw_status '%s'\n", | ||
803 | mrw_format_status[di.mrw_status]); | ||
804 | if (!di.mrw_status) | ||
805 | ret = 1; | ||
806 | else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && | ||
807 | mrw_format_restart) | ||
808 | ret = cdrom_mrw_bgformat(cdi, 1); | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | static int mo_open_write(struct cdrom_device_info *cdi) | ||
814 | { | ||
815 | struct packet_command cgc; | ||
816 | char buffer[255]; | ||
817 | int ret; | ||
818 | |||
819 | init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ); | ||
820 | cgc.quiet = 1; | ||
821 | |||
822 | /* | ||
823 | * obtain write protect information as per | ||
824 | * drivers/scsi/sd.c:sd_read_write_protect_flag | ||
825 | */ | ||
826 | |||
827 | ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); | ||
828 | if (ret) | ||
829 | ret = cdrom_mode_sense(cdi, &cgc, GPMODE_VENDOR_PAGE, 0); | ||
830 | if (ret) { | ||
831 | cgc.buflen = 255; | ||
832 | ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); | ||
833 | } | ||
834 | |||
835 | /* drive gave us no info, let the user go ahead */ | ||
836 | if (ret) | ||
837 | return 0; | ||
838 | |||
839 | return buffer[3] & 0x80; | ||
840 | } | ||
841 | |||
842 | static int cdrom_ram_open_write(struct cdrom_device_info *cdi) | ||
843 | { | ||
844 | struct rwrt_feature_desc rfd; | ||
845 | int ret; | ||
846 | |||
847 | if ((ret = cdrom_has_defect_mgt(cdi))) | ||
848 | return ret; | ||
849 | |||
850 | if ((ret = cdrom_get_random_writable(cdi, &rfd))) | ||
851 | return ret; | ||
852 | else if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) | ||
853 | ret = !rfd.curr; | ||
854 | |||
855 | cdinfo(CD_OPEN, "can open for random write\n"); | ||
856 | return ret; | ||
857 | } | ||
858 | |||
859 | static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) | ||
860 | { | ||
861 | struct packet_command cgc; | ||
862 | char buffer[32]; | ||
863 | int ret, mmc3_profile; | ||
864 | |||
865 | init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); | ||
866 | |||
867 | cgc.cmd[0] = GPCMD_GET_CONFIGURATION; | ||
868 | cgc.cmd[1] = 0; | ||
869 | cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */ | ||
870 | cgc.cmd[8] = sizeof(buffer); /* Allocation Length */ | ||
871 | cgc.quiet = 1; | ||
872 | |||
873 | if ((ret = cdi->ops->generic_packet(cdi, &cgc))) | ||
874 | mmc3_profile = 0xffff; | ||
875 | else | ||
876 | mmc3_profile = (buffer[6] << 8) | buffer[7]; | ||
877 | |||
878 | cdi->mmc3_profile = mmc3_profile; | ||
879 | } | ||
880 | |||
881 | static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) | ||
882 | { | ||
883 | switch (cdi->mmc3_profile) { | ||
884 | case 0x12: /* DVD-RAM */ | ||
885 | case 0x1A: /* DVD+RW */ | ||
886 | return 0; | ||
887 | default: | ||
888 | return 1; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | /* | ||
893 | * returns 0 for ok to open write, non-0 to disallow | ||
894 | */ | ||
895 | static int cdrom_open_write(struct cdrom_device_info *cdi) | ||
896 | { | ||
897 | int mrw, mrw_write, ram_write; | ||
898 | int ret = 1; | ||
899 | |||
900 | mrw = 0; | ||
901 | if (!cdrom_is_mrw(cdi, &mrw_write)) | ||
902 | mrw = 1; | ||
903 | |||
904 | if (CDROM_CAN(CDC_MO_DRIVE)) | ||
905 | ram_write = 1; | ||
906 | else | ||
907 | (void) cdrom_is_random_writable(cdi, &ram_write); | ||
908 | |||
909 | if (mrw) | ||
910 | cdi->mask &= ~CDC_MRW; | ||
911 | else | ||
912 | cdi->mask |= CDC_MRW; | ||
913 | |||
914 | if (mrw_write) | ||
915 | cdi->mask &= ~CDC_MRW_W; | ||
916 | else | ||
917 | cdi->mask |= CDC_MRW_W; | ||
918 | |||
919 | if (ram_write) | ||
920 | cdi->mask &= ~CDC_RAM; | ||
921 | else | ||
922 | cdi->mask |= CDC_RAM; | ||
923 | |||
924 | if (CDROM_CAN(CDC_MRW_W)) | ||
925 | ret = cdrom_mrw_open_write(cdi); | ||
926 | else if (CDROM_CAN(CDC_DVD_RAM)) | ||
927 | ret = cdrom_dvdram_open_write(cdi); | ||
928 | else if (CDROM_CAN(CDC_RAM) && | ||
929 | !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW|CDC_MO_DRIVE)) | ||
930 | ret = cdrom_ram_open_write(cdi); | ||
931 | else if (CDROM_CAN(CDC_MO_DRIVE)) | ||
932 | ret = mo_open_write(cdi); | ||
933 | else if (!cdrom_is_dvd_rw(cdi)) | ||
934 | ret = 0; | ||
935 | |||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi) | ||
940 | { | ||
941 | struct packet_command cgc; | ||
942 | |||
943 | if (cdi->mmc3_profile != 0x1a) { | ||
944 | cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name); | ||
945 | return; | ||
946 | } | ||
947 | |||
948 | if (!cdi->media_written) { | ||
949 | cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name); | ||
950 | return; | ||
951 | } | ||
952 | |||
953 | printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n", | ||
954 | cdi->name); | ||
955 | |||
956 | init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | ||
957 | cgc.cmd[0] = GPCMD_FLUSH_CACHE; | ||
958 | cgc.timeout = 30*HZ; | ||
959 | cdi->ops->generic_packet(cdi, &cgc); | ||
960 | |||
961 | init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | ||
962 | cgc.cmd[0] = GPCMD_CLOSE_TRACK; | ||
963 | cgc.timeout = 3000*HZ; | ||
964 | cgc.quiet = 1; | ||
965 | cdi->ops->generic_packet(cdi, &cgc); | ||
966 | |||
967 | init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | ||
968 | cgc.cmd[0] = GPCMD_CLOSE_TRACK; | ||
969 | cgc.cmd[2] = 2; /* Close session */ | ||
970 | cgc.quiet = 1; | ||
971 | cgc.timeout = 3000*HZ; | ||
972 | cdi->ops->generic_packet(cdi, &cgc); | ||
973 | |||
974 | cdi->media_written = 0; | ||
975 | } | ||
976 | |||
977 | static int cdrom_close_write(struct cdrom_device_info *cdi) | ||
978 | { | ||
979 | #if 0 | ||
980 | return cdrom_flush_cache(cdi); | ||
981 | #else | ||
982 | return 0; | ||
983 | #endif | ||
984 | } | ||
985 | |||
986 | /* We use the open-option O_NONBLOCK to indicate that the | ||
987 | * purpose of opening is only for subsequent ioctl() calls; no device | ||
988 | * integrity checks are performed. | ||
989 | * | ||
990 | * We hope that all cd-player programs will adopt this convention. It | ||
991 | * is in their own interest: device control becomes a lot easier | ||
992 | * this way. | ||
993 | */ | ||
994 | int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) | ||
995 | { | ||
996 | int ret; | ||
997 | |||
998 | cdinfo(CD_OPEN, "entering cdrom_open\n"); | ||
999 | |||
1000 | /* if this was a O_NONBLOCK open and we should honor the flags, | ||
1001 | * do a quick open without drive/disc integrity checks. */ | ||
1002 | cdi->use_count++; | ||
1003 | if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) { | ||
1004 | ret = cdi->ops->open(cdi, 1); | ||
1005 | } else { | ||
1006 | ret = open_for_data(cdi); | ||
1007 | if (ret) | ||
1008 | goto err; | ||
1009 | cdrom_mmc3_profile(cdi); | ||
1010 | if (fp->f_mode & FMODE_WRITE) { | ||
1011 | ret = -EROFS; | ||
1012 | if (cdrom_open_write(cdi)) | ||
1013 | goto err; | ||
1014 | if (!CDROM_CAN(CDC_RAM)) | ||
1015 | goto err; | ||
1016 | ret = 0; | ||
1017 | cdi->media_written = 0; | ||
1018 | } | ||
1019 | } | ||
1020 | |||
1021 | if (ret) | ||
1022 | goto err; | ||
1023 | |||
1024 | cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", | ||
1025 | cdi->name, cdi->use_count); | ||
1026 | /* Do this on open. Don't wait for mount, because they might | ||
1027 | not be mounting, but opening with O_NONBLOCK */ | ||
1028 | check_disk_change(ip->i_bdev); | ||
1029 | return 0; | ||
1030 | err: | ||
1031 | cdi->use_count--; | ||
1032 | return ret; | ||
1033 | } | ||
1034 | |||
1035 | static | ||
1036 | int open_for_data(struct cdrom_device_info * cdi) | ||
1037 | { | ||
1038 | int ret; | ||
1039 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1040 | tracktype tracks; | ||
1041 | cdinfo(CD_OPEN, "entering open_for_data\n"); | ||
1042 | /* Check if the driver can report drive status. If it can, we | ||
1043 | can do clever things. If it can't, well, we at least tried! */ | ||
1044 | if (cdo->drive_status != NULL) { | ||
1045 | ret = cdo->drive_status(cdi, CDSL_CURRENT); | ||
1046 | cdinfo(CD_OPEN, "drive_status=%d\n", ret); | ||
1047 | if (ret == CDS_TRAY_OPEN) { | ||
1048 | cdinfo(CD_OPEN, "the tray is open...\n"); | ||
1049 | /* can/may i close it? */ | ||
1050 | if (CDROM_CAN(CDC_CLOSE_TRAY) && | ||
1051 | cdi->options & CDO_AUTO_CLOSE) { | ||
1052 | cdinfo(CD_OPEN, "trying to close the tray.\n"); | ||
1053 | ret=cdo->tray_move(cdi,0); | ||
1054 | if (ret) { | ||
1055 | cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n"); | ||
1056 | /* Ignore the error from the low | ||
1057 | level driver. We don't care why it | ||
1058 | couldn't close the tray. We only care | ||
1059 | that there is no disc in the drive, | ||
1060 | since that is the _REAL_ problem here.*/ | ||
1061 | ret=-ENOMEDIUM; | ||
1062 | goto clean_up_and_return; | ||
1063 | } | ||
1064 | } else { | ||
1065 | cdinfo(CD_OPEN, "bummer. this drive can't close the tray.\n"); | ||
1066 | ret=-ENOMEDIUM; | ||
1067 | goto clean_up_and_return; | ||
1068 | } | ||
1069 | /* Ok, the door should be closed now.. Check again */ | ||
1070 | ret = cdo->drive_status(cdi, CDSL_CURRENT); | ||
1071 | if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { | ||
1072 | cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); | ||
1073 | cdinfo(CD_OPEN, "tray might not contain a medium.\n"); | ||
1074 | ret=-ENOMEDIUM; | ||
1075 | goto clean_up_and_return; | ||
1076 | } | ||
1077 | cdinfo(CD_OPEN, "the tray is now closed.\n"); | ||
1078 | } | ||
1079 | /* the door should be closed now, check for the disc */ | ||
1080 | ret = cdo->drive_status(cdi, CDSL_CURRENT); | ||
1081 | if (ret!=CDS_DISC_OK) { | ||
1082 | ret = -ENOMEDIUM; | ||
1083 | goto clean_up_and_return; | ||
1084 | } | ||
1085 | } | ||
1086 | cdrom_count_tracks(cdi, &tracks); | ||
1087 | if (tracks.error == CDS_NO_DISC) { | ||
1088 | cdinfo(CD_OPEN, "bummer. no disc.\n"); | ||
1089 | ret=-ENOMEDIUM; | ||
1090 | goto clean_up_and_return; | ||
1091 | } | ||
1092 | /* CD-Players which don't use O_NONBLOCK, workman | ||
1093 | * for example, need bit CDO_CHECK_TYPE cleared! */ | ||
1094 | if (tracks.data==0) { | ||
1095 | if (cdi->options & CDO_CHECK_TYPE) { | ||
1096 | /* give people a warning shot, now that CDO_CHECK_TYPE | ||
1097 | is the default case! */ | ||
1098 | cdinfo(CD_OPEN, "bummer. wrong media type.\n"); | ||
1099 | cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", | ||
1100 | (unsigned int)current->pid); | ||
1101 | ret=-EMEDIUMTYPE; | ||
1102 | goto clean_up_and_return; | ||
1103 | } | ||
1104 | else { | ||
1105 | cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n"); | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | cdinfo(CD_OPEN, "all seems well, opening the device.\n"); | ||
1110 | |||
1111 | /* all seems well, we can open the device */ | ||
1112 | ret = cdo->open(cdi, 0); /* open for data */ | ||
1113 | cdinfo(CD_OPEN, "opening the device gave me %d.\n", ret); | ||
1114 | /* After all this careful checking, we shouldn't have problems | ||
1115 | opening the device, but we don't want the device locked if | ||
1116 | this somehow fails... */ | ||
1117 | if (ret) { | ||
1118 | cdinfo(CD_OPEN, "open device failed.\n"); | ||
1119 | goto clean_up_and_return; | ||
1120 | } | ||
1121 | if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) { | ||
1122 | cdo->lock_door(cdi, 1); | ||
1123 | cdinfo(CD_OPEN, "door locked.\n"); | ||
1124 | } | ||
1125 | cdinfo(CD_OPEN, "device opened successfully.\n"); | ||
1126 | return ret; | ||
1127 | |||
1128 | /* Something failed. Try to unlock the drive, because some drivers | ||
1129 | (notably ide-cd) lock the drive after every command. This produced | ||
1130 | a nasty bug where after mount failed, the drive would remain locked! | ||
1131 | This ensures that the drive gets unlocked after a mount fails. This | ||
1132 | is a goto to avoid bloating the driver with redundant code. */ | ||
1133 | clean_up_and_return: | ||
1134 | cdinfo(CD_WARNING, "open failed.\n"); | ||
1135 | if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { | ||
1136 | cdo->lock_door(cdi, 0); | ||
1137 | cdinfo(CD_OPEN, "door unlocked.\n"); | ||
1138 | } | ||
1139 | return ret; | ||
1140 | } | ||
1141 | |||
1142 | /* This code is similar to that in open_for_data. The routine is called | ||
1143 | whenever an audio play operation is requested. | ||
1144 | */ | ||
1145 | int check_for_audio_disc(struct cdrom_device_info * cdi, | ||
1146 | struct cdrom_device_ops * cdo) | ||
1147 | { | ||
1148 | int ret; | ||
1149 | tracktype tracks; | ||
1150 | cdinfo(CD_OPEN, "entering check_for_audio_disc\n"); | ||
1151 | if (!(cdi->options & CDO_CHECK_TYPE)) | ||
1152 | return 0; | ||
1153 | if (cdo->drive_status != NULL) { | ||
1154 | ret = cdo->drive_status(cdi, CDSL_CURRENT); | ||
1155 | cdinfo(CD_OPEN, "drive_status=%d\n", ret); | ||
1156 | if (ret == CDS_TRAY_OPEN) { | ||
1157 | cdinfo(CD_OPEN, "the tray is open...\n"); | ||
1158 | /* can/may i close it? */ | ||
1159 | if (CDROM_CAN(CDC_CLOSE_TRAY) && | ||
1160 | cdi->options & CDO_AUTO_CLOSE) { | ||
1161 | cdinfo(CD_OPEN, "trying to close the tray.\n"); | ||
1162 | ret=cdo->tray_move(cdi,0); | ||
1163 | if (ret) { | ||
1164 | cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n"); | ||
1165 | /* Ignore the error from the low | ||
1166 | level driver. We don't care why it | ||
1167 | couldn't close the tray. We only care | ||
1168 | that there is no disc in the drive, | ||
1169 | since that is the _REAL_ problem here.*/ | ||
1170 | return -ENOMEDIUM; | ||
1171 | } | ||
1172 | } else { | ||
1173 | cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); | ||
1174 | return -ENOMEDIUM; | ||
1175 | } | ||
1176 | /* Ok, the door should be closed now.. Check again */ | ||
1177 | ret = cdo->drive_status(cdi, CDSL_CURRENT); | ||
1178 | if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { | ||
1179 | cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); | ||
1180 | return -ENOMEDIUM; | ||
1181 | } | ||
1182 | if (ret!=CDS_DISC_OK) { | ||
1183 | cdinfo(CD_OPEN, "bummer. disc isn't ready.\n"); | ||
1184 | return -EIO; | ||
1185 | } | ||
1186 | cdinfo(CD_OPEN, "the tray is now closed.\n"); | ||
1187 | } | ||
1188 | } | ||
1189 | cdrom_count_tracks(cdi, &tracks); | ||
1190 | if (tracks.error) | ||
1191 | return(tracks.error); | ||
1192 | |||
1193 | if (tracks.audio==0) | ||
1194 | return -EMEDIUMTYPE; | ||
1195 | |||
1196 | return 0; | ||
1197 | } | ||
1198 | |||
1199 | /* Admittedly, the logic below could be performed in a nicer way. */ | ||
1200 | int cdrom_release(struct cdrom_device_info *cdi, struct file *fp) | ||
1201 | { | ||
1202 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1203 | int opened_for_data; | ||
1204 | |||
1205 | cdinfo(CD_CLOSE, "entering cdrom_release\n"); | ||
1206 | |||
1207 | if (cdi->use_count > 0) | ||
1208 | cdi->use_count--; | ||
1209 | if (cdi->use_count == 0) | ||
1210 | cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); | ||
1211 | if (cdi->use_count == 0) | ||
1212 | cdrom_dvd_rw_close_write(cdi); | ||
1213 | if (cdi->use_count == 0 && | ||
1214 | (cdo->capability & CDC_LOCK) && !keeplocked) { | ||
1215 | cdinfo(CD_CLOSE, "Unlocking door!\n"); | ||
1216 | cdo->lock_door(cdi, 0); | ||
1217 | } | ||
1218 | opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || | ||
1219 | !(fp && fp->f_flags & O_NONBLOCK); | ||
1220 | |||
1221 | /* | ||
1222 | * flush cache on last write release | ||
1223 | */ | ||
1224 | if (CDROM_CAN(CDC_RAM) && !cdi->use_count && cdi->for_data) | ||
1225 | cdrom_close_write(cdi); | ||
1226 | |||
1227 | cdo->release(cdi); | ||
1228 | if (cdi->use_count == 0) { /* last process that closes dev*/ | ||
1229 | if (opened_for_data && | ||
1230 | cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) | ||
1231 | cdo->tray_move(cdi, 1); | ||
1232 | } | ||
1233 | return 0; | ||
1234 | } | ||
1235 | |||
1236 | static int cdrom_read_mech_status(struct cdrom_device_info *cdi, | ||
1237 | struct cdrom_changer_info *buf) | ||
1238 | { | ||
1239 | struct packet_command cgc; | ||
1240 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1241 | int length; | ||
1242 | |||
1243 | /* | ||
1244 | * Sanyo changer isn't spec compliant (doesn't use regular change | ||
1245 | * LOAD_UNLOAD command, and it doesn't implement the mech status | ||
1246 | * command below | ||
1247 | */ | ||
1248 | if (cdi->sanyo_slot) { | ||
1249 | buf->hdr.nslots = 3; | ||
1250 | buf->hdr.curslot = cdi->sanyo_slot == 3 ? 0 : cdi->sanyo_slot; | ||
1251 | for (length = 0; length < 3; length++) { | ||
1252 | buf->slots[length].disc_present = 1; | ||
1253 | buf->slots[length].change = 0; | ||
1254 | } | ||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | length = sizeof(struct cdrom_mechstat_header) + | ||
1259 | cdi->capacity * sizeof(struct cdrom_slot); | ||
1260 | |||
1261 | init_cdrom_command(&cgc, buf, length, CGC_DATA_READ); | ||
1262 | cgc.cmd[0] = GPCMD_MECHANISM_STATUS; | ||
1263 | cgc.cmd[8] = (length >> 8) & 0xff; | ||
1264 | cgc.cmd[9] = length & 0xff; | ||
1265 | return cdo->generic_packet(cdi, &cgc); | ||
1266 | } | ||
1267 | |||
1268 | static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot) | ||
1269 | { | ||
1270 | struct cdrom_changer_info *info; | ||
1271 | int ret; | ||
1272 | |||
1273 | cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); | ||
1274 | if (cdi->sanyo_slot) | ||
1275 | return CDS_NO_INFO; | ||
1276 | |||
1277 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
1278 | if (!info) | ||
1279 | return -ENOMEM; | ||
1280 | |||
1281 | if ((ret = cdrom_read_mech_status(cdi, info))) | ||
1282 | goto out_free; | ||
1283 | |||
1284 | if (info->slots[slot].disc_present) | ||
1285 | ret = CDS_DISC_OK; | ||
1286 | else | ||
1287 | ret = CDS_NO_DISC; | ||
1288 | |||
1289 | out_free: | ||
1290 | kfree(info); | ||
1291 | return ret; | ||
1292 | } | ||
1293 | |||
1294 | /* Return the number of slots for an ATAPI/SCSI cdrom, | ||
1295 | * return 1 if not a changer. | ||
1296 | */ | ||
1297 | int cdrom_number_of_slots(struct cdrom_device_info *cdi) | ||
1298 | { | ||
1299 | int status; | ||
1300 | int nslots = 1; | ||
1301 | struct cdrom_changer_info *info; | ||
1302 | |||
1303 | cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); | ||
1304 | /* cdrom_read_mech_status requires a valid value for capacity: */ | ||
1305 | cdi->capacity = 0; | ||
1306 | |||
1307 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
1308 | if (!info) | ||
1309 | return -ENOMEM; | ||
1310 | |||
1311 | if ((status = cdrom_read_mech_status(cdi, info)) == 0) | ||
1312 | nslots = info->hdr.nslots; | ||
1313 | |||
1314 | kfree(info); | ||
1315 | return nslots; | ||
1316 | } | ||
1317 | |||
1318 | |||
1319 | /* If SLOT < 0, unload the current slot. Otherwise, try to load SLOT. */ | ||
1320 | static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot) | ||
1321 | { | ||
1322 | struct packet_command cgc; | ||
1323 | |||
1324 | cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n"); | ||
1325 | if (cdi->sanyo_slot && slot < 0) | ||
1326 | return 0; | ||
1327 | |||
1328 | init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | ||
1329 | cgc.cmd[0] = GPCMD_LOAD_UNLOAD; | ||
1330 | cgc.cmd[4] = 2 + (slot >= 0); | ||
1331 | cgc.cmd[8] = slot; | ||
1332 | cgc.timeout = 60 * HZ; | ||
1333 | |||
1334 | /* The Sanyo 3 CD changer uses byte 7 of the | ||
1335 | GPCMD_TEST_UNIT_READY to command to switch CDs instead of | ||
1336 | using the GPCMD_LOAD_UNLOAD opcode. */ | ||
1337 | if (cdi->sanyo_slot && -1 < slot) { | ||
1338 | cgc.cmd[0] = GPCMD_TEST_UNIT_READY; | ||
1339 | cgc.cmd[7] = slot; | ||
1340 | cgc.cmd[4] = cgc.cmd[8] = 0; | ||
1341 | cdi->sanyo_slot = slot ? slot : 3; | ||
1342 | } | ||
1343 | |||
1344 | return cdi->ops->generic_packet(cdi, &cgc); | ||
1345 | } | ||
1346 | |||
1347 | static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) | ||
1348 | { | ||
1349 | struct cdrom_changer_info *info; | ||
1350 | int curslot; | ||
1351 | int ret; | ||
1352 | |||
1353 | cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n"); | ||
1354 | if (!CDROM_CAN(CDC_SELECT_DISC)) | ||
1355 | return -EDRIVE_CANT_DO_THIS; | ||
1356 | |||
1357 | (void) cdi->ops->media_changed(cdi, slot); | ||
1358 | |||
1359 | if (slot == CDSL_NONE) { | ||
1360 | /* set media changed bits, on both queues */ | ||
1361 | cdi->mc_flags = 0x3; | ||
1362 | return cdrom_load_unload(cdi, -1); | ||
1363 | } | ||
1364 | |||
1365 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
1366 | if (!info) | ||
1367 | return -ENOMEM; | ||
1368 | |||
1369 | if ((ret = cdrom_read_mech_status(cdi, info))) { | ||
1370 | kfree(info); | ||
1371 | return ret; | ||
1372 | } | ||
1373 | |||
1374 | curslot = info->hdr.curslot; | ||
1375 | kfree(info); | ||
1376 | |||
1377 | if (cdi->use_count > 1 || keeplocked) { | ||
1378 | if (slot == CDSL_CURRENT) { | ||
1379 | return curslot; | ||
1380 | } else { | ||
1381 | return -EBUSY; | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | /* Specifying CDSL_CURRENT will attempt to load the currnet slot, | ||
1386 | which is useful if it had been previously unloaded. | ||
1387 | Whether it can or not, it returns the current slot. | ||
1388 | Similarly, if slot happens to be the current one, we still | ||
1389 | try and load it. */ | ||
1390 | if (slot == CDSL_CURRENT) | ||
1391 | slot = curslot; | ||
1392 | |||
1393 | /* set media changed bits on both queues */ | ||
1394 | cdi->mc_flags = 0x3; | ||
1395 | if ((ret = cdrom_load_unload(cdi, slot))) | ||
1396 | return ret; | ||
1397 | |||
1398 | return slot; | ||
1399 | } | ||
1400 | |||
1401 | /* We want to make media_changed accessible to the user through an | ||
1402 | * ioctl. The main problem now is that we must double-buffer the | ||
1403 | * low-level implementation, to assure that the VFS and the user both | ||
1404 | * see a medium change once. | ||
1405 | */ | ||
1406 | |||
1407 | static | ||
1408 | int media_changed(struct cdrom_device_info *cdi, int queue) | ||
1409 | { | ||
1410 | unsigned int mask = (1 << (queue & 1)); | ||
1411 | int ret = !!(cdi->mc_flags & mask); | ||
1412 | |||
1413 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) | ||
1414 | return ret; | ||
1415 | /* changed since last call? */ | ||
1416 | if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { | ||
1417 | cdi->mc_flags = 0x3; /* set bit on both queues */ | ||
1418 | ret |= 1; | ||
1419 | cdi->media_written = 0; | ||
1420 | } | ||
1421 | cdi->mc_flags &= ~mask; /* clear bit */ | ||
1422 | return ret; | ||
1423 | } | ||
1424 | |||
1425 | int cdrom_media_changed(struct cdrom_device_info *cdi) | ||
1426 | { | ||
1427 | /* This talks to the VFS, which doesn't like errors - just 1 or 0. | ||
1428 | * Returning "0" is always safe (media hasn't been changed). Do that | ||
1429 | * if the low-level cdrom driver dosn't support media changed. */ | ||
1430 | if (cdi == NULL || cdi->ops->media_changed == NULL) | ||
1431 | return 0; | ||
1432 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) | ||
1433 | return 0; | ||
1434 | return media_changed(cdi, 0); | ||
1435 | } | ||
1436 | |||
1437 | /* badly broken, I know. Is due for a fixup anytime. */ | ||
1438 | static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) | ||
1439 | { | ||
1440 | struct cdrom_tochdr header; | ||
1441 | struct cdrom_tocentry entry; | ||
1442 | int ret, i; | ||
1443 | tracks->data=0; | ||
1444 | tracks->audio=0; | ||
1445 | tracks->cdi=0; | ||
1446 | tracks->xa=0; | ||
1447 | tracks->error=0; | ||
1448 | cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); | ||
1449 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) { | ||
1450 | tracks->error=CDS_NO_INFO; | ||
1451 | return; | ||
1452 | } | ||
1453 | /* Grab the TOC header so we can see how many tracks there are */ | ||
1454 | if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { | ||
1455 | if (ret == -ENOMEDIUM) | ||
1456 | tracks->error = CDS_NO_DISC; | ||
1457 | else | ||
1458 | tracks->error = CDS_NO_INFO; | ||
1459 | return; | ||
1460 | } | ||
1461 | /* check what type of tracks are on this disc */ | ||
1462 | entry.cdte_format = CDROM_MSF; | ||
1463 | for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { | ||
1464 | entry.cdte_track = i; | ||
1465 | if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { | ||
1466 | tracks->error=CDS_NO_INFO; | ||
1467 | return; | ||
1468 | } | ||
1469 | if (entry.cdte_ctrl & CDROM_DATA_TRACK) { | ||
1470 | if (entry.cdte_format == 0x10) | ||
1471 | tracks->cdi++; | ||
1472 | else if (entry.cdte_format == 0x20) | ||
1473 | tracks->xa++; | ||
1474 | else | ||
1475 | tracks->data++; | ||
1476 | } else | ||
1477 | tracks->audio++; | ||
1478 | cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", | ||
1479 | i, entry.cdte_format, entry.cdte_ctrl); | ||
1480 | } | ||
1481 | cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", | ||
1482 | header.cdth_trk1, tracks->audio, tracks->data, | ||
1483 | tracks->cdi, tracks->xa); | ||
1484 | } | ||
1485 | |||
1486 | /* Requests to the low-level drivers will /always/ be done in the | ||
1487 | following format convention: | ||
1488 | |||
1489 | CDROM_LBA: all data-related requests. | ||
1490 | CDROM_MSF: all audio-related requests. | ||
1491 | |||
1492 | However, a low-level implementation is allowed to refuse this | ||
1493 | request, and return information in its own favorite format. | ||
1494 | |||
1495 | It doesn't make sense /at all/ to ask for a play_audio in LBA | ||
1496 | format, or ask for multi-session info in MSF format. However, for | ||
1497 | backward compatibility these format requests will be satisfied, but | ||
1498 | the requests to the low-level drivers will be sanitized in the more | ||
1499 | meaningful format indicated above. | ||
1500 | */ | ||
1501 | |||
1502 | static | ||
1503 | void sanitize_format(union cdrom_addr *addr, | ||
1504 | u_char * curr, u_char requested) | ||
1505 | { | ||
1506 | if (*curr == requested) | ||
1507 | return; /* nothing to be done! */ | ||
1508 | if (requested == CDROM_LBA) { | ||
1509 | addr->lba = (int) addr->msf.frame + | ||
1510 | 75 * (addr->msf.second - 2 + 60 * addr->msf.minute); | ||
1511 | } else { /* CDROM_MSF */ | ||
1512 | int lba = addr->lba; | ||
1513 | addr->msf.frame = lba % 75; | ||
1514 | lba /= 75; | ||
1515 | lba += 2; | ||
1516 | addr->msf.second = lba % 60; | ||
1517 | addr->msf.minute = lba / 60; | ||
1518 | } | ||
1519 | *curr = requested; | ||
1520 | } | ||
1521 | |||
1522 | void init_cdrom_command(struct packet_command *cgc, void *buf, int len, | ||
1523 | int type) | ||
1524 | { | ||
1525 | memset(cgc, 0, sizeof(struct packet_command)); | ||
1526 | if (buf) | ||
1527 | memset(buf, 0, len); | ||
1528 | cgc->buffer = (char *) buf; | ||
1529 | cgc->buflen = len; | ||
1530 | cgc->data_direction = type; | ||
1531 | cgc->timeout = 5*HZ; | ||
1532 | } | ||
1533 | |||
1534 | /* DVD handling */ | ||
1535 | |||
1536 | #define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key)) | ||
1537 | #define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge)) | ||
1538 | |||
1539 | static void setup_report_key(struct packet_command *cgc, unsigned agid, unsigned type) | ||
1540 | { | ||
1541 | cgc->cmd[0] = GPCMD_REPORT_KEY; | ||
1542 | cgc->cmd[10] = type | (agid << 6); | ||
1543 | switch (type) { | ||
1544 | case 0: case 8: case 5: { | ||
1545 | cgc->buflen = 8; | ||
1546 | break; | ||
1547 | } | ||
1548 | case 1: { | ||
1549 | cgc->buflen = 16; | ||
1550 | break; | ||
1551 | } | ||
1552 | case 2: case 4: { | ||
1553 | cgc->buflen = 12; | ||
1554 | break; | ||
1555 | } | ||
1556 | } | ||
1557 | cgc->cmd[9] = cgc->buflen; | ||
1558 | cgc->data_direction = CGC_DATA_READ; | ||
1559 | } | ||
1560 | |||
1561 | static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned type) | ||
1562 | { | ||
1563 | cgc->cmd[0] = GPCMD_SEND_KEY; | ||
1564 | cgc->cmd[10] = type | (agid << 6); | ||
1565 | switch (type) { | ||
1566 | case 1: { | ||
1567 | cgc->buflen = 16; | ||
1568 | break; | ||
1569 | } | ||
1570 | case 3: { | ||
1571 | cgc->buflen = 12; | ||
1572 | break; | ||
1573 | } | ||
1574 | case 6: { | ||
1575 | cgc->buflen = 8; | ||
1576 | break; | ||
1577 | } | ||
1578 | } | ||
1579 | cgc->cmd[9] = cgc->buflen; | ||
1580 | cgc->data_direction = CGC_DATA_WRITE; | ||
1581 | } | ||
1582 | |||
1583 | static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) | ||
1584 | { | ||
1585 | int ret; | ||
1586 | u_char buf[20]; | ||
1587 | struct packet_command cgc; | ||
1588 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1589 | rpc_state_t rpc_state; | ||
1590 | |||
1591 | memset(buf, 0, sizeof(buf)); | ||
1592 | init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); | ||
1593 | |||
1594 | switch (ai->type) { | ||
1595 | /* LU data send */ | ||
1596 | case DVD_LU_SEND_AGID: | ||
1597 | cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); | ||
1598 | cgc.quiet = 1; | ||
1599 | setup_report_key(&cgc, ai->lsa.agid, 0); | ||
1600 | |||
1601 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1602 | return ret; | ||
1603 | |||
1604 | ai->lsa.agid = buf[7] >> 6; | ||
1605 | /* Returning data, let host change state */ | ||
1606 | break; | ||
1607 | |||
1608 | case DVD_LU_SEND_KEY1: | ||
1609 | cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); | ||
1610 | setup_report_key(&cgc, ai->lsk.agid, 2); | ||
1611 | |||
1612 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1613 | return ret; | ||
1614 | |||
1615 | copy_key(ai->lsk.key, &buf[4]); | ||
1616 | /* Returning data, let host change state */ | ||
1617 | break; | ||
1618 | |||
1619 | case DVD_LU_SEND_CHALLENGE: | ||
1620 | cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); | ||
1621 | setup_report_key(&cgc, ai->lsc.agid, 1); | ||
1622 | |||
1623 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1624 | return ret; | ||
1625 | |||
1626 | copy_chal(ai->lsc.chal, &buf[4]); | ||
1627 | /* Returning data, let host change state */ | ||
1628 | break; | ||
1629 | |||
1630 | /* Post-auth key */ | ||
1631 | case DVD_LU_SEND_TITLE_KEY: | ||
1632 | cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); | ||
1633 | cgc.quiet = 1; | ||
1634 | setup_report_key(&cgc, ai->lstk.agid, 4); | ||
1635 | cgc.cmd[5] = ai->lstk.lba; | ||
1636 | cgc.cmd[4] = ai->lstk.lba >> 8; | ||
1637 | cgc.cmd[3] = ai->lstk.lba >> 16; | ||
1638 | cgc.cmd[2] = ai->lstk.lba >> 24; | ||
1639 | |||
1640 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1641 | return ret; | ||
1642 | |||
1643 | ai->lstk.cpm = (buf[4] >> 7) & 1; | ||
1644 | ai->lstk.cp_sec = (buf[4] >> 6) & 1; | ||
1645 | ai->lstk.cgms = (buf[4] >> 4) & 3; | ||
1646 | copy_key(ai->lstk.title_key, &buf[5]); | ||
1647 | /* Returning data, let host change state */ | ||
1648 | break; | ||
1649 | |||
1650 | case DVD_LU_SEND_ASF: | ||
1651 | cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); | ||
1652 | setup_report_key(&cgc, ai->lsasf.agid, 5); | ||
1653 | |||
1654 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1655 | return ret; | ||
1656 | |||
1657 | ai->lsasf.asf = buf[7] & 1; | ||
1658 | break; | ||
1659 | |||
1660 | /* LU data receive (LU changes state) */ | ||
1661 | case DVD_HOST_SEND_CHALLENGE: | ||
1662 | cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); | ||
1663 | setup_send_key(&cgc, ai->hsc.agid, 1); | ||
1664 | buf[1] = 0xe; | ||
1665 | copy_chal(&buf[4], ai->hsc.chal); | ||
1666 | |||
1667 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1668 | return ret; | ||
1669 | |||
1670 | ai->type = DVD_LU_SEND_KEY1; | ||
1671 | break; | ||
1672 | |||
1673 | case DVD_HOST_SEND_KEY2: | ||
1674 | cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); | ||
1675 | setup_send_key(&cgc, ai->hsk.agid, 3); | ||
1676 | buf[1] = 0xa; | ||
1677 | copy_key(&buf[4], ai->hsk.key); | ||
1678 | |||
1679 | if ((ret = cdo->generic_packet(cdi, &cgc))) { | ||
1680 | ai->type = DVD_AUTH_FAILURE; | ||
1681 | return ret; | ||
1682 | } | ||
1683 | ai->type = DVD_AUTH_ESTABLISHED; | ||
1684 | break; | ||
1685 | |||
1686 | /* Misc */ | ||
1687 | case DVD_INVALIDATE_AGID: | ||
1688 | cgc.quiet = 1; | ||
1689 | cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); | ||
1690 | setup_report_key(&cgc, ai->lsa.agid, 0x3f); | ||
1691 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1692 | return ret; | ||
1693 | break; | ||
1694 | |||
1695 | /* Get region settings */ | ||
1696 | case DVD_LU_SEND_RPC_STATE: | ||
1697 | cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); | ||
1698 | setup_report_key(&cgc, 0, 8); | ||
1699 | memset(&rpc_state, 0, sizeof(rpc_state_t)); | ||
1700 | cgc.buffer = (char *) &rpc_state; | ||
1701 | |||
1702 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1703 | return ret; | ||
1704 | |||
1705 | ai->lrpcs.type = rpc_state.type_code; | ||
1706 | ai->lrpcs.vra = rpc_state.vra; | ||
1707 | ai->lrpcs.ucca = rpc_state.ucca; | ||
1708 | ai->lrpcs.region_mask = rpc_state.region_mask; | ||
1709 | ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; | ||
1710 | break; | ||
1711 | |||
1712 | /* Set region settings */ | ||
1713 | case DVD_HOST_SEND_RPC_STATE: | ||
1714 | cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); | ||
1715 | setup_send_key(&cgc, 0, 6); | ||
1716 | buf[1] = 6; | ||
1717 | buf[4] = ai->hrpcs.pdrc; | ||
1718 | |||
1719 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1720 | return ret; | ||
1721 | break; | ||
1722 | |||
1723 | default: | ||
1724 | cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); | ||
1725 | return -ENOTTY; | ||
1726 | } | ||
1727 | |||
1728 | return 0; | ||
1729 | } | ||
1730 | |||
1731 | static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) | ||
1732 | { | ||
1733 | unsigned char buf[21], *base; | ||
1734 | struct dvd_layer *layer; | ||
1735 | struct packet_command cgc; | ||
1736 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1737 | int ret, layer_num = s->physical.layer_num; | ||
1738 | |||
1739 | if (layer_num >= DVD_LAYERS) | ||
1740 | return -EINVAL; | ||
1741 | |||
1742 | init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); | ||
1743 | cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; | ||
1744 | cgc.cmd[6] = layer_num; | ||
1745 | cgc.cmd[7] = s->type; | ||
1746 | cgc.cmd[9] = cgc.buflen & 0xff; | ||
1747 | |||
1748 | /* | ||
1749 | * refrain from reporting errors on non-existing layers (mainly) | ||
1750 | */ | ||
1751 | cgc.quiet = 1; | ||
1752 | |||
1753 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1754 | return ret; | ||
1755 | |||
1756 | base = &buf[4]; | ||
1757 | layer = &s->physical.layer[layer_num]; | ||
1758 | |||
1759 | /* | ||
1760 | * place the data... really ugly, but at least we won't have to | ||
1761 | * worry about endianess in userspace. | ||
1762 | */ | ||
1763 | memset(layer, 0, sizeof(*layer)); | ||
1764 | layer->book_version = base[0] & 0xf; | ||
1765 | layer->book_type = base[0] >> 4; | ||
1766 | layer->min_rate = base[1] & 0xf; | ||
1767 | layer->disc_size = base[1] >> 4; | ||
1768 | layer->layer_type = base[2] & 0xf; | ||
1769 | layer->track_path = (base[2] >> 4) & 1; | ||
1770 | layer->nlayers = (base[2] >> 5) & 3; | ||
1771 | layer->track_density = base[3] & 0xf; | ||
1772 | layer->linear_density = base[3] >> 4; | ||
1773 | layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; | ||
1774 | layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; | ||
1775 | layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; | ||
1776 | layer->bca = base[16] >> 7; | ||
1777 | |||
1778 | return 0; | ||
1779 | } | ||
1780 | |||
1781 | static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) | ||
1782 | { | ||
1783 | int ret; | ||
1784 | u_char buf[8]; | ||
1785 | struct packet_command cgc; | ||
1786 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1787 | |||
1788 | init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); | ||
1789 | cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; | ||
1790 | cgc.cmd[6] = s->copyright.layer_num; | ||
1791 | cgc.cmd[7] = s->type; | ||
1792 | cgc.cmd[8] = cgc.buflen >> 8; | ||
1793 | cgc.cmd[9] = cgc.buflen & 0xff; | ||
1794 | |||
1795 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1796 | return ret; | ||
1797 | |||
1798 | s->copyright.cpst = buf[4]; | ||
1799 | s->copyright.rmi = buf[5]; | ||
1800 | |||
1801 | return 0; | ||
1802 | } | ||
1803 | |||
1804 | static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) | ||
1805 | { | ||
1806 | int ret, size; | ||
1807 | u_char *buf; | ||
1808 | struct packet_command cgc; | ||
1809 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1810 | |||
1811 | size = sizeof(s->disckey.value) + 4; | ||
1812 | |||
1813 | if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) | ||
1814 | return -ENOMEM; | ||
1815 | |||
1816 | init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); | ||
1817 | cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; | ||
1818 | cgc.cmd[7] = s->type; | ||
1819 | cgc.cmd[8] = size >> 8; | ||
1820 | cgc.cmd[9] = size & 0xff; | ||
1821 | cgc.cmd[10] = s->disckey.agid << 6; | ||
1822 | |||
1823 | if (!(ret = cdo->generic_packet(cdi, &cgc))) | ||
1824 | memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value)); | ||
1825 | |||
1826 | kfree(buf); | ||
1827 | return ret; | ||
1828 | } | ||
1829 | |||
1830 | static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) | ||
1831 | { | ||
1832 | int ret; | ||
1833 | u_char buf[4 + 188]; | ||
1834 | struct packet_command cgc; | ||
1835 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1836 | |||
1837 | init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); | ||
1838 | cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; | ||
1839 | cgc.cmd[7] = s->type; | ||
1840 | cgc.cmd[9] = cgc.buflen = 0xff; | ||
1841 | |||
1842 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1843 | return ret; | ||
1844 | |||
1845 | s->bca.len = buf[0] << 8 | buf[1]; | ||
1846 | if (s->bca.len < 12 || s->bca.len > 188) { | ||
1847 | cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); | ||
1848 | return -EIO; | ||
1849 | } | ||
1850 | memcpy(s->bca.value, &buf[4], s->bca.len); | ||
1851 | |||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) | ||
1856 | { | ||
1857 | int ret = 0, size; | ||
1858 | u_char *buf; | ||
1859 | struct packet_command cgc; | ||
1860 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1861 | |||
1862 | size = sizeof(s->manufact.value) + 4; | ||
1863 | |||
1864 | if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) | ||
1865 | return -ENOMEM; | ||
1866 | |||
1867 | init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); | ||
1868 | cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; | ||
1869 | cgc.cmd[7] = s->type; | ||
1870 | cgc.cmd[8] = size >> 8; | ||
1871 | cgc.cmd[9] = size & 0xff; | ||
1872 | |||
1873 | if ((ret = cdo->generic_packet(cdi, &cgc))) { | ||
1874 | kfree(buf); | ||
1875 | return ret; | ||
1876 | } | ||
1877 | |||
1878 | s->manufact.len = buf[0] << 8 | buf[1]; | ||
1879 | if (s->manufact.len < 0 || s->manufact.len > 2048) { | ||
1880 | cdinfo(CD_WARNING, "Received invalid manufacture info length" | ||
1881 | " (%d)\n", s->manufact.len); | ||
1882 | ret = -EIO; | ||
1883 | } else { | ||
1884 | memcpy(s->manufact.value, &buf[4], s->manufact.len); | ||
1885 | } | ||
1886 | |||
1887 | kfree(buf); | ||
1888 | return ret; | ||
1889 | } | ||
1890 | |||
1891 | static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s) | ||
1892 | { | ||
1893 | switch (s->type) { | ||
1894 | case DVD_STRUCT_PHYSICAL: | ||
1895 | return dvd_read_physical(cdi, s); | ||
1896 | |||
1897 | case DVD_STRUCT_COPYRIGHT: | ||
1898 | return dvd_read_copyright(cdi, s); | ||
1899 | |||
1900 | case DVD_STRUCT_DISCKEY: | ||
1901 | return dvd_read_disckey(cdi, s); | ||
1902 | |||
1903 | case DVD_STRUCT_BCA: | ||
1904 | return dvd_read_bca(cdi, s); | ||
1905 | |||
1906 | case DVD_STRUCT_MANUFACT: | ||
1907 | return dvd_read_manufact(cdi, s); | ||
1908 | |||
1909 | default: | ||
1910 | cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", | ||
1911 | s->type); | ||
1912 | return -EINVAL; | ||
1913 | } | ||
1914 | } | ||
1915 | |||
1916 | int cdrom_mode_sense(struct cdrom_device_info *cdi, | ||
1917 | struct packet_command *cgc, | ||
1918 | int page_code, int page_control) | ||
1919 | { | ||
1920 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1921 | |||
1922 | memset(cgc->cmd, 0, sizeof(cgc->cmd)); | ||
1923 | |||
1924 | cgc->cmd[0] = GPCMD_MODE_SENSE_10; | ||
1925 | cgc->cmd[2] = page_code | (page_control << 6); | ||
1926 | cgc->cmd[7] = cgc->buflen >> 8; | ||
1927 | cgc->cmd[8] = cgc->buflen & 0xff; | ||
1928 | cgc->data_direction = CGC_DATA_READ; | ||
1929 | return cdo->generic_packet(cdi, cgc); | ||
1930 | } | ||
1931 | |||
1932 | int cdrom_mode_select(struct cdrom_device_info *cdi, | ||
1933 | struct packet_command *cgc) | ||
1934 | { | ||
1935 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1936 | |||
1937 | memset(cgc->cmd, 0, sizeof(cgc->cmd)); | ||
1938 | memset(cgc->buffer, 0, 2); | ||
1939 | cgc->cmd[0] = GPCMD_MODE_SELECT_10; | ||
1940 | cgc->cmd[1] = 0x10; /* PF */ | ||
1941 | cgc->cmd[7] = cgc->buflen >> 8; | ||
1942 | cgc->cmd[8] = cgc->buflen & 0xff; | ||
1943 | cgc->data_direction = CGC_DATA_WRITE; | ||
1944 | return cdo->generic_packet(cdi, cgc); | ||
1945 | } | ||
1946 | |||
1947 | static int cdrom_read_subchannel(struct cdrom_device_info *cdi, | ||
1948 | struct cdrom_subchnl *subchnl, int mcn) | ||
1949 | { | ||
1950 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1951 | struct packet_command cgc; | ||
1952 | char buffer[32]; | ||
1953 | int ret; | ||
1954 | |||
1955 | init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); | ||
1956 | cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; | ||
1957 | cgc.cmd[1] = 2; /* MSF addressing */ | ||
1958 | cgc.cmd[2] = 0x40; /* request subQ data */ | ||
1959 | cgc.cmd[3] = mcn ? 2 : 1; | ||
1960 | cgc.cmd[8] = 16; | ||
1961 | |||
1962 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
1963 | return ret; | ||
1964 | |||
1965 | subchnl->cdsc_audiostatus = cgc.buffer[1]; | ||
1966 | subchnl->cdsc_format = CDROM_MSF; | ||
1967 | subchnl->cdsc_ctrl = cgc.buffer[5] & 0xf; | ||
1968 | subchnl->cdsc_trk = cgc.buffer[6]; | ||
1969 | subchnl->cdsc_ind = cgc.buffer[7]; | ||
1970 | |||
1971 | subchnl->cdsc_reladdr.msf.minute = cgc.buffer[13]; | ||
1972 | subchnl->cdsc_reladdr.msf.second = cgc.buffer[14]; | ||
1973 | subchnl->cdsc_reladdr.msf.frame = cgc.buffer[15]; | ||
1974 | subchnl->cdsc_absaddr.msf.minute = cgc.buffer[9]; | ||
1975 | subchnl->cdsc_absaddr.msf.second = cgc.buffer[10]; | ||
1976 | subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11]; | ||
1977 | |||
1978 | return 0; | ||
1979 | } | ||
1980 | |||
1981 | /* | ||
1982 | * Specific READ_10 interface | ||
1983 | */ | ||
1984 | static int cdrom_read_cd(struct cdrom_device_info *cdi, | ||
1985 | struct packet_command *cgc, int lba, | ||
1986 | int blocksize, int nblocks) | ||
1987 | { | ||
1988 | struct cdrom_device_ops *cdo = cdi->ops; | ||
1989 | |||
1990 | memset(&cgc->cmd, 0, sizeof(cgc->cmd)); | ||
1991 | cgc->cmd[0] = GPCMD_READ_10; | ||
1992 | cgc->cmd[2] = (lba >> 24) & 0xff; | ||
1993 | cgc->cmd[3] = (lba >> 16) & 0xff; | ||
1994 | cgc->cmd[4] = (lba >> 8) & 0xff; | ||
1995 | cgc->cmd[5] = lba & 0xff; | ||
1996 | cgc->cmd[6] = (nblocks >> 16) & 0xff; | ||
1997 | cgc->cmd[7] = (nblocks >> 8) & 0xff; | ||
1998 | cgc->cmd[8] = nblocks & 0xff; | ||
1999 | cgc->buflen = blocksize * nblocks; | ||
2000 | return cdo->generic_packet(cdi, cgc); | ||
2001 | } | ||
2002 | |||
2003 | /* very generic interface for reading the various types of blocks */ | ||
2004 | static int cdrom_read_block(struct cdrom_device_info *cdi, | ||
2005 | struct packet_command *cgc, | ||
2006 | int lba, int nblocks, int format, int blksize) | ||
2007 | { | ||
2008 | struct cdrom_device_ops *cdo = cdi->ops; | ||
2009 | |||
2010 | memset(&cgc->cmd, 0, sizeof(cgc->cmd)); | ||
2011 | cgc->cmd[0] = GPCMD_READ_CD; | ||
2012 | /* expected sector size - cdda,mode1,etc. */ | ||
2013 | cgc->cmd[1] = format << 2; | ||
2014 | /* starting address */ | ||
2015 | cgc->cmd[2] = (lba >> 24) & 0xff; | ||
2016 | cgc->cmd[3] = (lba >> 16) & 0xff; | ||
2017 | cgc->cmd[4] = (lba >> 8) & 0xff; | ||
2018 | cgc->cmd[5] = lba & 0xff; | ||
2019 | /* number of blocks */ | ||
2020 | cgc->cmd[6] = (nblocks >> 16) & 0xff; | ||
2021 | cgc->cmd[7] = (nblocks >> 8) & 0xff; | ||
2022 | cgc->cmd[8] = nblocks & 0xff; | ||
2023 | cgc->buflen = blksize * nblocks; | ||
2024 | |||
2025 | /* set the header info returned */ | ||
2026 | switch (blksize) { | ||
2027 | case CD_FRAMESIZE_RAW0 : cgc->cmd[9] = 0x58; break; | ||
2028 | case CD_FRAMESIZE_RAW1 : cgc->cmd[9] = 0x78; break; | ||
2029 | case CD_FRAMESIZE_RAW : cgc->cmd[9] = 0xf8; break; | ||
2030 | default : cgc->cmd[9] = 0x10; | ||
2031 | } | ||
2032 | |||
2033 | return cdo->generic_packet(cdi, cgc); | ||
2034 | } | ||
2035 | |||
2036 | static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, | ||
2037 | int lba, int nframes) | ||
2038 | { | ||
2039 | struct packet_command cgc; | ||
2040 | int ret = 0; | ||
2041 | int nr; | ||
2042 | |||
2043 | cdi->last_sense = 0; | ||
2044 | |||
2045 | memset(&cgc, 0, sizeof(cgc)); | ||
2046 | |||
2047 | /* | ||
2048 | * start with will ra.nframes size, back down if alloc fails | ||
2049 | */ | ||
2050 | nr = nframes; | ||
2051 | do { | ||
2052 | cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); | ||
2053 | if (cgc.buffer) | ||
2054 | break; | ||
2055 | |||
2056 | nr >>= 1; | ||
2057 | } while (nr); | ||
2058 | |||
2059 | if (!nr) | ||
2060 | return -ENOMEM; | ||
2061 | |||
2062 | if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { | ||
2063 | ret = -EFAULT; | ||
2064 | goto out; | ||
2065 | } | ||
2066 | |||
2067 | cgc.data_direction = CGC_DATA_READ; | ||
2068 | while (nframes > 0) { | ||
2069 | if (nr > nframes) | ||
2070 | nr = nframes; | ||
2071 | |||
2072 | ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); | ||
2073 | if (ret) | ||
2074 | break; | ||
2075 | if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { | ||
2076 | ret = -EFAULT; | ||
2077 | break; | ||
2078 | } | ||
2079 | ubuf += CD_FRAMESIZE_RAW * nr; | ||
2080 | nframes -= nr; | ||
2081 | lba += nr; | ||
2082 | } | ||
2083 | out: | ||
2084 | kfree(cgc.buffer); | ||
2085 | return ret; | ||
2086 | } | ||
2087 | |||
2088 | static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, | ||
2089 | int lba, int nframes) | ||
2090 | { | ||
2091 | request_queue_t *q = cdi->disk->queue; | ||
2092 | struct request *rq; | ||
2093 | struct bio *bio; | ||
2094 | unsigned int len; | ||
2095 | int nr, ret = 0; | ||
2096 | |||
2097 | if (!q) | ||
2098 | return -ENXIO; | ||
2099 | |||
2100 | cdi->last_sense = 0; | ||
2101 | |||
2102 | while (nframes) { | ||
2103 | nr = nframes; | ||
2104 | if (cdi->cdda_method == CDDA_BPC_SINGLE) | ||
2105 | nr = 1; | ||
2106 | if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9)) | ||
2107 | nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW; | ||
2108 | |||
2109 | len = nr * CD_FRAMESIZE_RAW; | ||
2110 | |||
2111 | rq = blk_rq_map_user(q, READ, ubuf, len); | ||
2112 | if (IS_ERR(rq)) | ||
2113 | return PTR_ERR(rq); | ||
2114 | |||
2115 | memset(rq->cmd, 0, sizeof(rq->cmd)); | ||
2116 | rq->cmd[0] = GPCMD_READ_CD; | ||
2117 | rq->cmd[1] = 1 << 2; | ||
2118 | rq->cmd[2] = (lba >> 24) & 0xff; | ||
2119 | rq->cmd[3] = (lba >> 16) & 0xff; | ||
2120 | rq->cmd[4] = (lba >> 8) & 0xff; | ||
2121 | rq->cmd[5] = lba & 0xff; | ||
2122 | rq->cmd[6] = (nr >> 16) & 0xff; | ||
2123 | rq->cmd[7] = (nr >> 8) & 0xff; | ||
2124 | rq->cmd[8] = nr & 0xff; | ||
2125 | rq->cmd[9] = 0xf8; | ||
2126 | |||
2127 | rq->cmd_len = 12; | ||
2128 | rq->flags |= REQ_BLOCK_PC; | ||
2129 | rq->timeout = 60 * HZ; | ||
2130 | bio = rq->bio; | ||
2131 | |||
2132 | if (rq->bio) | ||
2133 | blk_queue_bounce(q, &rq->bio); | ||
2134 | |||
2135 | if (blk_execute_rq(q, cdi->disk, rq)) { | ||
2136 | struct request_sense *s = rq->sense; | ||
2137 | ret = -EIO; | ||
2138 | cdi->last_sense = s->sense_key; | ||
2139 | } | ||
2140 | |||
2141 | if (blk_rq_unmap_user(rq, bio, len)) | ||
2142 | ret = -EFAULT; | ||
2143 | |||
2144 | if (ret) | ||
2145 | break; | ||
2146 | |||
2147 | nframes -= nr; | ||
2148 | lba += nr; | ||
2149 | ubuf += len; | ||
2150 | } | ||
2151 | |||
2152 | return ret; | ||
2153 | } | ||
2154 | |||
2155 | static int cdrom_read_cdda(struct cdrom_device_info *cdi, __u8 __user *ubuf, | ||
2156 | int lba, int nframes) | ||
2157 | { | ||
2158 | int ret; | ||
2159 | |||
2160 | if (cdi->cdda_method == CDDA_OLD) | ||
2161 | return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); | ||
2162 | |||
2163 | retry: | ||
2164 | /* | ||
2165 | * for anything else than success and io error, we need to retry | ||
2166 | */ | ||
2167 | ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes); | ||
2168 | if (!ret || ret != -EIO) | ||
2169 | return ret; | ||
2170 | |||
2171 | /* | ||
2172 | * I've seen drives get sense 4/8/3 udma crc errors on multi | ||
2173 | * frame dma, so drop to single frame dma if we need to | ||
2174 | */ | ||
2175 | if (cdi->cdda_method == CDDA_BPC_FULL && nframes > 1) { | ||
2176 | printk("cdrom: dropping to single frame dma\n"); | ||
2177 | cdi->cdda_method = CDDA_BPC_SINGLE; | ||
2178 | goto retry; | ||
2179 | } | ||
2180 | |||
2181 | /* | ||
2182 | * so we have an io error of some sort with multi frame dma. if the | ||
2183 | * condition wasn't a hardware error | ||
2184 | * problems, not for any error | ||
2185 | */ | ||
2186 | if (cdi->last_sense != 0x04 && cdi->last_sense != 0x0b) | ||
2187 | return ret; | ||
2188 | |||
2189 | printk("cdrom: dropping to old style cdda (sense=%x)\n", cdi->last_sense); | ||
2190 | cdi->cdda_method = CDDA_OLD; | ||
2191 | return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); | ||
2192 | } | ||
2193 | |||
2194 | /* Just about every imaginable ioctl is supported in the Uniform layer | ||
2195 | * these days. ATAPI / SCSI specific code now mainly resides in | ||
2196 | * mmc_ioct(). | ||
2197 | */ | ||
2198 | int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi, | ||
2199 | struct inode *ip, unsigned int cmd, unsigned long arg) | ||
2200 | { | ||
2201 | struct cdrom_device_ops *cdo = cdi->ops; | ||
2202 | int ret; | ||
2203 | |||
2204 | /* Try the generic SCSI command ioctl's first.. */ | ||
2205 | ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, (void __user *)arg); | ||
2206 | if (ret != -ENOTTY) | ||
2207 | return ret; | ||
2208 | |||
2209 | /* the first few commands do not deal with audio drive_info, but | ||
2210 | only with routines in cdrom device operations. */ | ||
2211 | switch (cmd) { | ||
2212 | case CDROMMULTISESSION: { | ||
2213 | struct cdrom_multisession ms_info; | ||
2214 | u_char requested_format; | ||
2215 | cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); | ||
2216 | if (!(cdo->capability & CDC_MULTI_SESSION)) | ||
2217 | return -ENOSYS; | ||
2218 | IOCTL_IN(arg, struct cdrom_multisession, ms_info); | ||
2219 | requested_format = ms_info.addr_format; | ||
2220 | if (!((requested_format == CDROM_MSF) || | ||
2221 | (requested_format == CDROM_LBA))) | ||
2222 | return -EINVAL; | ||
2223 | ms_info.addr_format = CDROM_LBA; | ||
2224 | if ((ret=cdo->get_last_session(cdi, &ms_info))) | ||
2225 | return ret; | ||
2226 | sanitize_format(&ms_info.addr, &ms_info.addr_format, | ||
2227 | requested_format); | ||
2228 | IOCTL_OUT(arg, struct cdrom_multisession, ms_info); | ||
2229 | cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); | ||
2230 | return 0; | ||
2231 | } | ||
2232 | |||
2233 | case CDROMEJECT: { | ||
2234 | cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); | ||
2235 | if (!CDROM_CAN(CDC_OPEN_TRAY)) | ||
2236 | return -ENOSYS; | ||
2237 | if (cdi->use_count != 1 || keeplocked) | ||
2238 | return -EBUSY; | ||
2239 | if (CDROM_CAN(CDC_LOCK)) | ||
2240 | if ((ret=cdo->lock_door(cdi, 0))) | ||
2241 | return ret; | ||
2242 | |||
2243 | return cdo->tray_move(cdi, 1); | ||
2244 | } | ||
2245 | |||
2246 | case CDROMCLOSETRAY: { | ||
2247 | cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); | ||
2248 | if (!CDROM_CAN(CDC_CLOSE_TRAY)) | ||
2249 | return -ENOSYS; | ||
2250 | return cdo->tray_move(cdi, 0); | ||
2251 | } | ||
2252 | |||
2253 | case CDROMEJECT_SW: { | ||
2254 | cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); | ||
2255 | if (!CDROM_CAN(CDC_OPEN_TRAY)) | ||
2256 | return -ENOSYS; | ||
2257 | if (keeplocked) | ||
2258 | return -EBUSY; | ||
2259 | cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT); | ||
2260 | if (arg) | ||
2261 | cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT; | ||
2262 | return 0; | ||
2263 | } | ||
2264 | |||
2265 | case CDROM_MEDIA_CHANGED: { | ||
2266 | struct cdrom_changer_info *info; | ||
2267 | int changed; | ||
2268 | |||
2269 | cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); | ||
2270 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) | ||
2271 | return -ENOSYS; | ||
2272 | |||
2273 | /* cannot select disc or select current disc */ | ||
2274 | if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) | ||
2275 | return media_changed(cdi, 1); | ||
2276 | |||
2277 | if ((unsigned int)arg >= cdi->capacity) | ||
2278 | return -EINVAL; | ||
2279 | |||
2280 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
2281 | if (!info) | ||
2282 | return -ENOMEM; | ||
2283 | |||
2284 | if ((ret = cdrom_read_mech_status(cdi, info))) { | ||
2285 | kfree(info); | ||
2286 | return ret; | ||
2287 | } | ||
2288 | |||
2289 | changed = info->slots[arg].change; | ||
2290 | kfree(info); | ||
2291 | return changed; | ||
2292 | } | ||
2293 | |||
2294 | case CDROM_SET_OPTIONS: { | ||
2295 | cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); | ||
2296 | /* options need to be in sync with capability. too late for | ||
2297 | that, so we have to check each one separately... */ | ||
2298 | switch (arg) { | ||
2299 | case CDO_USE_FFLAGS: | ||
2300 | case CDO_CHECK_TYPE: | ||
2301 | break; | ||
2302 | case CDO_LOCK: | ||
2303 | if (!CDROM_CAN(CDC_LOCK)) | ||
2304 | return -ENOSYS; | ||
2305 | break; | ||
2306 | case 0: | ||
2307 | return cdi->options; | ||
2308 | /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */ | ||
2309 | default: | ||
2310 | if (!CDROM_CAN(arg)) | ||
2311 | return -ENOSYS; | ||
2312 | } | ||
2313 | cdi->options |= (int) arg; | ||
2314 | return cdi->options; | ||
2315 | } | ||
2316 | |||
2317 | case CDROM_CLEAR_OPTIONS: { | ||
2318 | cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); | ||
2319 | cdi->options &= ~(int) arg; | ||
2320 | return cdi->options; | ||
2321 | } | ||
2322 | |||
2323 | case CDROM_SELECT_SPEED: { | ||
2324 | cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); | ||
2325 | if (!CDROM_CAN(CDC_SELECT_SPEED)) | ||
2326 | return -ENOSYS; | ||
2327 | return cdo->select_speed(cdi, arg); | ||
2328 | } | ||
2329 | |||
2330 | case CDROM_SELECT_DISC: { | ||
2331 | cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); | ||
2332 | if (!CDROM_CAN(CDC_SELECT_DISC)) | ||
2333 | return -ENOSYS; | ||
2334 | |||
2335 | if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE)) | ||
2336 | if ((int)arg >= cdi->capacity) | ||
2337 | return -EINVAL; | ||
2338 | |||
2339 | /* cdo->select_disc is a hook to allow a driver-specific | ||
2340 | * way of seleting disc. However, since there is no | ||
2341 | * equiv hook for cdrom_slot_status this may not | ||
2342 | * actually be useful... | ||
2343 | */ | ||
2344 | if (cdo->select_disc != NULL) | ||
2345 | return cdo->select_disc(cdi, arg); | ||
2346 | |||
2347 | /* no driver specific select_disc(), call our own */ | ||
2348 | cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); | ||
2349 | return cdrom_select_disc(cdi, arg); | ||
2350 | } | ||
2351 | |||
2352 | case CDROMRESET: { | ||
2353 | if (!capable(CAP_SYS_ADMIN)) | ||
2354 | return -EACCES; | ||
2355 | cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); | ||
2356 | if (!CDROM_CAN(CDC_RESET)) | ||
2357 | return -ENOSYS; | ||
2358 | invalidate_bdev(ip->i_bdev, 0); | ||
2359 | return cdo->reset(cdi); | ||
2360 | } | ||
2361 | |||
2362 | case CDROM_LOCKDOOR: { | ||
2363 | cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); | ||
2364 | if (!CDROM_CAN(CDC_LOCK)) | ||
2365 | return -EDRIVE_CANT_DO_THIS; | ||
2366 | keeplocked = arg ? 1 : 0; | ||
2367 | /* don't unlock the door on multiple opens,but allow root | ||
2368 | * to do so */ | ||
2369 | if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN)) | ||
2370 | return -EBUSY; | ||
2371 | return cdo->lock_door(cdi, arg); | ||
2372 | } | ||
2373 | |||
2374 | case CDROM_DEBUG: { | ||
2375 | if (!capable(CAP_SYS_ADMIN)) | ||
2376 | return -EACCES; | ||
2377 | cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); | ||
2378 | debug = arg ? 1 : 0; | ||
2379 | return debug; | ||
2380 | } | ||
2381 | |||
2382 | case CDROM_GET_CAPABILITY: { | ||
2383 | cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); | ||
2384 | return (cdo->capability & ~cdi->mask); | ||
2385 | } | ||
2386 | |||
2387 | /* The following function is implemented, although very few audio | ||
2388 | * discs give Universal Product Code information, which should just be | ||
2389 | * the Medium Catalog Number on the box. Note, that the way the code | ||
2390 | * is written on the CD is /not/ uniform across all discs! | ||
2391 | */ | ||
2392 | case CDROM_GET_MCN: { | ||
2393 | struct cdrom_mcn mcn; | ||
2394 | cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); | ||
2395 | if (!(cdo->capability & CDC_MCN)) | ||
2396 | return -ENOSYS; | ||
2397 | if ((ret=cdo->get_mcn(cdi, &mcn))) | ||
2398 | return ret; | ||
2399 | IOCTL_OUT(arg, struct cdrom_mcn, mcn); | ||
2400 | cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); | ||
2401 | return 0; | ||
2402 | } | ||
2403 | |||
2404 | case CDROM_DRIVE_STATUS: { | ||
2405 | cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); | ||
2406 | if (!(cdo->capability & CDC_DRIVE_STATUS)) | ||
2407 | return -ENOSYS; | ||
2408 | if (!CDROM_CAN(CDC_SELECT_DISC)) | ||
2409 | return cdo->drive_status(cdi, CDSL_CURRENT); | ||
2410 | if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) | ||
2411 | return cdo->drive_status(cdi, CDSL_CURRENT); | ||
2412 | if (((int)arg >= cdi->capacity)) | ||
2413 | return -EINVAL; | ||
2414 | return cdrom_slot_status(cdi, arg); | ||
2415 | } | ||
2416 | |||
2417 | /* Ok, this is where problems start. The current interface for the | ||
2418 | CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption | ||
2419 | that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, | ||
2420 | while this is often the case, it is also very common for CDs to | ||
2421 | have some tracks with data, and some tracks with audio. Just | ||
2422 | because I feel like it, I declare the following to be the best | ||
2423 | way to cope. If the CD has ANY data tracks on it, it will be | ||
2424 | returned as a data CD. If it has any XA tracks, I will return | ||
2425 | it as that. Now I could simplify this interface by combining these | ||
2426 | returns with the above, but this more clearly demonstrates | ||
2427 | the problem with the current interface. Too bad this wasn't | ||
2428 | designed to use bitmasks... -Erik | ||
2429 | |||
2430 | Well, now we have the option CDS_MIXED: a mixed-type CD. | ||
2431 | User level programmers might feel the ioctl is not very useful. | ||
2432 | ---david | ||
2433 | */ | ||
2434 | case CDROM_DISC_STATUS: { | ||
2435 | tracktype tracks; | ||
2436 | cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); | ||
2437 | cdrom_count_tracks(cdi, &tracks); | ||
2438 | if (tracks.error) | ||
2439 | return(tracks.error); | ||
2440 | |||
2441 | /* Policy mode on */ | ||
2442 | if (tracks.audio > 0) { | ||
2443 | if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) | ||
2444 | return CDS_AUDIO; | ||
2445 | else | ||
2446 | return CDS_MIXED; | ||
2447 | } | ||
2448 | if (tracks.cdi > 0) return CDS_XA_2_2; | ||
2449 | if (tracks.xa > 0) return CDS_XA_2_1; | ||
2450 | if (tracks.data > 0) return CDS_DATA_1; | ||
2451 | /* Policy mode off */ | ||
2452 | |||
2453 | cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); | ||
2454 | return CDS_NO_INFO; | ||
2455 | } | ||
2456 | |||
2457 | case CDROM_CHANGER_NSLOTS: { | ||
2458 | cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); | ||
2459 | return cdi->capacity; | ||
2460 | } | ||
2461 | } | ||
2462 | |||
2463 | /* use the ioctls that are implemented through the generic_packet() | ||
2464 | interface. this may look at bit funny, but if -ENOTTY is | ||
2465 | returned that particular ioctl is not implemented and we | ||
2466 | let it go through the device specific ones. */ | ||
2467 | if (CDROM_CAN(CDC_GENERIC_PACKET)) { | ||
2468 | ret = mmc_ioctl(cdi, cmd, arg); | ||
2469 | if (ret != -ENOTTY) { | ||
2470 | return ret; | ||
2471 | } | ||
2472 | } | ||
2473 | |||
2474 | /* note: most of the cdinfo() calls are commented out here, | ||
2475 | because they fill up the sys log when CD players poll | ||
2476 | the drive. */ | ||
2477 | switch (cmd) { | ||
2478 | case CDROMSUBCHNL: { | ||
2479 | struct cdrom_subchnl q; | ||
2480 | u_char requested, back; | ||
2481 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2482 | return -ENOSYS; | ||
2483 | /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ | ||
2484 | IOCTL_IN(arg, struct cdrom_subchnl, q); | ||
2485 | requested = q.cdsc_format; | ||
2486 | if (!((requested == CDROM_MSF) || | ||
2487 | (requested == CDROM_LBA))) | ||
2488 | return -EINVAL; | ||
2489 | q.cdsc_format = CDROM_MSF; | ||
2490 | if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) | ||
2491 | return ret; | ||
2492 | back = q.cdsc_format; /* local copy */ | ||
2493 | sanitize_format(&q.cdsc_absaddr, &back, requested); | ||
2494 | sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); | ||
2495 | IOCTL_OUT(arg, struct cdrom_subchnl, q); | ||
2496 | /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ | ||
2497 | return 0; | ||
2498 | } | ||
2499 | case CDROMREADTOCHDR: { | ||
2500 | struct cdrom_tochdr header; | ||
2501 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2502 | return -ENOSYS; | ||
2503 | /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ | ||
2504 | IOCTL_IN(arg, struct cdrom_tochdr, header); | ||
2505 | if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) | ||
2506 | return ret; | ||
2507 | IOCTL_OUT(arg, struct cdrom_tochdr, header); | ||
2508 | /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ | ||
2509 | return 0; | ||
2510 | } | ||
2511 | case CDROMREADTOCENTRY: { | ||
2512 | struct cdrom_tocentry entry; | ||
2513 | u_char requested_format; | ||
2514 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2515 | return -ENOSYS; | ||
2516 | /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ | ||
2517 | IOCTL_IN(arg, struct cdrom_tocentry, entry); | ||
2518 | requested_format = entry.cdte_format; | ||
2519 | if (!((requested_format == CDROM_MSF) || | ||
2520 | (requested_format == CDROM_LBA))) | ||
2521 | return -EINVAL; | ||
2522 | /* make interface to low-level uniform */ | ||
2523 | entry.cdte_format = CDROM_MSF; | ||
2524 | if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) | ||
2525 | return ret; | ||
2526 | sanitize_format(&entry.cdte_addr, | ||
2527 | &entry.cdte_format, requested_format); | ||
2528 | IOCTL_OUT(arg, struct cdrom_tocentry, entry); | ||
2529 | /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ | ||
2530 | return 0; | ||
2531 | } | ||
2532 | case CDROMPLAYMSF: { | ||
2533 | struct cdrom_msf msf; | ||
2534 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2535 | return -ENOSYS; | ||
2536 | cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); | ||
2537 | IOCTL_IN(arg, struct cdrom_msf, msf); | ||
2538 | return cdo->audio_ioctl(cdi, cmd, &msf); | ||
2539 | } | ||
2540 | case CDROMPLAYTRKIND: { | ||
2541 | struct cdrom_ti ti; | ||
2542 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2543 | return -ENOSYS; | ||
2544 | cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); | ||
2545 | IOCTL_IN(arg, struct cdrom_ti, ti); | ||
2546 | CHECKAUDIO; | ||
2547 | return cdo->audio_ioctl(cdi, cmd, &ti); | ||
2548 | } | ||
2549 | case CDROMVOLCTRL: { | ||
2550 | struct cdrom_volctrl volume; | ||
2551 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2552 | return -ENOSYS; | ||
2553 | cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); | ||
2554 | IOCTL_IN(arg, struct cdrom_volctrl, volume); | ||
2555 | return cdo->audio_ioctl(cdi, cmd, &volume); | ||
2556 | } | ||
2557 | case CDROMVOLREAD: { | ||
2558 | struct cdrom_volctrl volume; | ||
2559 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2560 | return -ENOSYS; | ||
2561 | cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); | ||
2562 | if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) | ||
2563 | return ret; | ||
2564 | IOCTL_OUT(arg, struct cdrom_volctrl, volume); | ||
2565 | return 0; | ||
2566 | } | ||
2567 | case CDROMSTART: | ||
2568 | case CDROMSTOP: | ||
2569 | case CDROMPAUSE: | ||
2570 | case CDROMRESUME: { | ||
2571 | if (!CDROM_CAN(CDC_PLAY_AUDIO)) | ||
2572 | return -ENOSYS; | ||
2573 | cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); | ||
2574 | CHECKAUDIO; | ||
2575 | return cdo->audio_ioctl(cdi, cmd, NULL); | ||
2576 | } | ||
2577 | } /* switch */ | ||
2578 | |||
2579 | /* do the device specific ioctls */ | ||
2580 | if (CDROM_CAN(CDC_IOCTLS)) | ||
2581 | return cdo->dev_ioctl(cdi, cmd, arg); | ||
2582 | |||
2583 | return -ENOSYS; | ||
2584 | } | ||
2585 | |||
2586 | static inline | ||
2587 | int msf_to_lba(char m, char s, char f) | ||
2588 | { | ||
2589 | return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; | ||
2590 | } | ||
2591 | |||
2592 | /* | ||
2593 | * Required when we need to use READ_10 to issue other than 2048 block | ||
2594 | * reads | ||
2595 | */ | ||
2596 | static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) | ||
2597 | { | ||
2598 | struct cdrom_device_ops *cdo = cdi->ops; | ||
2599 | struct packet_command cgc; | ||
2600 | struct modesel_head mh; | ||
2601 | |||
2602 | memset(&mh, 0, sizeof(mh)); | ||
2603 | mh.block_desc_length = 0x08; | ||
2604 | mh.block_length_med = (size >> 8) & 0xff; | ||
2605 | mh.block_length_lo = size & 0xff; | ||
2606 | |||
2607 | memset(&cgc, 0, sizeof(cgc)); | ||
2608 | cgc.cmd[0] = 0x15; | ||
2609 | cgc.cmd[1] = 1 << 4; | ||
2610 | cgc.cmd[4] = 12; | ||
2611 | cgc.buflen = sizeof(mh); | ||
2612 | cgc.buffer = (char *) &mh; | ||
2613 | cgc.data_direction = CGC_DATA_WRITE; | ||
2614 | mh.block_desc_length = 0x08; | ||
2615 | mh.block_length_med = (size >> 8) & 0xff; | ||
2616 | mh.block_length_lo = size & 0xff; | ||
2617 | |||
2618 | return cdo->generic_packet(cdi, &cgc); | ||
2619 | } | ||
2620 | |||
2621 | static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | ||
2622 | unsigned long arg) | ||
2623 | { | ||
2624 | struct cdrom_device_ops *cdo = cdi->ops; | ||
2625 | struct packet_command cgc; | ||
2626 | struct request_sense sense; | ||
2627 | unsigned char buffer[32]; | ||
2628 | int ret = 0; | ||
2629 | |||
2630 | memset(&cgc, 0, sizeof(cgc)); | ||
2631 | |||
2632 | /* build a unified command and queue it through | ||
2633 | cdo->generic_packet() */ | ||
2634 | switch (cmd) { | ||
2635 | case CDROMREADRAW: | ||
2636 | case CDROMREADMODE1: | ||
2637 | case CDROMREADMODE2: { | ||
2638 | struct cdrom_msf msf; | ||
2639 | int blocksize = 0, format = 0, lba; | ||
2640 | |||
2641 | switch (cmd) { | ||
2642 | case CDROMREADRAW: | ||
2643 | blocksize = CD_FRAMESIZE_RAW; | ||
2644 | break; | ||
2645 | case CDROMREADMODE1: | ||
2646 | blocksize = CD_FRAMESIZE; | ||
2647 | format = 2; | ||
2648 | break; | ||
2649 | case CDROMREADMODE2: | ||
2650 | blocksize = CD_FRAMESIZE_RAW0; | ||
2651 | break; | ||
2652 | } | ||
2653 | IOCTL_IN(arg, struct cdrom_msf, msf); | ||
2654 | lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0); | ||
2655 | /* FIXME: we need upper bound checking, too!! */ | ||
2656 | if (lba < 0) | ||
2657 | return -EINVAL; | ||
2658 | cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); | ||
2659 | if (cgc.buffer == NULL) | ||
2660 | return -ENOMEM; | ||
2661 | memset(&sense, 0, sizeof(sense)); | ||
2662 | cgc.sense = &sense; | ||
2663 | cgc.data_direction = CGC_DATA_READ; | ||
2664 | ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); | ||
2665 | if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) { | ||
2666 | /* | ||
2667 | * SCSI-II devices are not required to support | ||
2668 | * READ_CD, so let's try switching block size | ||
2669 | */ | ||
2670 | /* FIXME: switch back again... */ | ||
2671 | if ((ret = cdrom_switch_blocksize(cdi, blocksize))) { | ||
2672 | kfree(cgc.buffer); | ||
2673 | return ret; | ||
2674 | } | ||
2675 | cgc.sense = NULL; | ||
2676 | ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1); | ||
2677 | ret |= cdrom_switch_blocksize(cdi, blocksize); | ||
2678 | } | ||
2679 | if (!ret && copy_to_user((char __user *)arg, cgc.buffer, blocksize)) | ||
2680 | ret = -EFAULT; | ||
2681 | kfree(cgc.buffer); | ||
2682 | return ret; | ||
2683 | } | ||
2684 | case CDROMREADAUDIO: { | ||
2685 | struct cdrom_read_audio ra; | ||
2686 | int lba; | ||
2687 | |||
2688 | IOCTL_IN(arg, struct cdrom_read_audio, ra); | ||
2689 | |||
2690 | if (ra.addr_format == CDROM_MSF) | ||
2691 | lba = msf_to_lba(ra.addr.msf.minute, | ||
2692 | ra.addr.msf.second, | ||
2693 | ra.addr.msf.frame); | ||
2694 | else if (ra.addr_format == CDROM_LBA) | ||
2695 | lba = ra.addr.lba; | ||
2696 | else | ||
2697 | return -EINVAL; | ||
2698 | |||
2699 | /* FIXME: we need upper bound checking, too!! */ | ||
2700 | if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES) | ||
2701 | return -EINVAL; | ||
2702 | |||
2703 | return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes); | ||
2704 | } | ||
2705 | case CDROMSUBCHNL: { | ||
2706 | struct cdrom_subchnl q; | ||
2707 | u_char requested, back; | ||
2708 | IOCTL_IN(arg, struct cdrom_subchnl, q); | ||
2709 | requested = q.cdsc_format; | ||
2710 | if (!((requested == CDROM_MSF) || | ||
2711 | (requested == CDROM_LBA))) | ||
2712 | return -EINVAL; | ||
2713 | q.cdsc_format = CDROM_MSF; | ||
2714 | if ((ret = cdrom_read_subchannel(cdi, &q, 0))) | ||
2715 | return ret; | ||
2716 | back = q.cdsc_format; /* local copy */ | ||
2717 | sanitize_format(&q.cdsc_absaddr, &back, requested); | ||
2718 | sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); | ||
2719 | IOCTL_OUT(arg, struct cdrom_subchnl, q); | ||
2720 | /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ | ||
2721 | return 0; | ||
2722 | } | ||
2723 | case CDROMPLAYMSF: { | ||
2724 | struct cdrom_msf msf; | ||
2725 | cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); | ||
2726 | IOCTL_IN(arg, struct cdrom_msf, msf); | ||
2727 | cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; | ||
2728 | cgc.cmd[3] = msf.cdmsf_min0; | ||
2729 | cgc.cmd[4] = msf.cdmsf_sec0; | ||
2730 | cgc.cmd[5] = msf.cdmsf_frame0; | ||
2731 | cgc.cmd[6] = msf.cdmsf_min1; | ||
2732 | cgc.cmd[7] = msf.cdmsf_sec1; | ||
2733 | cgc.cmd[8] = msf.cdmsf_frame1; | ||
2734 | cgc.data_direction = CGC_DATA_NONE; | ||
2735 | return cdo->generic_packet(cdi, &cgc); | ||
2736 | } | ||
2737 | case CDROMPLAYBLK: { | ||
2738 | struct cdrom_blk blk; | ||
2739 | cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); | ||
2740 | IOCTL_IN(arg, struct cdrom_blk, blk); | ||
2741 | cgc.cmd[0] = GPCMD_PLAY_AUDIO_10; | ||
2742 | cgc.cmd[2] = (blk.from >> 24) & 0xff; | ||
2743 | cgc.cmd[3] = (blk.from >> 16) & 0xff; | ||
2744 | cgc.cmd[4] = (blk.from >> 8) & 0xff; | ||
2745 | cgc.cmd[5] = blk.from & 0xff; | ||
2746 | cgc.cmd[7] = (blk.len >> 8) & 0xff; | ||
2747 | cgc.cmd[8] = blk.len & 0xff; | ||
2748 | cgc.data_direction = CGC_DATA_NONE; | ||
2749 | return cdo->generic_packet(cdi, &cgc); | ||
2750 | } | ||
2751 | case CDROMVOLCTRL: | ||
2752 | case CDROMVOLREAD: { | ||
2753 | struct cdrom_volctrl volctrl; | ||
2754 | char mask[sizeof(buffer)]; | ||
2755 | unsigned short offset; | ||
2756 | |||
2757 | cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); | ||
2758 | |||
2759 | IOCTL_IN(arg, struct cdrom_volctrl, volctrl); | ||
2760 | |||
2761 | cgc.buffer = buffer; | ||
2762 | cgc.buflen = 24; | ||
2763 | if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0))) | ||
2764 | return ret; | ||
2765 | |||
2766 | /* originally the code depended on buffer[1] to determine | ||
2767 | how much data is available for transfer. buffer[1] is | ||
2768 | unfortunately ambigious and the only reliable way seem | ||
2769 | to be to simply skip over the block descriptor... */ | ||
2770 | offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6)); | ||
2771 | |||
2772 | if (offset + 16 > sizeof(buffer)) | ||
2773 | return -E2BIG; | ||
2774 | |||
2775 | if (offset + 16 > cgc.buflen) { | ||
2776 | cgc.buflen = offset+16; | ||
2777 | ret = cdrom_mode_sense(cdi, &cgc, | ||
2778 | GPMODE_AUDIO_CTL_PAGE, 0); | ||
2779 | if (ret) | ||
2780 | return ret; | ||
2781 | } | ||
2782 | |||
2783 | /* sanity check */ | ||
2784 | if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || | ||
2785 | buffer[offset+1] < 14) | ||
2786 | return -EINVAL; | ||
2787 | |||
2788 | /* now we have the current volume settings. if it was only | ||
2789 | a CDROMVOLREAD, return these values */ | ||
2790 | if (cmd == CDROMVOLREAD) { | ||
2791 | volctrl.channel0 = buffer[offset+9]; | ||
2792 | volctrl.channel1 = buffer[offset+11]; | ||
2793 | volctrl.channel2 = buffer[offset+13]; | ||
2794 | volctrl.channel3 = buffer[offset+15]; | ||
2795 | IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); | ||
2796 | return 0; | ||
2797 | } | ||
2798 | |||
2799 | /* get the volume mask */ | ||
2800 | cgc.buffer = mask; | ||
2801 | if ((ret = cdrom_mode_sense(cdi, &cgc, | ||
2802 | GPMODE_AUDIO_CTL_PAGE, 1))) | ||
2803 | return ret; | ||
2804 | |||
2805 | buffer[offset+9] = volctrl.channel0 & mask[offset+9]; | ||
2806 | buffer[offset+11] = volctrl.channel1 & mask[offset+11]; | ||
2807 | buffer[offset+13] = volctrl.channel2 & mask[offset+13]; | ||
2808 | buffer[offset+15] = volctrl.channel3 & mask[offset+15]; | ||
2809 | |||
2810 | /* set volume */ | ||
2811 | cgc.buffer = buffer + offset - 8; | ||
2812 | memset(cgc.buffer, 0, 8); | ||
2813 | return cdrom_mode_select(cdi, &cgc); | ||
2814 | } | ||
2815 | |||
2816 | case CDROMSTART: | ||
2817 | case CDROMSTOP: { | ||
2818 | cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); | ||
2819 | cgc.cmd[0] = GPCMD_START_STOP_UNIT; | ||
2820 | cgc.cmd[1] = 1; | ||
2821 | cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; | ||
2822 | cgc.data_direction = CGC_DATA_NONE; | ||
2823 | return cdo->generic_packet(cdi, &cgc); | ||
2824 | } | ||
2825 | |||
2826 | case CDROMPAUSE: | ||
2827 | case CDROMRESUME: { | ||
2828 | cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); | ||
2829 | cgc.cmd[0] = GPCMD_PAUSE_RESUME; | ||
2830 | cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; | ||
2831 | cgc.data_direction = CGC_DATA_NONE; | ||
2832 | return cdo->generic_packet(cdi, &cgc); | ||
2833 | } | ||
2834 | |||
2835 | case DVD_READ_STRUCT: { | ||
2836 | dvd_struct *s; | ||
2837 | int size = sizeof(dvd_struct); | ||
2838 | if (!CDROM_CAN(CDC_DVD)) | ||
2839 | return -ENOSYS; | ||
2840 | if ((s = (dvd_struct *) kmalloc(size, GFP_KERNEL)) == NULL) | ||
2841 | return -ENOMEM; | ||
2842 | cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); | ||
2843 | if (copy_from_user(s, (dvd_struct __user *)arg, size)) { | ||
2844 | kfree(s); | ||
2845 | return -EFAULT; | ||
2846 | } | ||
2847 | if ((ret = dvd_read_struct(cdi, s))) { | ||
2848 | kfree(s); | ||
2849 | return ret; | ||
2850 | } | ||
2851 | if (copy_to_user((dvd_struct __user *)arg, s, size)) | ||
2852 | ret = -EFAULT; | ||
2853 | kfree(s); | ||
2854 | return ret; | ||
2855 | } | ||
2856 | |||
2857 | case DVD_AUTH: { | ||
2858 | dvd_authinfo ai; | ||
2859 | if (!CDROM_CAN(CDC_DVD)) | ||
2860 | return -ENOSYS; | ||
2861 | cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); | ||
2862 | IOCTL_IN(arg, dvd_authinfo, ai); | ||
2863 | if ((ret = dvd_do_auth (cdi, &ai))) | ||
2864 | return ret; | ||
2865 | IOCTL_OUT(arg, dvd_authinfo, ai); | ||
2866 | return 0; | ||
2867 | } | ||
2868 | |||
2869 | case CDROM_NEXT_WRITABLE: { | ||
2870 | long next = 0; | ||
2871 | cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); | ||
2872 | if ((ret = cdrom_get_next_writable(cdi, &next))) | ||
2873 | return ret; | ||
2874 | IOCTL_OUT(arg, long, next); | ||
2875 | return 0; | ||
2876 | } | ||
2877 | case CDROM_LAST_WRITTEN: { | ||
2878 | long last = 0; | ||
2879 | cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); | ||
2880 | if ((ret = cdrom_get_last_written(cdi, &last))) | ||
2881 | return ret; | ||
2882 | IOCTL_OUT(arg, long, last); | ||
2883 | return 0; | ||
2884 | } | ||
2885 | } /* switch */ | ||
2886 | |||
2887 | return -ENOTTY; | ||
2888 | } | ||
2889 | |||
2890 | static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type, | ||
2891 | track_information *ti) | ||
2892 | { | ||
2893 | struct cdrom_device_ops *cdo = cdi->ops; | ||
2894 | struct packet_command cgc; | ||
2895 | int ret, buflen; | ||
2896 | |||
2897 | init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); | ||
2898 | cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; | ||
2899 | cgc.cmd[1] = type & 3; | ||
2900 | cgc.cmd[4] = (track & 0xff00) >> 8; | ||
2901 | cgc.cmd[5] = track & 0xff; | ||
2902 | cgc.cmd[8] = 8; | ||
2903 | cgc.quiet = 1; | ||
2904 | |||
2905 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
2906 | return ret; | ||
2907 | |||
2908 | buflen = be16_to_cpu(ti->track_information_length) + | ||
2909 | sizeof(ti->track_information_length); | ||
2910 | |||
2911 | if (buflen > sizeof(track_information)) | ||
2912 | buflen = sizeof(track_information); | ||
2913 | |||
2914 | cgc.cmd[8] = cgc.buflen = buflen; | ||
2915 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
2916 | return ret; | ||
2917 | |||
2918 | /* return actual fill size */ | ||
2919 | return buflen; | ||
2920 | } | ||
2921 | |||
2922 | /* requires CD R/RW */ | ||
2923 | static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di) | ||
2924 | { | ||
2925 | struct cdrom_device_ops *cdo = cdi->ops; | ||
2926 | struct packet_command cgc; | ||
2927 | int ret, buflen; | ||
2928 | |||
2929 | /* set up command and get the disc info */ | ||
2930 | init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); | ||
2931 | cgc.cmd[0] = GPCMD_READ_DISC_INFO; | ||
2932 | cgc.cmd[8] = cgc.buflen = 2; | ||
2933 | cgc.quiet = 1; | ||
2934 | |||
2935 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
2936 | return ret; | ||
2937 | |||
2938 | /* not all drives have the same disc_info length, so requeue | ||
2939 | * packet with the length the drive tells us it can supply | ||
2940 | */ | ||
2941 | buflen = be16_to_cpu(di->disc_information_length) + | ||
2942 | sizeof(di->disc_information_length); | ||
2943 | |||
2944 | if (buflen > sizeof(disc_information)) | ||
2945 | buflen = sizeof(disc_information); | ||
2946 | |||
2947 | cgc.cmd[8] = cgc.buflen = buflen; | ||
2948 | if ((ret = cdo->generic_packet(cdi, &cgc))) | ||
2949 | return ret; | ||
2950 | |||
2951 | /* return actual fill size */ | ||
2952 | return buflen; | ||
2953 | } | ||
2954 | |||
2955 | /* return the last written block on the CD-R media. this is for the udf | ||
2956 | file system. */ | ||
2957 | int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) | ||
2958 | { | ||
2959 | struct cdrom_tocentry toc; | ||
2960 | disc_information di; | ||
2961 | track_information ti; | ||
2962 | __u32 last_track; | ||
2963 | int ret = -1, ti_size; | ||
2964 | |||
2965 | if (!CDROM_CAN(CDC_GENERIC_PACKET)) | ||
2966 | goto use_toc; | ||
2967 | |||
2968 | ret = cdrom_get_disc_info(cdi, &di); | ||
2969 | if (ret < (int)(offsetof(typeof(di), last_track_lsb) | ||
2970 | + sizeof(di.last_track_lsb))) | ||
2971 | goto use_toc; | ||
2972 | |||
2973 | /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ | ||
2974 | last_track = (di.last_track_msb << 8) | di.last_track_lsb; | ||
2975 | ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); | ||
2976 | if (ti_size < (int)offsetof(typeof(ti), track_start)) | ||
2977 | goto use_toc; | ||
2978 | |||
2979 | /* if this track is blank, try the previous. */ | ||
2980 | if (ti.blank) { | ||
2981 | if (last_track==1) | ||
2982 | goto use_toc; | ||
2983 | last_track--; | ||
2984 | ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); | ||
2985 | } | ||
2986 | |||
2987 | if (ti_size < (int)(offsetof(typeof(ti), track_size) | ||
2988 | + sizeof(ti.track_size))) | ||
2989 | goto use_toc; | ||
2990 | |||
2991 | /* if last recorded field is valid, return it. */ | ||
2992 | if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) | ||
2993 | + sizeof(ti.last_rec_address))) { | ||
2994 | *last_written = be32_to_cpu(ti.last_rec_address); | ||
2995 | } else { | ||
2996 | /* make it up instead */ | ||
2997 | *last_written = be32_to_cpu(ti.track_start) + | ||
2998 | be32_to_cpu(ti.track_size); | ||
2999 | if (ti.free_blocks) | ||
3000 | *last_written -= (be32_to_cpu(ti.free_blocks) + 7); | ||
3001 | } | ||
3002 | return 0; | ||
3003 | |||
3004 | /* this is where we end up if the drive either can't do a | ||
3005 | GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if | ||
3006 | it doesn't give enough information or fails. then we return | ||
3007 | the toc contents. */ | ||
3008 | use_toc: | ||
3009 | toc.cdte_format = CDROM_MSF; | ||
3010 | toc.cdte_track = CDROM_LEADOUT; | ||
3011 | if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) | ||
3012 | return ret; | ||
3013 | sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); | ||
3014 | *last_written = toc.cdte_addr.lba; | ||
3015 | return 0; | ||
3016 | } | ||
3017 | |||
3018 | /* return the next writable block. also for udf file system. */ | ||
3019 | static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable) | ||
3020 | { | ||
3021 | disc_information di; | ||
3022 | track_information ti; | ||
3023 | __u16 last_track; | ||
3024 | int ret, ti_size; | ||
3025 | |||
3026 | if (!CDROM_CAN(CDC_GENERIC_PACKET)) | ||
3027 | goto use_last_written; | ||
3028 | |||
3029 | ret = cdrom_get_disc_info(cdi, &di); | ||
3030 | if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) | ||
3031 | + sizeof(di.last_track_lsb)) | ||
3032 | goto use_last_written; | ||
3033 | |||
3034 | /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ | ||
3035 | last_track = (di.last_track_msb << 8) | di.last_track_lsb; | ||
3036 | ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); | ||
3037 | if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) | ||
3038 | goto use_last_written; | ||
3039 | |||
3040 | /* if this track is blank, try the previous. */ | ||
3041 | if (ti.blank) { | ||
3042 | if (last_track == 1) | ||
3043 | goto use_last_written; | ||
3044 | last_track--; | ||
3045 | ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); | ||
3046 | if (ti_size < 0) | ||
3047 | goto use_last_written; | ||
3048 | } | ||
3049 | |||
3050 | /* if next recordable address field is valid, use it. */ | ||
3051 | if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) | ||
3052 | + sizeof(ti.next_writable)) { | ||
3053 | *next_writable = be32_to_cpu(ti.next_writable); | ||
3054 | return 0; | ||
3055 | } | ||
3056 | |||
3057 | use_last_written: | ||
3058 | if ((ret = cdrom_get_last_written(cdi, next_writable))) { | ||
3059 | *next_writable = 0; | ||
3060 | return ret; | ||
3061 | } else { | ||
3062 | *next_writable += 7; | ||
3063 | return 0; | ||
3064 | } | ||
3065 | } | ||
3066 | |||
3067 | EXPORT_SYMBOL(cdrom_get_last_written); | ||
3068 | EXPORT_SYMBOL(register_cdrom); | ||
3069 | EXPORT_SYMBOL(unregister_cdrom); | ||
3070 | EXPORT_SYMBOL(cdrom_open); | ||
3071 | EXPORT_SYMBOL(cdrom_release); | ||
3072 | EXPORT_SYMBOL(cdrom_ioctl); | ||
3073 | EXPORT_SYMBOL(cdrom_media_changed); | ||
3074 | EXPORT_SYMBOL(cdrom_number_of_slots); | ||
3075 | EXPORT_SYMBOL(cdrom_mode_select); | ||
3076 | EXPORT_SYMBOL(cdrom_mode_sense); | ||
3077 | EXPORT_SYMBOL(init_cdrom_command); | ||
3078 | EXPORT_SYMBOL(cdrom_get_media_event); | ||
3079 | |||
3080 | #ifdef CONFIG_SYSCTL | ||
3081 | |||
3082 | #define CDROM_STR_SIZE 1000 | ||
3083 | |||
3084 | static struct cdrom_sysctl_settings { | ||
3085 | char info[CDROM_STR_SIZE]; /* general info */ | ||
3086 | int autoclose; /* close tray upon mount, etc */ | ||
3087 | int autoeject; /* eject on umount */ | ||
3088 | int debug; /* turn on debugging messages */ | ||
3089 | int lock; /* lock the door on device open */ | ||
3090 | int check; /* check media type */ | ||
3091 | } cdrom_sysctl_settings; | ||
3092 | |||
3093 | static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, | ||
3094 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
3095 | { | ||
3096 | int pos; | ||
3097 | struct cdrom_device_info *cdi; | ||
3098 | char *info = cdrom_sysctl_settings.info; | ||
3099 | |||
3100 | if (!*lenp || (*ppos && !write)) { | ||
3101 | *lenp = 0; | ||
3102 | return 0; | ||
3103 | } | ||
3104 | |||
3105 | pos = sprintf(info, "CD-ROM information, " VERSION "\n"); | ||
3106 | |||
3107 | pos += sprintf(info+pos, "\ndrive name:\t"); | ||
3108 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3109 | pos += sprintf(info+pos, "\t%s", cdi->name); | ||
3110 | |||
3111 | pos += sprintf(info+pos, "\ndrive speed:\t"); | ||
3112 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3113 | pos += sprintf(info+pos, "\t%d", cdi->speed); | ||
3114 | |||
3115 | pos += sprintf(info+pos, "\ndrive # of slots:"); | ||
3116 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3117 | pos += sprintf(info+pos, "\t%d", cdi->capacity); | ||
3118 | |||
3119 | pos += sprintf(info+pos, "\nCan close tray:\t"); | ||
3120 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3121 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); | ||
3122 | |||
3123 | pos += sprintf(info+pos, "\nCan open tray:\t"); | ||
3124 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3125 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); | ||
3126 | |||
3127 | pos += sprintf(info+pos, "\nCan lock tray:\t"); | ||
3128 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3129 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); | ||
3130 | |||
3131 | pos += sprintf(info+pos, "\nCan change speed:"); | ||
3132 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3133 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); | ||
3134 | |||
3135 | pos += sprintf(info+pos, "\nCan select disk:"); | ||
3136 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3137 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); | ||
3138 | |||
3139 | pos += sprintf(info+pos, "\nCan read multisession:"); | ||
3140 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3141 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); | ||
3142 | |||
3143 | pos += sprintf(info+pos, "\nCan read MCN:\t"); | ||
3144 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3145 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); | ||
3146 | |||
3147 | pos += sprintf(info+pos, "\nReports media changed:"); | ||
3148 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3149 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); | ||
3150 | |||
3151 | pos += sprintf(info+pos, "\nCan play audio:\t"); | ||
3152 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3153 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); | ||
3154 | |||
3155 | pos += sprintf(info+pos, "\nCan write CD-R:\t"); | ||
3156 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3157 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); | ||
3158 | |||
3159 | pos += sprintf(info+pos, "\nCan write CD-RW:"); | ||
3160 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3161 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); | ||
3162 | |||
3163 | pos += sprintf(info+pos, "\nCan read DVD:\t"); | ||
3164 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3165 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); | ||
3166 | |||
3167 | pos += sprintf(info+pos, "\nCan write DVD-R:"); | ||
3168 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3169 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); | ||
3170 | |||
3171 | pos += sprintf(info+pos, "\nCan write DVD-RAM:"); | ||
3172 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3173 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); | ||
3174 | |||
3175 | pos += sprintf(info+pos, "\nCan read MRW:\t"); | ||
3176 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3177 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0); | ||
3178 | |||
3179 | pos += sprintf(info+pos, "\nCan write MRW:\t"); | ||
3180 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3181 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0); | ||
3182 | |||
3183 | pos += sprintf(info+pos, "\nCan write RAM:\t"); | ||
3184 | for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) | ||
3185 | pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0); | ||
3186 | |||
3187 | strcpy(info+pos,"\n\n"); | ||
3188 | |||
3189 | return proc_dostring(ctl, write, filp, buffer, lenp, ppos); | ||
3190 | } | ||
3191 | |||
3192 | /* Unfortunately, per device settings are not implemented through | ||
3193 | procfs/sysctl yet. When they are, this will naturally disappear. For now | ||
3194 | just update all drives. Later this will become the template on which | ||
3195 | new registered drives will be based. */ | ||
3196 | static void cdrom_update_settings(void) | ||
3197 | { | ||
3198 | struct cdrom_device_info *cdi; | ||
3199 | |||
3200 | for (cdi = topCdromPtr; cdi != NULL; cdi = cdi->next) { | ||
3201 | if (autoclose && CDROM_CAN(CDC_CLOSE_TRAY)) | ||
3202 | cdi->options |= CDO_AUTO_CLOSE; | ||
3203 | else if (!autoclose) | ||
3204 | cdi->options &= ~CDO_AUTO_CLOSE; | ||
3205 | if (autoeject && CDROM_CAN(CDC_OPEN_TRAY)) | ||
3206 | cdi->options |= CDO_AUTO_EJECT; | ||
3207 | else if (!autoeject) | ||
3208 | cdi->options &= ~CDO_AUTO_EJECT; | ||
3209 | if (lockdoor && CDROM_CAN(CDC_LOCK)) | ||
3210 | cdi->options |= CDO_LOCK; | ||
3211 | else if (!lockdoor) | ||
3212 | cdi->options &= ~CDO_LOCK; | ||
3213 | if (check_media_type) | ||
3214 | cdi->options |= CDO_CHECK_TYPE; | ||
3215 | else | ||
3216 | cdi->options &= ~CDO_CHECK_TYPE; | ||
3217 | } | ||
3218 | } | ||
3219 | |||
3220 | static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp, | ||
3221 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
3222 | { | ||
3223 | int *valp = ctl->data; | ||
3224 | int val = *valp; | ||
3225 | int ret; | ||
3226 | |||
3227 | ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); | ||
3228 | |||
3229 | if (write && *valp != val) { | ||
3230 | |||
3231 | /* we only care for 1 or 0. */ | ||
3232 | if (*valp) | ||
3233 | *valp = 1; | ||
3234 | else | ||
3235 | *valp = 0; | ||
3236 | |||
3237 | switch (ctl->ctl_name) { | ||
3238 | case DEV_CDROM_AUTOCLOSE: { | ||
3239 | if (valp == &cdrom_sysctl_settings.autoclose) | ||
3240 | autoclose = cdrom_sysctl_settings.autoclose; | ||
3241 | break; | ||
3242 | } | ||
3243 | case DEV_CDROM_AUTOEJECT: { | ||
3244 | if (valp == &cdrom_sysctl_settings.autoeject) | ||
3245 | autoeject = cdrom_sysctl_settings.autoeject; | ||
3246 | break; | ||
3247 | } | ||
3248 | case DEV_CDROM_DEBUG: { | ||
3249 | if (valp == &cdrom_sysctl_settings.debug) | ||
3250 | debug = cdrom_sysctl_settings.debug; | ||
3251 | break; | ||
3252 | } | ||
3253 | case DEV_CDROM_LOCK: { | ||
3254 | if (valp == &cdrom_sysctl_settings.lock) | ||
3255 | lockdoor = cdrom_sysctl_settings.lock; | ||
3256 | break; | ||
3257 | } | ||
3258 | case DEV_CDROM_CHECK_MEDIA: { | ||
3259 | if (valp == &cdrom_sysctl_settings.check) | ||
3260 | check_media_type = cdrom_sysctl_settings.check; | ||
3261 | break; | ||
3262 | } | ||
3263 | } | ||
3264 | /* update the option flags according to the changes. we | ||
3265 | don't have per device options through sysctl yet, | ||
3266 | but we will have and then this will disappear. */ | ||
3267 | cdrom_update_settings(); | ||
3268 | } | ||
3269 | |||
3270 | return ret; | ||
3271 | } | ||
3272 | |||
3273 | /* Place files in /proc/sys/dev/cdrom */ | ||
3274 | static ctl_table cdrom_table[] = { | ||
3275 | { | ||
3276 | .ctl_name = DEV_CDROM_INFO, | ||
3277 | .procname = "info", | ||
3278 | .data = &cdrom_sysctl_settings.info, | ||
3279 | .maxlen = CDROM_STR_SIZE, | ||
3280 | .mode = 0444, | ||
3281 | .proc_handler = &cdrom_sysctl_info, | ||
3282 | }, | ||
3283 | { | ||
3284 | .ctl_name = DEV_CDROM_AUTOCLOSE, | ||
3285 | .procname = "autoclose", | ||
3286 | .data = &cdrom_sysctl_settings.autoclose, | ||
3287 | .maxlen = sizeof(int), | ||
3288 | .mode = 0644, | ||
3289 | .proc_handler = &cdrom_sysctl_handler, | ||
3290 | }, | ||
3291 | { | ||
3292 | .ctl_name = DEV_CDROM_AUTOEJECT, | ||
3293 | .procname = "autoeject", | ||
3294 | .data = &cdrom_sysctl_settings.autoeject, | ||
3295 | .maxlen = sizeof(int), | ||
3296 | .mode = 0644, | ||
3297 | .proc_handler = &cdrom_sysctl_handler, | ||
3298 | }, | ||
3299 | { | ||
3300 | .ctl_name = DEV_CDROM_DEBUG, | ||
3301 | .procname = "debug", | ||
3302 | .data = &cdrom_sysctl_settings.debug, | ||
3303 | .maxlen = sizeof(int), | ||
3304 | .mode = 0644, | ||
3305 | .proc_handler = &cdrom_sysctl_handler, | ||
3306 | }, | ||
3307 | { | ||
3308 | .ctl_name = DEV_CDROM_LOCK, | ||
3309 | .procname = "lock", | ||
3310 | .data = &cdrom_sysctl_settings.lock, | ||
3311 | .maxlen = sizeof(int), | ||
3312 | .mode = 0644, | ||
3313 | .proc_handler = &cdrom_sysctl_handler, | ||
3314 | }, | ||
3315 | { | ||
3316 | .ctl_name = DEV_CDROM_CHECK_MEDIA, | ||
3317 | .procname = "check_media", | ||
3318 | .data = &cdrom_sysctl_settings.check, | ||
3319 | .maxlen = sizeof(int), | ||
3320 | .mode = 0644, | ||
3321 | .proc_handler = &cdrom_sysctl_handler | ||
3322 | }, | ||
3323 | { .ctl_name = 0 } | ||
3324 | }; | ||
3325 | |||
3326 | static ctl_table cdrom_cdrom_table[] = { | ||
3327 | { | ||
3328 | .ctl_name = DEV_CDROM, | ||
3329 | .procname = "cdrom", | ||
3330 | .maxlen = 0, | ||
3331 | .mode = 0555, | ||
3332 | .child = cdrom_table, | ||
3333 | }, | ||
3334 | { .ctl_name = 0 } | ||
3335 | }; | ||
3336 | |||
3337 | /* Make sure that /proc/sys/dev is there */ | ||
3338 | static ctl_table cdrom_root_table[] = { | ||
3339 | { | ||
3340 | .ctl_name = CTL_DEV, | ||
3341 | .procname = "dev", | ||
3342 | .maxlen = 0, | ||
3343 | .mode = 0555, | ||
3344 | .child = cdrom_cdrom_table, | ||
3345 | }, | ||
3346 | { .ctl_name = 0 } | ||
3347 | }; | ||
3348 | static struct ctl_table_header *cdrom_sysctl_header; | ||
3349 | |||
3350 | static void cdrom_sysctl_register(void) | ||
3351 | { | ||
3352 | static int initialized; | ||
3353 | |||
3354 | if (initialized == 1) | ||
3355 | return; | ||
3356 | |||
3357 | cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); | ||
3358 | if (cdrom_root_table->ctl_name && cdrom_root_table->child->de) | ||
3359 | cdrom_root_table->child->de->owner = THIS_MODULE; | ||
3360 | |||
3361 | /* set the defaults */ | ||
3362 | cdrom_sysctl_settings.autoclose = autoclose; | ||
3363 | cdrom_sysctl_settings.autoeject = autoeject; | ||
3364 | cdrom_sysctl_settings.debug = debug; | ||
3365 | cdrom_sysctl_settings.lock = lockdoor; | ||
3366 | cdrom_sysctl_settings.check = check_media_type; | ||
3367 | |||
3368 | initialized = 1; | ||
3369 | } | ||
3370 | |||
3371 | static void cdrom_sysctl_unregister(void) | ||
3372 | { | ||
3373 | if (cdrom_sysctl_header) | ||
3374 | unregister_sysctl_table(cdrom_sysctl_header); | ||
3375 | } | ||
3376 | |||
3377 | #endif /* CONFIG_SYSCTL */ | ||
3378 | |||
3379 | static int __init cdrom_init(void) | ||
3380 | { | ||
3381 | #ifdef CONFIG_SYSCTL | ||
3382 | cdrom_sysctl_register(); | ||
3383 | #endif | ||
3384 | return 0; | ||
3385 | } | ||
3386 | |||
3387 | static void __exit cdrom_exit(void) | ||
3388 | { | ||
3389 | printk(KERN_INFO "Uniform CD-ROM driver unloaded\n"); | ||
3390 | #ifdef CONFIG_SYSCTL | ||
3391 | cdrom_sysctl_unregister(); | ||
3392 | #endif | ||
3393 | } | ||
3394 | |||
3395 | module_init(cdrom_init); | ||
3396 | module_exit(cdrom_exit); | ||
3397 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c new file mode 100644 index 000000000000..647a71b12a2a --- /dev/null +++ b/drivers/cdrom/cdu31a.c | |||
@@ -0,0 +1,3248 @@ | |||
1 | /* | ||
2 | * Sony CDU-31A CDROM interface device driver. | ||
3 | * | ||
4 | * Corey Minyard (minyard@wf-rch.cirr.com) | ||
5 | * | ||
6 | * Colossians 3:17 | ||
7 | * | ||
8 | * See Documentation/cdrom/cdu31a for additional details about this driver. | ||
9 | * | ||
10 | * The Sony interface device driver handles Sony interface CDROM | ||
11 | * drives and provides a complete block-level interface as well as an | ||
12 | * ioctl() interface compatible with the Sun (as specified in | ||
13 | * include/linux/cdrom.h). With this interface, CDROMs can be | ||
14 | * accessed and standard audio CDs can be played back normally. | ||
15 | * | ||
16 | * WARNING - All autoprobes have been removed from the driver. | ||
17 | * You MUST configure the CDU31A via a LILO config | ||
18 | * at boot time or in lilo.conf. I have the | ||
19 | * following in my lilo.conf: | ||
20 | * | ||
21 | * append="cdu31a=0x1f88,0,PAS" | ||
22 | * | ||
23 | * The first number is the I/O base address of the | ||
24 | * card. The second is the interrupt (0 means none). | ||
25 | * The third should be "PAS" if on a Pro-Audio | ||
26 | * spectrum, or nothing if on something else. | ||
27 | * | ||
28 | * This interface is (unfortunately) a polled interface. This is | ||
29 | * because most Sony interfaces are set up with DMA and interrupts | ||
30 | * disables. Some (like mine) do not even have the capability to | ||
31 | * handle interrupts or DMA. For this reason you will see a lot of | ||
32 | * the following: | ||
33 | * | ||
34 | * retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; | ||
35 | * while (time_before(jiffies, retry_count) && (! <some condition to wait for)) | ||
36 | * { | ||
37 | * while (handle_sony_cd_attention()) | ||
38 | * ; | ||
39 | * | ||
40 | * sony_sleep(); | ||
41 | * } | ||
42 | * if (the condition not met) | ||
43 | * { | ||
44 | * return an error; | ||
45 | * } | ||
46 | * | ||
47 | * This ugly hack waits for something to happen, sleeping a little | ||
48 | * between every try. it also handles attentions, which are | ||
49 | * asynchronous events from the drive informing the driver that a disk | ||
50 | * has been inserted, removed, etc. | ||
51 | * | ||
52 | * NEWS FLASH - The driver now supports interrupts but they are | ||
53 | * turned off by default. Use of interrupts is highly encouraged, it | ||
54 | * cuts CPU usage down to a reasonable level. I had DMA in for a while | ||
55 | * but PC DMA is just too slow. Better to just insb() it. | ||
56 | * | ||
57 | * One thing about these drives: They talk in MSF (Minute Second Frame) format. | ||
58 | * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a | ||
59 | * disk. The funny thing is that these are sent to the drive in BCD, but the | ||
60 | * interface wants to see them in decimal. A lot of conversion goes on. | ||
61 | * | ||
62 | * DRIVER SPECIAL FEATURES | ||
63 | * ----------------------- | ||
64 | * | ||
65 | * This section describes features beyond the normal audio and CD-ROM | ||
66 | * functions of the drive. | ||
67 | * | ||
68 | * XA compatibility | ||
69 | * | ||
70 | * The driver should support XA disks for both the CDU31A and CDU33A. | ||
71 | * It does this transparently, the using program doesn't need to set it. | ||
72 | * | ||
73 | * Multi-Session | ||
74 | * | ||
75 | * A multi-session disk looks just like a normal disk to the user. | ||
76 | * Just mount one normally, and all the data should be there. | ||
77 | * A special thanks to Koen for help with this! | ||
78 | * | ||
79 | * Raw sector I/O | ||
80 | * | ||
81 | * Using the CDROMREADAUDIO it is possible to read raw audio and data | ||
82 | * tracks. Both operations return 2352 bytes per sector. On the data | ||
83 | * tracks, the first 12 bytes is not returned by the drive and the value | ||
84 | * of that data is indeterminate. | ||
85 | * | ||
86 | * | ||
87 | * Copyright (C) 1993 Corey Minyard | ||
88 | * | ||
89 | * This program is free software; you can redistribute it and/or modify | ||
90 | * it under the terms of the GNU General Public License as published by | ||
91 | * the Free Software Foundation; either version 2 of the License, or | ||
92 | * (at your option) any later version. | ||
93 | * | ||
94 | * This program is distributed in the hope that it will be useful, | ||
95 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
96 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
97 | * GNU General Public License for more details. | ||
98 | * | ||
99 | * You should have received a copy of the GNU General Public License | ||
100 | * along with this program; if not, write to the Free Software | ||
101 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
102 | * | ||
103 | * TODO: | ||
104 | * CDs with form1 and form2 sectors cause problems | ||
105 | * with current read-ahead strategy. | ||
106 | * | ||
107 | * Credits: | ||
108 | * Heiko Eissfeldt <heiko@colossus.escape.de> | ||
109 | * For finding abug in the return of the track numbers. | ||
110 | * TOC processing redone for proper multisession support. | ||
111 | * | ||
112 | * | ||
113 | * It probably a little late to be adding a history, but I guess I | ||
114 | * will start. | ||
115 | * | ||
116 | * 10/24/95 - Added support for disabling the eject button when the | ||
117 | * drive is open. Note that there is a small problem | ||
118 | * still here, if the eject button is pushed while the | ||
119 | * drive light is flashing, the drive will return a bad | ||
120 | * status and be reset. It recovers, though. | ||
121 | * | ||
122 | * 03/07/97 - Fixed a problem with timers. | ||
123 | * | ||
124 | * | ||
125 | * 18 Spetember 1997 -- Ported to Uniform CD-ROM driver by | ||
126 | * Heiko Eissfeldt <heiko@colossus.escape.de> with additional | ||
127 | * changes by Erik Andersen <andersee@debian.org> | ||
128 | * | ||
129 | * 24 January 1998 -- Removed the scd_disc_status() function, which was now | ||
130 | * just dead code left over from the port. | ||
131 | * Erik Andersen <andersee@debian.org> | ||
132 | * | ||
133 | * 16 July 1998 -- Drive donated to Erik Andersen by John Kodis | ||
134 | * <kodis@jagunet.com>. Work begun on fixing driver to | ||
135 | * work under 2.1.X. Added temporary extra printks | ||
136 | * which seem to slow it down enough to work. | ||
137 | * | ||
138 | * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
139 | * Removed init_module & cleanup_module in favor of | ||
140 | * module_init & module_exit. | ||
141 | * Torben Mathiasen <tmm@image.dk> | ||
142 | * | ||
143 | * 22 October 2004 -- Make the driver work in 2.6.X | ||
144 | * Added workaround to fix hard lockups on eject | ||
145 | * Fixed door locking problem after mounting empty drive | ||
146 | * Set double-speed drives to double speed by default | ||
147 | * Removed all readahead things - not needed anymore | ||
148 | * Ondrej Zary <rainbow@rainbow-software.org> | ||
149 | */ | ||
150 | |||
151 | #define DEBUG 1 | ||
152 | |||
153 | #include <linux/major.h> | ||
154 | #include <linux/module.h> | ||
155 | #include <linux/errno.h> | ||
156 | #include <linux/signal.h> | ||
157 | #include <linux/sched.h> | ||
158 | #include <linux/timer.h> | ||
159 | #include <linux/fs.h> | ||
160 | #include <linux/kernel.h> | ||
161 | #include <linux/hdreg.h> | ||
162 | #include <linux/genhd.h> | ||
163 | #include <linux/ioport.h> | ||
164 | #include <linux/devfs_fs_kernel.h> | ||
165 | #include <linux/string.h> | ||
166 | #include <linux/slab.h> | ||
167 | #include <linux/init.h> | ||
168 | #include <linux/interrupt.h> | ||
169 | #include <linux/cdrom.h> | ||
170 | |||
171 | #include <asm/system.h> | ||
172 | #include <asm/io.h> | ||
173 | #include <asm/uaccess.h> | ||
174 | #include <asm/dma.h> | ||
175 | |||
176 | #include "cdu31a.h" | ||
177 | |||
178 | #define MAJOR_NR CDU31A_CDROM_MAJOR | ||
179 | #include <linux/blkdev.h> | ||
180 | |||
181 | #define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10 | ||
182 | |||
183 | #define PFX "CDU31A: " | ||
184 | |||
185 | /* | ||
186 | ** Edit the following data to change interrupts, DMA channels, etc. | ||
187 | ** Default is polled and no DMA. DMA is not recommended for double-speed | ||
188 | ** drives. | ||
189 | */ | ||
190 | static struct { | ||
191 | unsigned short base; /* I/O Base Address */ | ||
192 | short int_num; /* Interrupt Number (-1 means scan for it, | ||
193 | 0 means don't use) */ | ||
194 | } cdu31a_addresses[] __initdata = { | ||
195 | {0} | ||
196 | }; | ||
197 | |||
198 | static int handle_sony_cd_attention(void); | ||
199 | static int read_subcode(void); | ||
200 | static void sony_get_toc(void); | ||
201 | static int scd_spinup(void); | ||
202 | /*static int scd_open(struct inode *inode, struct file *filp);*/ | ||
203 | static int scd_open(struct cdrom_device_info *, int); | ||
204 | static void do_sony_cd_cmd(unsigned char cmd, | ||
205 | unsigned char *params, | ||
206 | unsigned int num_params, | ||
207 | unsigned char *result_buffer, | ||
208 | unsigned int *result_size); | ||
209 | static void size_to_buf(unsigned int size, unsigned char *buf); | ||
210 | |||
211 | /* Parameters for the read-ahead. */ | ||
212 | static unsigned int sony_next_block; /* Next 512 byte block offset */ | ||
213 | static unsigned int sony_blocks_left = 0; /* Number of 512 byte blocks left | ||
214 | in the current read command. */ | ||
215 | |||
216 | |||
217 | /* The base I/O address of the Sony Interface. This is a variable (not a | ||
218 | #define) so it can be easily changed via some future ioctl() */ | ||
219 | static unsigned int cdu31a_port = 0; | ||
220 | module_param(cdu31a_port, uint, 0); | ||
221 | |||
222 | /* | ||
223 | * The following are I/O addresses of the various registers for the drive. The | ||
224 | * comment for the base address also applies here. | ||
225 | */ | ||
226 | static volatile unsigned short sony_cd_cmd_reg; | ||
227 | static volatile unsigned short sony_cd_param_reg; | ||
228 | static volatile unsigned short sony_cd_write_reg; | ||
229 | static volatile unsigned short sony_cd_control_reg; | ||
230 | static volatile unsigned short sony_cd_status_reg; | ||
231 | static volatile unsigned short sony_cd_result_reg; | ||
232 | static volatile unsigned short sony_cd_read_reg; | ||
233 | static volatile unsigned short sony_cd_fifost_reg; | ||
234 | |||
235 | static struct request_queue *cdu31a_queue; | ||
236 | static DEFINE_SPINLOCK(cdu31a_lock); /* queue lock */ | ||
237 | |||
238 | static int sony_spun_up = 0; /* Has the drive been spun up? */ | ||
239 | |||
240 | static int sony_speed = 0; /* Last wanted speed */ | ||
241 | |||
242 | static int sony_xa_mode = 0; /* Is an XA disk in the drive | ||
243 | and the drive a CDU31A? */ | ||
244 | |||
245 | static int sony_raw_data_mode = 1; /* 1 if data tracks, 0 if audio. | ||
246 | For raw data reads. */ | ||
247 | |||
248 | static unsigned int sony_usage = 0; /* How many processes have the | ||
249 | drive open. */ | ||
250 | |||
251 | static int sony_pas_init = 0; /* Initialize the Pro-Audio | ||
252 | Spectrum card? */ | ||
253 | |||
254 | static struct s_sony_session_toc single_toc; /* Holds the | ||
255 | table of | ||
256 | contents. */ | ||
257 | |||
258 | static struct s_all_sessions_toc sony_toc; /* entries gathered from all | ||
259 | sessions */ | ||
260 | |||
261 | static int sony_toc_read = 0; /* Has the TOC been read for | ||
262 | the drive? */ | ||
263 | |||
264 | static struct s_sony_subcode last_sony_subcode; /* Points to the last | ||
265 | subcode address read */ | ||
266 | |||
267 | static DECLARE_MUTEX(sony_sem); /* Semaphore for drive hardware access */ | ||
268 | |||
269 | static int is_double_speed = 0; /* does the drive support double speed ? */ | ||
270 | |||
271 | static int is_auto_eject = 1; /* Door has been locked? 1=No/0=Yes */ | ||
272 | |||
273 | /* | ||
274 | * The audio status uses the values from read subchannel data as specified | ||
275 | * in include/linux/cdrom.h. | ||
276 | */ | ||
277 | static volatile int sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
278 | |||
279 | /* | ||
280 | * The following are a hack for pausing and resuming audio play. The drive | ||
281 | * does not work as I would expect it, if you stop it then start it again, | ||
282 | * the drive seeks back to the beginning and starts over. This holds the | ||
283 | * position during a pause so a resume can restart it. It uses the | ||
284 | * audio status variable above to tell if it is paused. | ||
285 | */ | ||
286 | static unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 }; | ||
287 | static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 }; | ||
288 | |||
289 | /* What IRQ is the drive using? 0 if none. */ | ||
290 | static int cdu31a_irq = 0; | ||
291 | module_param(cdu31a_irq, int, 0); | ||
292 | |||
293 | /* The interrupt handler will wake this queue up when it gets an | ||
294 | interrupts. */ | ||
295 | DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait); | ||
296 | static int irq_flag = 0; | ||
297 | |||
298 | static int curr_control_reg = 0; /* Current value of the control register */ | ||
299 | |||
300 | /* A disk changed variable. When a disk change is detected, it will | ||
301 | all be set to TRUE. As the upper layers ask for disk_changed status | ||
302 | it will be cleared. */ | ||
303 | static char disk_changed; | ||
304 | |||
305 | /* This was readahead_buffer once... Now it's used only for audio reads */ | ||
306 | static char audio_buffer[CD_FRAMESIZE_RAW]; | ||
307 | |||
308 | /* Used to time a short period to abort an operation after the | ||
309 | drive has been idle for a while. This keeps the light on | ||
310 | the drive from flashing for very long. */ | ||
311 | static struct timer_list cdu31a_abort_timer; | ||
312 | |||
313 | /* Marks if the timeout has started an abort read. This is used | ||
314 | on entry to the drive to tell the code to read out the status | ||
315 | from the abort read. */ | ||
316 | static int abort_read_started = 0; | ||
317 | |||
318 | /* | ||
319 | * Uniform cdrom interface function | ||
320 | * report back, if disc has changed from time of last request. | ||
321 | */ | ||
322 | static int scd_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
323 | { | ||
324 | int retval; | ||
325 | |||
326 | retval = disk_changed; | ||
327 | disk_changed = 0; | ||
328 | |||
329 | return retval; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Uniform cdrom interface function | ||
334 | * report back, if drive is ready | ||
335 | */ | ||
336 | static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
337 | { | ||
338 | if (CDSL_CURRENT != slot_nr) | ||
339 | /* we have no changer support */ | ||
340 | return -EINVAL; | ||
341 | if (sony_spun_up) | ||
342 | return CDS_DISC_OK; | ||
343 | if (down_interruptible(&sony_sem)) | ||
344 | return -ERESTARTSYS; | ||
345 | if (scd_spinup() == 0) | ||
346 | sony_spun_up = 1; | ||
347 | up(&sony_sem); | ||
348 | return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; | ||
349 | } | ||
350 | |||
351 | static inline void enable_interrupts(void) | ||
352 | { | ||
353 | curr_control_reg |= (SONY_ATTN_INT_EN_BIT | ||
354 | | SONY_RES_RDY_INT_EN_BIT | ||
355 | | SONY_DATA_RDY_INT_EN_BIT); | ||
356 | outb(curr_control_reg, sony_cd_control_reg); | ||
357 | } | ||
358 | |||
359 | static inline void disable_interrupts(void) | ||
360 | { | ||
361 | curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT | ||
362 | | SONY_RES_RDY_INT_EN_BIT | ||
363 | | SONY_DATA_RDY_INT_EN_BIT); | ||
364 | outb(curr_control_reg, sony_cd_control_reg); | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Wait a little while (used for polling the drive). If in initialization, | ||
369 | * setting a timeout doesn't work, so just loop for a while. | ||
370 | */ | ||
371 | static inline void sony_sleep(void) | ||
372 | { | ||
373 | if (cdu31a_irq <= 0) { | ||
374 | yield(); | ||
375 | } else { /* Interrupt driven */ | ||
376 | DEFINE_WAIT(w); | ||
377 | int first = 1; | ||
378 | |||
379 | while (1) { | ||
380 | prepare_to_wait(&cdu31a_irq_wait, &w, | ||
381 | TASK_INTERRUPTIBLE); | ||
382 | if (first) { | ||
383 | enable_interrupts(); | ||
384 | first = 0; | ||
385 | } | ||
386 | |||
387 | if (irq_flag != 0) | ||
388 | break; | ||
389 | if (!signal_pending(current)) { | ||
390 | schedule(); | ||
391 | continue; | ||
392 | } else | ||
393 | disable_interrupts(); | ||
394 | break; | ||
395 | } | ||
396 | finish_wait(&cdu31a_irq_wait, &w); | ||
397 | irq_flag = 0; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | |||
402 | /* | ||
403 | * The following are convenience routine to read various status and set | ||
404 | * various conditions in the drive. | ||
405 | */ | ||
406 | static inline int is_attention(void) | ||
407 | { | ||
408 | return (inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0; | ||
409 | } | ||
410 | |||
411 | static inline int is_busy(void) | ||
412 | { | ||
413 | return (inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0; | ||
414 | } | ||
415 | |||
416 | static inline int is_data_ready(void) | ||
417 | { | ||
418 | return (inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0; | ||
419 | } | ||
420 | |||
421 | static inline int is_data_requested(void) | ||
422 | { | ||
423 | return (inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0; | ||
424 | } | ||
425 | |||
426 | static inline int is_result_ready(void) | ||
427 | { | ||
428 | return (inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0; | ||
429 | } | ||
430 | |||
431 | static inline int is_param_write_rdy(void) | ||
432 | { | ||
433 | return (inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0; | ||
434 | } | ||
435 | |||
436 | static inline int is_result_reg_not_empty(void) | ||
437 | { | ||
438 | return (inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0; | ||
439 | } | ||
440 | |||
441 | static inline void reset_drive(void) | ||
442 | { | ||
443 | curr_control_reg = 0; | ||
444 | sony_toc_read = 0; | ||
445 | outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg); | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * Uniform cdrom interface function | ||
450 | * reset drive and return when it is ready | ||
451 | */ | ||
452 | static int scd_reset(struct cdrom_device_info *cdi) | ||
453 | { | ||
454 | unsigned long retry_count; | ||
455 | |||
456 | if (down_interruptible(&sony_sem)) | ||
457 | return -ERESTARTSYS; | ||
458 | reset_drive(); | ||
459 | |||
460 | retry_count = jiffies + SONY_RESET_TIMEOUT; | ||
461 | while (time_before(jiffies, retry_count) && (!is_attention())) { | ||
462 | sony_sleep(); | ||
463 | } | ||
464 | |||
465 | up(&sony_sem); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static inline void clear_attention(void) | ||
470 | { | ||
471 | outb(curr_control_reg | SONY_ATTN_CLR_BIT, sony_cd_control_reg); | ||
472 | } | ||
473 | |||
474 | static inline void clear_result_ready(void) | ||
475 | { | ||
476 | outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg); | ||
477 | } | ||
478 | |||
479 | static inline void clear_data_ready(void) | ||
480 | { | ||
481 | outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT, | ||
482 | sony_cd_control_reg); | ||
483 | } | ||
484 | |||
485 | static inline void clear_param_reg(void) | ||
486 | { | ||
487 | outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg); | ||
488 | } | ||
489 | |||
490 | static inline unsigned char read_status_register(void) | ||
491 | { | ||
492 | return inb(sony_cd_status_reg); | ||
493 | } | ||
494 | |||
495 | static inline unsigned char read_result_register(void) | ||
496 | { | ||
497 | return inb(sony_cd_result_reg); | ||
498 | } | ||
499 | |||
500 | static inline unsigned char read_data_register(void) | ||
501 | { | ||
502 | return inb(sony_cd_read_reg); | ||
503 | } | ||
504 | |||
505 | static inline void write_param(unsigned char param) | ||
506 | { | ||
507 | outb(param, sony_cd_param_reg); | ||
508 | } | ||
509 | |||
510 | static inline void write_cmd(unsigned char cmd) | ||
511 | { | ||
512 | outb(curr_control_reg | SONY_RES_RDY_INT_EN_BIT, | ||
513 | sony_cd_control_reg); | ||
514 | outb(cmd, sony_cd_cmd_reg); | ||
515 | } | ||
516 | |||
517 | static irqreturn_t cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
518 | { | ||
519 | unsigned char val; | ||
520 | |||
521 | if (abort_read_started) { | ||
522 | /* We might be waiting for an abort to finish. Don't | ||
523 | disable interrupts yet, though, because we handle | ||
524 | this one here. */ | ||
525 | /* Clear out the result registers. */ | ||
526 | while (is_result_reg_not_empty()) { | ||
527 | val = read_result_register(); | ||
528 | } | ||
529 | clear_data_ready(); | ||
530 | clear_result_ready(); | ||
531 | |||
532 | /* Clear out the data */ | ||
533 | while (is_data_requested()) { | ||
534 | val = read_data_register(); | ||
535 | } | ||
536 | abort_read_started = 0; | ||
537 | |||
538 | /* If something was waiting, wake it up now. */ | ||
539 | if (waitqueue_active(&cdu31a_irq_wait)) { | ||
540 | disable_interrupts(); | ||
541 | irq_flag = 1; | ||
542 | wake_up_interruptible(&cdu31a_irq_wait); | ||
543 | } | ||
544 | } else if (waitqueue_active(&cdu31a_irq_wait)) { | ||
545 | disable_interrupts(); | ||
546 | irq_flag = 1; | ||
547 | wake_up_interruptible(&cdu31a_irq_wait); | ||
548 | } else { | ||
549 | disable_interrupts(); | ||
550 | printk(KERN_NOTICE PFX | ||
551 | "Got an interrupt but nothing was waiting\n"); | ||
552 | } | ||
553 | return IRQ_HANDLED; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * give more verbose error messages | ||
558 | */ | ||
559 | static unsigned char *translate_error(unsigned char err_code) | ||
560 | { | ||
561 | static unsigned char errbuf[80]; | ||
562 | |||
563 | switch (err_code) { | ||
564 | case 0x10: return "illegal command "; | ||
565 | case 0x11: return "illegal parameter "; | ||
566 | |||
567 | case 0x20: return "not loaded "; | ||
568 | case 0x21: return "no disc "; | ||
569 | case 0x22: return "not spinning "; | ||
570 | case 0x23: return "spinning "; | ||
571 | case 0x25: return "spindle servo "; | ||
572 | case 0x26: return "focus servo "; | ||
573 | case 0x29: return "eject mechanism "; | ||
574 | case 0x2a: return "audio playing "; | ||
575 | case 0x2c: return "emergency eject "; | ||
576 | |||
577 | case 0x30: return "focus "; | ||
578 | case 0x31: return "frame sync "; | ||
579 | case 0x32: return "subcode address "; | ||
580 | case 0x33: return "block sync "; | ||
581 | case 0x34: return "header address "; | ||
582 | |||
583 | case 0x40: return "illegal track read "; | ||
584 | case 0x41: return "mode 0 read "; | ||
585 | case 0x42: return "illegal mode read "; | ||
586 | case 0x43: return "illegal block size read "; | ||
587 | case 0x44: return "mode read "; | ||
588 | case 0x45: return "form read "; | ||
589 | case 0x46: return "leadout read "; | ||
590 | case 0x47: return "buffer overrun "; | ||
591 | |||
592 | case 0x53: return "unrecoverable CIRC "; | ||
593 | case 0x57: return "unrecoverable LECC "; | ||
594 | |||
595 | case 0x60: return "no TOC "; | ||
596 | case 0x61: return "invalid subcode data "; | ||
597 | case 0x63: return "focus on TOC read "; | ||
598 | case 0x64: return "frame sync on TOC read "; | ||
599 | case 0x65: return "TOC data "; | ||
600 | |||
601 | case 0x70: return "hardware failure "; | ||
602 | case 0x91: return "leadin "; | ||
603 | case 0x92: return "leadout "; | ||
604 | case 0x93: return "data track "; | ||
605 | } | ||
606 | sprintf(errbuf, "unknown 0x%02x ", err_code); | ||
607 | return errbuf; | ||
608 | } | ||
609 | |||
610 | /* | ||
611 | * Set the drive parameters so the drive will auto-spin-up when a | ||
612 | * disk is inserted. | ||
613 | */ | ||
614 | static void set_drive_params(int want_doublespeed) | ||
615 | { | ||
616 | unsigned char res_reg[12]; | ||
617 | unsigned int res_size; | ||
618 | unsigned char params[3]; | ||
619 | |||
620 | |||
621 | params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME; | ||
622 | params[1] = 0x00; /* Never spin down the drive. */ | ||
623 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
624 | params, 2, res_reg, &res_size); | ||
625 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
626 | printk(KERN_NOTICE PFX | ||
627 | "Unable to set spin-down time: 0x%2.2x\n", res_reg[1]); | ||
628 | } | ||
629 | |||
630 | params[0] = SONY_SD_MECH_CONTROL; | ||
631 | params[1] = SONY_AUTO_SPIN_UP_BIT; /* Set auto spin up */ | ||
632 | |||
633 | if (is_auto_eject) | ||
634 | params[1] |= SONY_AUTO_EJECT_BIT; | ||
635 | |||
636 | if (is_double_speed && want_doublespeed) { | ||
637 | params[1] |= SONY_DOUBLE_SPEED_BIT; /* Set the drive to double speed if | ||
638 | possible */ | ||
639 | } | ||
640 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
641 | params, 2, res_reg, &res_size); | ||
642 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
643 | printk(KERN_NOTICE PFX "Unable to set mechanical " | ||
644 | "parameters: 0x%2.2x\n", res_reg[1]); | ||
645 | } | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * Uniform cdrom interface function | ||
650 | * select reading speed for data access | ||
651 | */ | ||
652 | static int scd_select_speed(struct cdrom_device_info *cdi, int speed) | ||
653 | { | ||
654 | if (speed == 0) | ||
655 | sony_speed = 1; | ||
656 | else | ||
657 | sony_speed = speed - 1; | ||
658 | |||
659 | if (down_interruptible(&sony_sem)) | ||
660 | return -ERESTARTSYS; | ||
661 | set_drive_params(sony_speed); | ||
662 | up(&sony_sem); | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * Uniform cdrom interface function | ||
668 | * lock or unlock eject button | ||
669 | */ | ||
670 | static int scd_lock_door(struct cdrom_device_info *cdi, int lock) | ||
671 | { | ||
672 | if (lock == 0) { | ||
673 | is_auto_eject = 1; | ||
674 | } else { | ||
675 | is_auto_eject = 0; | ||
676 | } | ||
677 | if (down_interruptible(&sony_sem)) | ||
678 | return -ERESTARTSYS; | ||
679 | set_drive_params(sony_speed); | ||
680 | up(&sony_sem); | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* | ||
685 | * This code will reset the drive and attempt to restore sane parameters. | ||
686 | */ | ||
687 | static void restart_on_error(void) | ||
688 | { | ||
689 | unsigned char res_reg[12]; | ||
690 | unsigned int res_size; | ||
691 | unsigned long retry_count; | ||
692 | |||
693 | |||
694 | printk(KERN_NOTICE PFX "Resetting drive on error\n"); | ||
695 | reset_drive(); | ||
696 | retry_count = jiffies + SONY_RESET_TIMEOUT; | ||
697 | while (time_before(jiffies, retry_count) && (!is_attention())) { | ||
698 | sony_sleep(); | ||
699 | } | ||
700 | set_drive_params(sony_speed); | ||
701 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); | ||
702 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
703 | printk(KERN_NOTICE PFX "Unable to spin up drive: 0x%2.2x\n", | ||
704 | res_reg[1]); | ||
705 | } | ||
706 | |||
707 | msleep(2000); | ||
708 | |||
709 | sony_get_toc(); | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * This routine writes data to the parameter register. Since this should | ||
714 | * happen fairly fast, it is polled with no OS waits between. | ||
715 | */ | ||
716 | static int write_params(unsigned char *params, int num_params) | ||
717 | { | ||
718 | unsigned int retry_count; | ||
719 | |||
720 | |||
721 | retry_count = SONY_READY_RETRIES; | ||
722 | while ((retry_count > 0) && (!is_param_write_rdy())) { | ||
723 | retry_count--; | ||
724 | } | ||
725 | if (!is_param_write_rdy()) { | ||
726 | return -EIO; | ||
727 | } | ||
728 | |||
729 | while (num_params > 0) { | ||
730 | write_param(*params); | ||
731 | params++; | ||
732 | num_params--; | ||
733 | } | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | |||
739 | /* | ||
740 | * The following reads data from the command result register. It is a | ||
741 | * fairly complex routine, all status info flows back through this | ||
742 | * interface. The algorithm is stolen directly from the flowcharts in | ||
743 | * the drive manual. | ||
744 | */ | ||
745 | static void | ||
746 | get_result(unsigned char *result_buffer, unsigned int *result_size) | ||
747 | { | ||
748 | unsigned char a, b; | ||
749 | int i; | ||
750 | unsigned long retry_count; | ||
751 | |||
752 | |||
753 | while (handle_sony_cd_attention()); | ||
754 | /* Wait for the result data to be ready */ | ||
755 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
756 | while (time_before(jiffies, retry_count) | ||
757 | && (is_busy() || (!(is_result_ready())))) { | ||
758 | sony_sleep(); | ||
759 | |||
760 | while (handle_sony_cd_attention()); | ||
761 | } | ||
762 | if (is_busy() || (!(is_result_ready()))) { | ||
763 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
764 | result_buffer[0] = 0x20; | ||
765 | result_buffer[1] = SONY_TIMEOUT_OP_ERR; | ||
766 | *result_size = 2; | ||
767 | return; | ||
768 | } | ||
769 | |||
770 | /* | ||
771 | * Get the first two bytes. This determines what else needs | ||
772 | * to be done. | ||
773 | */ | ||
774 | clear_result_ready(); | ||
775 | a = read_result_register(); | ||
776 | *result_buffer = a; | ||
777 | result_buffer++; | ||
778 | |||
779 | /* Check for block error status result. */ | ||
780 | if ((a & 0xf0) == 0x50) { | ||
781 | *result_size = 1; | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | b = read_result_register(); | ||
786 | *result_buffer = b; | ||
787 | result_buffer++; | ||
788 | *result_size = 2; | ||
789 | |||
790 | /* | ||
791 | * 0x20 means an error occurred. Byte 2 will have the error code. | ||
792 | * Otherwise, the command succeeded, byte 2 will have the count of | ||
793 | * how many more status bytes are coming. | ||
794 | * | ||
795 | * The result register can be read 10 bytes at a time, a wait for | ||
796 | * result ready to be asserted must be done between every 10 bytes. | ||
797 | */ | ||
798 | if ((a & 0xf0) != 0x20) { | ||
799 | if (b > 8) { | ||
800 | for (i = 0; i < 8; i++) { | ||
801 | *result_buffer = read_result_register(); | ||
802 | result_buffer++; | ||
803 | (*result_size)++; | ||
804 | } | ||
805 | b = b - 8; | ||
806 | |||
807 | while (b > 10) { | ||
808 | retry_count = SONY_READY_RETRIES; | ||
809 | while ((retry_count > 0) | ||
810 | && (!is_result_ready())) { | ||
811 | retry_count--; | ||
812 | } | ||
813 | if (!is_result_ready()) { | ||
814 | pr_debug(PFX "timeout out %d\n", | ||
815 | __LINE__); | ||
816 | result_buffer[0] = 0x20; | ||
817 | result_buffer[1] = | ||
818 | SONY_TIMEOUT_OP_ERR; | ||
819 | *result_size = 2; | ||
820 | return; | ||
821 | } | ||
822 | |||
823 | clear_result_ready(); | ||
824 | |||
825 | for (i = 0; i < 10; i++) { | ||
826 | *result_buffer = | ||
827 | read_result_register(); | ||
828 | result_buffer++; | ||
829 | (*result_size)++; | ||
830 | } | ||
831 | b = b - 10; | ||
832 | } | ||
833 | |||
834 | if (b > 0) { | ||
835 | retry_count = SONY_READY_RETRIES; | ||
836 | while ((retry_count > 0) | ||
837 | && (!is_result_ready())) { | ||
838 | retry_count--; | ||
839 | } | ||
840 | if (!is_result_ready()) { | ||
841 | pr_debug(PFX "timeout out %d\n", | ||
842 | __LINE__); | ||
843 | result_buffer[0] = 0x20; | ||
844 | result_buffer[1] = | ||
845 | SONY_TIMEOUT_OP_ERR; | ||
846 | *result_size = 2; | ||
847 | return; | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | |||
852 | while (b > 0) { | ||
853 | *result_buffer = read_result_register(); | ||
854 | result_buffer++; | ||
855 | (*result_size)++; | ||
856 | b--; | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | * Do a command that does not involve data transfer. This routine must | ||
863 | * be re-entrant from the same task to support being called from the | ||
864 | * data operation code when an error occurs. | ||
865 | */ | ||
866 | static void | ||
867 | do_sony_cd_cmd(unsigned char cmd, | ||
868 | unsigned char *params, | ||
869 | unsigned int num_params, | ||
870 | unsigned char *result_buffer, unsigned int *result_size) | ||
871 | { | ||
872 | unsigned long retry_count; | ||
873 | int num_retries = 0; | ||
874 | |||
875 | retry_cd_operation: | ||
876 | |||
877 | while (handle_sony_cd_attention()); | ||
878 | |||
879 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
880 | while (time_before(jiffies, retry_count) && (is_busy())) { | ||
881 | sony_sleep(); | ||
882 | |||
883 | while (handle_sony_cd_attention()); | ||
884 | } | ||
885 | if (is_busy()) { | ||
886 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
887 | result_buffer[0] = 0x20; | ||
888 | result_buffer[1] = SONY_TIMEOUT_OP_ERR; | ||
889 | *result_size = 2; | ||
890 | } else { | ||
891 | clear_result_ready(); | ||
892 | clear_param_reg(); | ||
893 | |||
894 | write_params(params, num_params); | ||
895 | write_cmd(cmd); | ||
896 | |||
897 | get_result(result_buffer, result_size); | ||
898 | } | ||
899 | |||
900 | if (((result_buffer[0] & 0xf0) == 0x20) | ||
901 | && (num_retries < MAX_CDU31A_RETRIES)) { | ||
902 | num_retries++; | ||
903 | msleep(100); | ||
904 | goto retry_cd_operation; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | |||
909 | /* | ||
910 | * Handle an attention from the drive. This will return 1 if it found one | ||
911 | * or 0 if not (if one is found, the caller might want to call again). | ||
912 | * | ||
913 | * This routine counts the number of consecutive times it is called | ||
914 | * (since this is always called from a while loop until it returns | ||
915 | * a 0), and returns a 0 if it happens too many times. This will help | ||
916 | * prevent a lockup. | ||
917 | */ | ||
918 | static int handle_sony_cd_attention(void) | ||
919 | { | ||
920 | unsigned char atten_code; | ||
921 | static int num_consecutive_attentions = 0; | ||
922 | volatile int val; | ||
923 | |||
924 | |||
925 | #if 0 | ||
926 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
927 | #endif | ||
928 | if (is_attention()) { | ||
929 | if (num_consecutive_attentions > | ||
930 | CDU31A_MAX_CONSECUTIVE_ATTENTIONS) { | ||
931 | printk(KERN_NOTICE PFX "Too many consecutive " | ||
932 | "attentions: %d\n", num_consecutive_attentions); | ||
933 | num_consecutive_attentions = 0; | ||
934 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, | ||
935 | __LINE__); | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | clear_attention(); | ||
940 | atten_code = read_result_register(); | ||
941 | |||
942 | switch (atten_code) { | ||
943 | /* Someone changed the CD. Mark it as changed */ | ||
944 | case SONY_MECH_LOADED_ATTN: | ||
945 | disk_changed = 1; | ||
946 | sony_toc_read = 0; | ||
947 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
948 | sony_blocks_left = 0; | ||
949 | break; | ||
950 | |||
951 | case SONY_SPIN_DOWN_COMPLETE_ATTN: | ||
952 | /* Mark the disk as spun down. */ | ||
953 | sony_spun_up = 0; | ||
954 | break; | ||
955 | |||
956 | case SONY_AUDIO_PLAY_DONE_ATTN: | ||
957 | sony_audio_status = CDROM_AUDIO_COMPLETED; | ||
958 | read_subcode(); | ||
959 | break; | ||
960 | |||
961 | case SONY_EJECT_PUSHED_ATTN: | ||
962 | if (is_auto_eject) { | ||
963 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
964 | } | ||
965 | break; | ||
966 | |||
967 | case SONY_LEAD_IN_ERR_ATTN: | ||
968 | case SONY_LEAD_OUT_ERR_ATTN: | ||
969 | case SONY_DATA_TRACK_ERR_ATTN: | ||
970 | case SONY_AUDIO_PLAYBACK_ERR_ATTN: | ||
971 | sony_audio_status = CDROM_AUDIO_ERROR; | ||
972 | break; | ||
973 | } | ||
974 | |||
975 | num_consecutive_attentions++; | ||
976 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
977 | return 1; | ||
978 | } else if (abort_read_started) { | ||
979 | while (is_result_reg_not_empty()) { | ||
980 | val = read_result_register(); | ||
981 | } | ||
982 | clear_data_ready(); | ||
983 | clear_result_ready(); | ||
984 | /* Clear out the data */ | ||
985 | while (is_data_requested()) { | ||
986 | val = read_data_register(); | ||
987 | } | ||
988 | abort_read_started = 0; | ||
989 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
990 | return 1; | ||
991 | } | ||
992 | |||
993 | num_consecutive_attentions = 0; | ||
994 | #if 0 | ||
995 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
996 | #endif | ||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | |||
1001 | /* Convert from an integer 0-99 to BCD */ | ||
1002 | static inline unsigned int int_to_bcd(unsigned int val) | ||
1003 | { | ||
1004 | int retval; | ||
1005 | |||
1006 | |||
1007 | retval = (val / 10) << 4; | ||
1008 | retval = retval | val % 10; | ||
1009 | return retval; | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | /* Convert from BCD to an integer from 0-99 */ | ||
1014 | static unsigned int bcd_to_int(unsigned int bcd) | ||
1015 | { | ||
1016 | return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | /* | ||
1021 | * Convert a logical sector value (like the OS would want to use for | ||
1022 | * a block device) to an MSF format. | ||
1023 | */ | ||
1024 | static void log_to_msf(unsigned int log, unsigned char *msf) | ||
1025 | { | ||
1026 | log = log + LOG_START_OFFSET; | ||
1027 | msf[0] = int_to_bcd(log / 4500); | ||
1028 | log = log % 4500; | ||
1029 | msf[1] = int_to_bcd(log / 75); | ||
1030 | msf[2] = int_to_bcd(log % 75); | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | /* | ||
1035 | * Convert an MSF format to a logical sector. | ||
1036 | */ | ||
1037 | static unsigned int msf_to_log(unsigned char *msf) | ||
1038 | { | ||
1039 | unsigned int log; | ||
1040 | |||
1041 | |||
1042 | log = msf[2]; | ||
1043 | log += msf[1] * 75; | ||
1044 | log += msf[0] * 4500; | ||
1045 | log = log - LOG_START_OFFSET; | ||
1046 | |||
1047 | return log; | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /* | ||
1052 | * Take in integer size value and put it into a buffer like | ||
1053 | * the drive would want to see a number-of-sector value. | ||
1054 | */ | ||
1055 | static void size_to_buf(unsigned int size, unsigned char *buf) | ||
1056 | { | ||
1057 | buf[0] = size / 65536; | ||
1058 | size = size % 65536; | ||
1059 | buf[1] = size / 256; | ||
1060 | buf[2] = size % 256; | ||
1061 | } | ||
1062 | |||
1063 | /* Starts a read operation. Returns 0 on success and 1 on failure. | ||
1064 | The read operation used here allows multiple sequential sectors | ||
1065 | to be read and status returned for each sector. The driver will | ||
1066 | read the output one at a time as the requests come and abort the | ||
1067 | operation if the requested sector is not the next one from the | ||
1068 | drive. */ | ||
1069 | static int | ||
1070 | start_request(unsigned int sector, unsigned int nsect) | ||
1071 | { | ||
1072 | unsigned char params[6]; | ||
1073 | unsigned long retry_count; | ||
1074 | |||
1075 | |||
1076 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1077 | log_to_msf(sector, params); | ||
1078 | size_to_buf(nsect, ¶ms[3]); | ||
1079 | |||
1080 | /* | ||
1081 | * Clear any outstanding attentions and wait for the drive to | ||
1082 | * complete any pending operations. | ||
1083 | */ | ||
1084 | while (handle_sony_cd_attention()); | ||
1085 | |||
1086 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
1087 | while (time_before(jiffies, retry_count) && (is_busy())) { | ||
1088 | sony_sleep(); | ||
1089 | |||
1090 | while (handle_sony_cd_attention()); | ||
1091 | } | ||
1092 | |||
1093 | if (is_busy()) { | ||
1094 | printk(KERN_NOTICE PFX "Timeout while waiting " | ||
1095 | "to issue command\n"); | ||
1096 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1097 | return 1; | ||
1098 | } else { | ||
1099 | /* Issue the command */ | ||
1100 | clear_result_ready(); | ||
1101 | clear_param_reg(); | ||
1102 | |||
1103 | write_params(params, 6); | ||
1104 | write_cmd(SONY_READ_BLKERR_STAT_CMD); | ||
1105 | |||
1106 | sony_blocks_left = nsect * 4; | ||
1107 | sony_next_block = sector * 4; | ||
1108 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1112 | } | ||
1113 | |||
1114 | /* Abort a pending read operation. Clear all the drive status variables. */ | ||
1115 | static void abort_read(void) | ||
1116 | { | ||
1117 | unsigned char result_reg[2]; | ||
1118 | int result_size; | ||
1119 | volatile int val; | ||
1120 | |||
1121 | |||
1122 | do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size); | ||
1123 | if ((result_reg[0] & 0xf0) == 0x20) { | ||
1124 | printk(KERN_ERR PFX "Aborting read, %s error\n", | ||
1125 | translate_error(result_reg[1])); | ||
1126 | } | ||
1127 | |||
1128 | while (is_result_reg_not_empty()) { | ||
1129 | val = read_result_register(); | ||
1130 | } | ||
1131 | clear_data_ready(); | ||
1132 | clear_result_ready(); | ||
1133 | /* Clear out the data */ | ||
1134 | while (is_data_requested()) { | ||
1135 | val = read_data_register(); | ||
1136 | } | ||
1137 | |||
1138 | sony_blocks_left = 0; | ||
1139 | } | ||
1140 | |||
1141 | /* Called when the timer times out. This will abort the | ||
1142 | pending read operation. */ | ||
1143 | static void handle_abort_timeout(unsigned long data) | ||
1144 | { | ||
1145 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1146 | /* If it is in use, ignore it. */ | ||
1147 | if (down_trylock(&sony_sem) == 0) { | ||
1148 | /* We can't use abort_read(), because it will sleep | ||
1149 | or schedule in the timer interrupt. Just start | ||
1150 | the operation, finish it on the next access to | ||
1151 | the drive. */ | ||
1152 | clear_result_ready(); | ||
1153 | clear_param_reg(); | ||
1154 | write_cmd(SONY_ABORT_CMD); | ||
1155 | |||
1156 | sony_blocks_left = 0; | ||
1157 | abort_read_started = 1; | ||
1158 | up(&sony_sem); | ||
1159 | } | ||
1160 | pr_debug(PFX "Leaving %s\n", __FUNCTION__); | ||
1161 | } | ||
1162 | |||
1163 | /* Actually get one sector of data from the drive. */ | ||
1164 | static void | ||
1165 | input_data_sector(char *buffer) | ||
1166 | { | ||
1167 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1168 | |||
1169 | /* If an XA disk on a CDU31A, skip the first 12 bytes of data from | ||
1170 | the disk. The real data is after that. We can use audio_buffer. */ | ||
1171 | if (sony_xa_mode) | ||
1172 | insb(sony_cd_read_reg, audio_buffer, CD_XA_HEAD); | ||
1173 | |||
1174 | clear_data_ready(); | ||
1175 | |||
1176 | insb(sony_cd_read_reg, buffer, 2048); | ||
1177 | |||
1178 | /* If an XA disk, we have to clear out the rest of the unused | ||
1179 | error correction data. We can use audio_buffer for that. */ | ||
1180 | if (sony_xa_mode) | ||
1181 | insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL); | ||
1182 | |||
1183 | pr_debug(PFX "Leaving %s\n", __FUNCTION__); | ||
1184 | } | ||
1185 | |||
1186 | /* read data from the drive. Note the nsect must be <= 4. */ | ||
1187 | static void | ||
1188 | read_data_block(char *buffer, | ||
1189 | unsigned int block, | ||
1190 | unsigned int nblocks, | ||
1191 | unsigned char res_reg[], int *res_size) | ||
1192 | { | ||
1193 | unsigned long retry_count; | ||
1194 | |||
1195 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1196 | |||
1197 | res_reg[0] = 0; | ||
1198 | res_reg[1] = 0; | ||
1199 | *res_size = 0; | ||
1200 | |||
1201 | /* Wait for the drive to tell us we have something */ | ||
1202 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
1203 | while (time_before(jiffies, retry_count) && !(is_data_ready())) { | ||
1204 | while (handle_sony_cd_attention()); | ||
1205 | |||
1206 | sony_sleep(); | ||
1207 | } | ||
1208 | if (!(is_data_ready())) { | ||
1209 | if (is_result_ready()) { | ||
1210 | get_result(res_reg, res_size); | ||
1211 | if ((res_reg[0] & 0xf0) != 0x20) { | ||
1212 | printk(KERN_NOTICE PFX "Got result that should" | ||
1213 | " have been error: %d\n", res_reg[0]); | ||
1214 | res_reg[0] = 0x20; | ||
1215 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
1216 | *res_size = 2; | ||
1217 | } | ||
1218 | abort_read(); | ||
1219 | } else { | ||
1220 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
1221 | res_reg[0] = 0x20; | ||
1222 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
1223 | *res_size = 2; | ||
1224 | abort_read(); | ||
1225 | } | ||
1226 | } else { | ||
1227 | input_data_sector(buffer); | ||
1228 | sony_blocks_left -= nblocks; | ||
1229 | sony_next_block += nblocks; | ||
1230 | |||
1231 | /* Wait for the status from the drive. */ | ||
1232 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
1233 | while (time_before(jiffies, retry_count) | ||
1234 | && !(is_result_ready())) { | ||
1235 | while (handle_sony_cd_attention()); | ||
1236 | |||
1237 | sony_sleep(); | ||
1238 | } | ||
1239 | |||
1240 | if (!is_result_ready()) { | ||
1241 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
1242 | res_reg[0] = 0x20; | ||
1243 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
1244 | *res_size = 2; | ||
1245 | abort_read(); | ||
1246 | } else { | ||
1247 | get_result(res_reg, res_size); | ||
1248 | |||
1249 | /* If we got a buffer status, handle that. */ | ||
1250 | if ((res_reg[0] & 0xf0) == 0x50) { | ||
1251 | |||
1252 | if ((res_reg[0] == | ||
1253 | SONY_NO_CIRC_ERR_BLK_STAT) | ||
1254 | || (res_reg[0] == | ||
1255 | SONY_NO_LECC_ERR_BLK_STAT) | ||
1256 | || (res_reg[0] == | ||
1257 | SONY_RECOV_LECC_ERR_BLK_STAT)) { | ||
1258 | /* nothing here */ | ||
1259 | } else { | ||
1260 | printk(KERN_ERR PFX "Data block " | ||
1261 | "error: 0x%x\n", res_reg[0]); | ||
1262 | res_reg[0] = 0x20; | ||
1263 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
1264 | *res_size = 2; | ||
1265 | } | ||
1266 | |||
1267 | /* Final transfer is done for read command, get final result. */ | ||
1268 | if (sony_blocks_left == 0) { | ||
1269 | get_result(res_reg, res_size); | ||
1270 | } | ||
1271 | } else if ((res_reg[0] & 0xf0) != 0x20) { | ||
1272 | /* The drive gave me bad status, I don't know what to do. | ||
1273 | Reset the driver and return an error. */ | ||
1274 | printk(KERN_ERR PFX "Invalid block " | ||
1275 | "status: 0x%x\n", res_reg[0]); | ||
1276 | restart_on_error(); | ||
1277 | res_reg[0] = 0x20; | ||
1278 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
1279 | *res_size = 2; | ||
1280 | } | ||
1281 | } | ||
1282 | } | ||
1283 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1284 | } | ||
1285 | |||
1286 | |||
1287 | /* | ||
1288 | * The OS calls this to perform a read or write operation to the drive. | ||
1289 | * Write obviously fail. Reads to a read ahead of sony_buffer_size | ||
1290 | * bytes to help speed operations. This especially helps since the OS | ||
1291 | * uses 1024 byte blocks and the drive uses 2048 byte blocks. Since most | ||
1292 | * data access on a CD is done sequentially, this saves a lot of operations. | ||
1293 | */ | ||
1294 | static void do_cdu31a_request(request_queue_t * q) | ||
1295 | { | ||
1296 | struct request *req; | ||
1297 | int block, nblock, num_retries; | ||
1298 | unsigned char res_reg[12]; | ||
1299 | unsigned int res_size; | ||
1300 | |||
1301 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1302 | |||
1303 | spin_unlock_irq(q->queue_lock); | ||
1304 | if (down_interruptible(&sony_sem)) { | ||
1305 | spin_lock_irq(q->queue_lock); | ||
1306 | return; | ||
1307 | } | ||
1308 | |||
1309 | /* Get drive status before doing anything. */ | ||
1310 | while (handle_sony_cd_attention()); | ||
1311 | |||
1312 | /* Make sure we have a valid TOC. */ | ||
1313 | sony_get_toc(); | ||
1314 | |||
1315 | |||
1316 | /* Make sure the timer is cancelled. */ | ||
1317 | del_timer(&cdu31a_abort_timer); | ||
1318 | |||
1319 | while (1) { | ||
1320 | /* | ||
1321 | * The beginning here is stolen from the hard disk driver. I hope | ||
1322 | * it's right. | ||
1323 | */ | ||
1324 | req = elv_next_request(q); | ||
1325 | if (!req) | ||
1326 | goto end_do_cdu31a_request; | ||
1327 | |||
1328 | if (!sony_spun_up) | ||
1329 | scd_spinup(); | ||
1330 | |||
1331 | block = req->sector; | ||
1332 | nblock = req->nr_sectors; | ||
1333 | pr_debug(PFX "request at block %d, length %d blocks\n", | ||
1334 | block, nblock); | ||
1335 | if (!sony_toc_read) { | ||
1336 | printk(KERN_NOTICE PFX "TOC not read\n"); | ||
1337 | end_request(req, 0); | ||
1338 | continue; | ||
1339 | } | ||
1340 | |||
1341 | /* WTF??? */ | ||
1342 | if (!(req->flags & REQ_CMD)) | ||
1343 | continue; | ||
1344 | if (rq_data_dir(req) == WRITE) { | ||
1345 | end_request(req, 0); | ||
1346 | continue; | ||
1347 | } | ||
1348 | |||
1349 | /* | ||
1350 | * If the block address is invalid or the request goes beyond the end of | ||
1351 | * the media, return an error. | ||
1352 | */ | ||
1353 | if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { | ||
1354 | printk(KERN_NOTICE PFX "Request past end of media\n"); | ||
1355 | end_request(req, 0); | ||
1356 | continue; | ||
1357 | } | ||
1358 | |||
1359 | if (nblock > 4) | ||
1360 | nblock = 4; | ||
1361 | num_retries = 0; | ||
1362 | |||
1363 | try_read_again: | ||
1364 | while (handle_sony_cd_attention()); | ||
1365 | |||
1366 | if (!sony_toc_read) { | ||
1367 | printk(KERN_NOTICE PFX "TOC not read\n"); | ||
1368 | end_request(req, 0); | ||
1369 | continue; | ||
1370 | } | ||
1371 | |||
1372 | /* If no data is left to be read from the drive, start the | ||
1373 | next request. */ | ||
1374 | if (sony_blocks_left == 0) { | ||
1375 | if (start_request(block / 4, nblock / 4)) { | ||
1376 | end_request(req, 0); | ||
1377 | continue; | ||
1378 | } | ||
1379 | } | ||
1380 | /* If the requested block is not the next one waiting in | ||
1381 | the driver, abort the current operation and start a | ||
1382 | new one. */ | ||
1383 | else if (block != sony_next_block) { | ||
1384 | pr_debug(PFX "Read for block %d, expected %d\n", | ||
1385 | block, sony_next_block); | ||
1386 | abort_read(); | ||
1387 | if (!sony_toc_read) { | ||
1388 | printk(KERN_NOTICE PFX "TOC not read\n"); | ||
1389 | end_request(req, 0); | ||
1390 | continue; | ||
1391 | } | ||
1392 | if (start_request(block / 4, nblock / 4)) { | ||
1393 | printk(KERN_NOTICE PFX "start request failed\n"); | ||
1394 | end_request(req, 0); | ||
1395 | continue; | ||
1396 | } | ||
1397 | } | ||
1398 | |||
1399 | read_data_block(req->buffer, block, nblock, res_reg, &res_size); | ||
1400 | |||
1401 | if (res_reg[0] != 0x20) { | ||
1402 | if (!end_that_request_first(req, 1, nblock)) { | ||
1403 | spin_lock_irq(q->queue_lock); | ||
1404 | blkdev_dequeue_request(req); | ||
1405 | end_that_request_last(req); | ||
1406 | spin_unlock_irq(q->queue_lock); | ||
1407 | } | ||
1408 | continue; | ||
1409 | } | ||
1410 | |||
1411 | if (num_retries > MAX_CDU31A_RETRIES) { | ||
1412 | end_request(req, 0); | ||
1413 | continue; | ||
1414 | } | ||
1415 | |||
1416 | num_retries++; | ||
1417 | if (res_reg[1] == SONY_NOT_SPIN_ERR) { | ||
1418 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
1419 | &res_size); | ||
1420 | } else { | ||
1421 | printk(KERN_NOTICE PFX "%s error for block %d, nblock %d\n", | ||
1422 | translate_error(res_reg[1]), block, nblock); | ||
1423 | } | ||
1424 | goto try_read_again; | ||
1425 | } | ||
1426 | end_do_cdu31a_request: | ||
1427 | #if 0 | ||
1428 | /* After finished, cancel any pending operations. */ | ||
1429 | abort_read(); | ||
1430 | #else | ||
1431 | /* Start a timer to time out after a while to disable | ||
1432 | the read. */ | ||
1433 | cdu31a_abort_timer.expires = jiffies + 2 * HZ; /* Wait 2 seconds */ | ||
1434 | add_timer(&cdu31a_abort_timer); | ||
1435 | #endif | ||
1436 | |||
1437 | up(&sony_sem); | ||
1438 | spin_lock_irq(q->queue_lock); | ||
1439 | pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); | ||
1440 | } | ||
1441 | |||
1442 | |||
1443 | /* | ||
1444 | * Read the table of contents from the drive and set up TOC if | ||
1445 | * successful. | ||
1446 | */ | ||
1447 | static void sony_get_toc(void) | ||
1448 | { | ||
1449 | unsigned char res_reg[2]; | ||
1450 | unsigned int res_size; | ||
1451 | unsigned char parms[1]; | ||
1452 | int session; | ||
1453 | int num_spin_ups; | ||
1454 | int totaltracks = 0; | ||
1455 | int mint = 99; | ||
1456 | int maxt = 0; | ||
1457 | |||
1458 | pr_debug(PFX "Entering %s\n", __FUNCTION__); | ||
1459 | |||
1460 | num_spin_ups = 0; | ||
1461 | if (!sony_toc_read) { | ||
1462 | respinup_on_gettoc: | ||
1463 | /* Ignore the result, since it might error if spinning already. */ | ||
1464 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
1465 | &res_size); | ||
1466 | |||
1467 | do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, | ||
1468 | &res_size); | ||
1469 | |||
1470 | /* The drive sometimes returns error 0. I don't know why, but ignore | ||
1471 | it. It seems to mean the drive has already done the operation. */ | ||
1472 | if ((res_size < 2) | ||
1473 | || ((res_reg[0] != 0) && (res_reg[1] != 0))) { | ||
1474 | /* If the drive is already playing, it's ok. */ | ||
1475 | if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) | ||
1476 | || (res_reg[1] == 0)) { | ||
1477 | goto gettoc_drive_spinning; | ||
1478 | } | ||
1479 | |||
1480 | /* If the drive says it is not spun up (even though we just did it!) | ||
1481 | then retry the operation at least a few times. */ | ||
1482 | if ((res_reg[1] == SONY_NOT_SPIN_ERR) | ||
1483 | && (num_spin_ups < MAX_CDU31A_RETRIES)) { | ||
1484 | num_spin_ups++; | ||
1485 | goto respinup_on_gettoc; | ||
1486 | } | ||
1487 | |||
1488 | printk("cdu31a: Error reading TOC: %x %s\n", | ||
1489 | res_reg[0], translate_error(res_reg[1])); | ||
1490 | return; | ||
1491 | } | ||
1492 | |||
1493 | gettoc_drive_spinning: | ||
1494 | |||
1495 | /* The idea here is we keep asking for sessions until the command | ||
1496 | fails. Then we know what the last valid session on the disk is. | ||
1497 | No need to check session 0, since session 0 is the same as session | ||
1498 | 1; the command returns different information if you give it 0. | ||
1499 | */ | ||
1500 | #if DEBUG | ||
1501 | memset(&sony_toc, 0x0e, sizeof(sony_toc)); | ||
1502 | memset(&single_toc, 0x0f, sizeof(single_toc)); | ||
1503 | #endif | ||
1504 | session = 1; | ||
1505 | while (1) { | ||
1506 | /* This seems to slow things down enough to make it work. This | ||
1507 | * appears to be a problem in do_sony_cd_cmd. This printk seems | ||
1508 | * to address the symptoms... -Erik */ | ||
1509 | pr_debug(PFX "Trying session %d\n", session); | ||
1510 | parms[0] = session; | ||
1511 | do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD, | ||
1512 | parms, 1, res_reg, &res_size); | ||
1513 | |||
1514 | pr_debug(PFX "%2.2x %2.2x\n", res_reg[0], res_reg[1]); | ||
1515 | |||
1516 | if ((res_size < 2) | ||
1517 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
1518 | /* An error reading the TOC, this must be past the last session. */ | ||
1519 | if (session == 1) | ||
1520 | printk | ||
1521 | ("Yikes! Couldn't read any sessions!"); | ||
1522 | break; | ||
1523 | } | ||
1524 | pr_debug(PFX "Reading session %d\n", session); | ||
1525 | |||
1526 | parms[0] = session; | ||
1527 | do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD, | ||
1528 | parms, | ||
1529 | 1, | ||
1530 | (unsigned char *) &single_toc, | ||
1531 | &res_size); | ||
1532 | if ((res_size < 2) | ||
1533 | || ((single_toc.exec_status[0] & 0xf0) == | ||
1534 | 0x20)) { | ||
1535 | printk(KERN_ERR PFX "Error reading " | ||
1536 | "session %d: %x %s\n", | ||
1537 | session, single_toc.exec_status[0], | ||
1538 | translate_error(single_toc. | ||
1539 | exec_status[1])); | ||
1540 | /* An error reading the TOC. Return without sony_toc_read | ||
1541 | set. */ | ||
1542 | return; | ||
1543 | } | ||
1544 | pr_debug(PFX "add0 %01x, con0 %01x, poi0 %02x, " | ||
1545 | "1st trk %d, dsktyp %x, dum0 %x\n", | ||
1546 | single_toc.address0, single_toc.control0, | ||
1547 | single_toc.point0, | ||
1548 | bcd_to_int(single_toc.first_track_num), | ||
1549 | single_toc.disk_type, single_toc.dummy0); | ||
1550 | pr_debug(PFX "add1 %01x, con1 %01x, poi1 %02x, " | ||
1551 | "lst trk %d, dummy1 %x, dum2 %x\n", | ||
1552 | single_toc.address1, single_toc.control1, | ||
1553 | single_toc.point1, | ||
1554 | bcd_to_int(single_toc.last_track_num), | ||
1555 | single_toc.dummy1, single_toc.dummy2); | ||
1556 | pr_debug(PFX "add2 %01x, con2 %01x, poi2 %02x " | ||
1557 | "leadout start min %d, sec %d, frame %d\n", | ||
1558 | single_toc.address2, single_toc.control2, | ||
1559 | single_toc.point2, | ||
1560 | bcd_to_int(single_toc.lead_out_start_msf[0]), | ||
1561 | bcd_to_int(single_toc.lead_out_start_msf[1]), | ||
1562 | bcd_to_int(single_toc.lead_out_start_msf[2])); | ||
1563 | if (res_size > 18 && single_toc.pointb0 > 0xaf) | ||
1564 | pr_debug(PFX "addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n" | ||
1565 | "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n", | ||
1566 | single_toc.addressb0, | ||
1567 | single_toc.controlb0, | ||
1568 | single_toc.pointb0, | ||
1569 | bcd_to_int(single_toc. | ||
1570 | next_poss_prog_area_msf | ||
1571 | [0]), | ||
1572 | bcd_to_int(single_toc. | ||
1573 | next_poss_prog_area_msf | ||
1574 | [1]), | ||
1575 | bcd_to_int(single_toc. | ||
1576 | next_poss_prog_area_msf | ||
1577 | [2]), | ||
1578 | single_toc.num_mode_5_pointers, | ||
1579 | bcd_to_int(single_toc. | ||
1580 | max_start_outer_leadout_msf | ||
1581 | [0]), | ||
1582 | bcd_to_int(single_toc. | ||
1583 | max_start_outer_leadout_msf | ||
1584 | [1]), | ||
1585 | bcd_to_int(single_toc. | ||
1586 | max_start_outer_leadout_msf | ||
1587 | [2])); | ||
1588 | if (res_size > 27 && single_toc.pointb1 > 0xaf) | ||
1589 | pr_debug(PFX "addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n", | ||
1590 | single_toc.addressb1, | ||
1591 | single_toc.controlb1, | ||
1592 | single_toc.pointb1, | ||
1593 | single_toc.dummyb0_1[0], | ||
1594 | single_toc.dummyb0_1[1], | ||
1595 | single_toc.dummyb0_1[2], | ||
1596 | single_toc.dummyb0_1[3], | ||
1597 | single_toc.num_skip_interval_pointers, | ||
1598 | single_toc.num_skip_track_assignments, | ||
1599 | single_toc.dummyb0_2); | ||
1600 | if (res_size > 36 && single_toc.pointb2 > 0xaf) | ||
1601 | pr_debug(PFX "addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1602 | single_toc.addressb2, | ||
1603 | single_toc.controlb2, | ||
1604 | single_toc.pointb2, | ||
1605 | single_toc.tracksb2[0], | ||
1606 | single_toc.tracksb2[1], | ||
1607 | single_toc.tracksb2[2], | ||
1608 | single_toc.tracksb2[3], | ||
1609 | single_toc.tracksb2[4], | ||
1610 | single_toc.tracksb2[5], | ||
1611 | single_toc.tracksb2[6]); | ||
1612 | if (res_size > 45 && single_toc.pointb3 > 0xaf) | ||
1613 | pr_debug(PFX "addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1614 | single_toc.addressb3, | ||
1615 | single_toc.controlb3, | ||
1616 | single_toc.pointb3, | ||
1617 | single_toc.tracksb3[0], | ||
1618 | single_toc.tracksb3[1], | ||
1619 | single_toc.tracksb3[2], | ||
1620 | single_toc.tracksb3[3], | ||
1621 | single_toc.tracksb3[4], | ||
1622 | single_toc.tracksb3[5], | ||
1623 | single_toc.tracksb3[6]); | ||
1624 | if (res_size > 54 && single_toc.pointb4 > 0xaf) | ||
1625 | pr_debug(PFX "addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1626 | single_toc.addressb4, | ||
1627 | single_toc.controlb4, | ||
1628 | single_toc.pointb4, | ||
1629 | single_toc.tracksb4[0], | ||
1630 | single_toc.tracksb4[1], | ||
1631 | single_toc.tracksb4[2], | ||
1632 | single_toc.tracksb4[3], | ||
1633 | single_toc.tracksb4[4], | ||
1634 | single_toc.tracksb4[5], | ||
1635 | single_toc.tracksb4[6]); | ||
1636 | if (res_size > 63 && single_toc.pointc0 > 0xaf) | ||
1637 | pr_debug(PFX "addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n", | ||
1638 | single_toc.addressc0, | ||
1639 | single_toc.controlc0, | ||
1640 | single_toc.pointc0, | ||
1641 | single_toc.dummyc0[0], | ||
1642 | single_toc.dummyc0[1], | ||
1643 | single_toc.dummyc0[2], | ||
1644 | single_toc.dummyc0[3], | ||
1645 | single_toc.dummyc0[4], | ||
1646 | single_toc.dummyc0[5], | ||
1647 | single_toc.dummyc0[6]); | ||
1648 | #undef DEBUG | ||
1649 | #define DEBUG 0 | ||
1650 | |||
1651 | sony_toc.lead_out_start_msf[0] = | ||
1652 | bcd_to_int(single_toc.lead_out_start_msf[0]); | ||
1653 | sony_toc.lead_out_start_msf[1] = | ||
1654 | bcd_to_int(single_toc.lead_out_start_msf[1]); | ||
1655 | sony_toc.lead_out_start_msf[2] = | ||
1656 | bcd_to_int(single_toc.lead_out_start_msf[2]); | ||
1657 | sony_toc.lead_out_start_lba = | ||
1658 | single_toc.lead_out_start_lba = | ||
1659 | msf_to_log(sony_toc.lead_out_start_msf); | ||
1660 | |||
1661 | /* For points that do not exist, move the data over them | ||
1662 | to the right location. */ | ||
1663 | if (single_toc.pointb0 != 0xb0) { | ||
1664 | memmove(((char *) &single_toc) + 27, | ||
1665 | ((char *) &single_toc) + 18, | ||
1666 | res_size - 18); | ||
1667 | res_size += 9; | ||
1668 | } else if (res_size > 18) { | ||
1669 | sony_toc.lead_out_start_msf[0] = | ||
1670 | bcd_to_int(single_toc. | ||
1671 | max_start_outer_leadout_msf | ||
1672 | [0]); | ||
1673 | sony_toc.lead_out_start_msf[1] = | ||
1674 | bcd_to_int(single_toc. | ||
1675 | max_start_outer_leadout_msf | ||
1676 | [1]); | ||
1677 | sony_toc.lead_out_start_msf[2] = | ||
1678 | bcd_to_int(single_toc. | ||
1679 | max_start_outer_leadout_msf | ||
1680 | [2]); | ||
1681 | sony_toc.lead_out_start_lba = | ||
1682 | msf_to_log(sony_toc. | ||
1683 | lead_out_start_msf); | ||
1684 | } | ||
1685 | if (single_toc.pointb1 != 0xb1) { | ||
1686 | memmove(((char *) &single_toc) + 36, | ||
1687 | ((char *) &single_toc) + 27, | ||
1688 | res_size - 27); | ||
1689 | res_size += 9; | ||
1690 | } | ||
1691 | if (single_toc.pointb2 != 0xb2) { | ||
1692 | memmove(((char *) &single_toc) + 45, | ||
1693 | ((char *) &single_toc) + 36, | ||
1694 | res_size - 36); | ||
1695 | res_size += 9; | ||
1696 | } | ||
1697 | if (single_toc.pointb3 != 0xb3) { | ||
1698 | memmove(((char *) &single_toc) + 54, | ||
1699 | ((char *) &single_toc) + 45, | ||
1700 | res_size - 45); | ||
1701 | res_size += 9; | ||
1702 | } | ||
1703 | if (single_toc.pointb4 != 0xb4) { | ||
1704 | memmove(((char *) &single_toc) + 63, | ||
1705 | ((char *) &single_toc) + 54, | ||
1706 | res_size - 54); | ||
1707 | res_size += 9; | ||
1708 | } | ||
1709 | if (single_toc.pointc0 != 0xc0) { | ||
1710 | memmove(((char *) &single_toc) + 72, | ||
1711 | ((char *) &single_toc) + 63, | ||
1712 | res_size - 63); | ||
1713 | res_size += 9; | ||
1714 | } | ||
1715 | #if DEBUG | ||
1716 | printk(PRINT_INFO PFX "start track lba %u, " | ||
1717 | "leadout start lba %u\n", | ||
1718 | single_toc.start_track_lba, | ||
1719 | single_toc.lead_out_start_lba); | ||
1720 | { | ||
1721 | int i; | ||
1722 | for (i = 0; | ||
1723 | i < | ||
1724 | 1 + | ||
1725 | bcd_to_int(single_toc.last_track_num) | ||
1726 | - | ||
1727 | bcd_to_int(single_toc. | ||
1728 | first_track_num); i++) { | ||
1729 | printk(KERN_INFO PFX "trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n", | ||
1730 | i, | ||
1731 | single_toc.tracks[i].address, | ||
1732 | single_toc.tracks[i].control, | ||
1733 | bcd_to_int(single_toc. | ||
1734 | tracks[i].track), | ||
1735 | bcd_to_int(single_toc. | ||
1736 | tracks[i]. | ||
1737 | track_start_msf | ||
1738 | [0]), | ||
1739 | bcd_to_int(single_toc. | ||
1740 | tracks[i]. | ||
1741 | track_start_msf | ||
1742 | [1]), | ||
1743 | bcd_to_int(single_toc. | ||
1744 | tracks[i]. | ||
1745 | track_start_msf | ||
1746 | [2])); | ||
1747 | if (mint > | ||
1748 | bcd_to_int(single_toc. | ||
1749 | tracks[i].track)) | ||
1750 | mint = | ||
1751 | bcd_to_int(single_toc. | ||
1752 | tracks[i]. | ||
1753 | track); | ||
1754 | if (maxt < | ||
1755 | bcd_to_int(single_toc. | ||
1756 | tracks[i].track)) | ||
1757 | maxt = | ||
1758 | bcd_to_int(single_toc. | ||
1759 | tracks[i]. | ||
1760 | track); | ||
1761 | } | ||
1762 | printk(KERN_INFO PFX "min track number %d, " | ||
1763 | "max track number %d\n", | ||
1764 | mint, maxt); | ||
1765 | } | ||
1766 | #endif | ||
1767 | |||
1768 | /* prepare a special table of contents for a CD-I disc. They don't have one. */ | ||
1769 | if (single_toc.disk_type == 0x10 && | ||
1770 | single_toc.first_track_num == 2 && | ||
1771 | single_toc.last_track_num == 2 /* CD-I */ ) { | ||
1772 | sony_toc.tracks[totaltracks].address = 1; | ||
1773 | sony_toc.tracks[totaltracks].control = 4; /* force data tracks */ | ||
1774 | sony_toc.tracks[totaltracks].track = 1; | ||
1775 | sony_toc.tracks[totaltracks]. | ||
1776 | track_start_msf[0] = 0; | ||
1777 | sony_toc.tracks[totaltracks]. | ||
1778 | track_start_msf[1] = 2; | ||
1779 | sony_toc.tracks[totaltracks]. | ||
1780 | track_start_msf[2] = 0; | ||
1781 | mint = maxt = 1; | ||
1782 | totaltracks++; | ||
1783 | } else | ||
1784 | /* gather track entries from this session */ | ||
1785 | { | ||
1786 | int i; | ||
1787 | for (i = 0; | ||
1788 | i < | ||
1789 | 1 + | ||
1790 | bcd_to_int(single_toc.last_track_num) | ||
1791 | - | ||
1792 | bcd_to_int(single_toc. | ||
1793 | first_track_num); | ||
1794 | i++, totaltracks++) { | ||
1795 | sony_toc.tracks[totaltracks]. | ||
1796 | address = | ||
1797 | single_toc.tracks[i].address; | ||
1798 | sony_toc.tracks[totaltracks]. | ||
1799 | control = | ||
1800 | single_toc.tracks[i].control; | ||
1801 | sony_toc.tracks[totaltracks]. | ||
1802 | track = | ||
1803 | bcd_to_int(single_toc. | ||
1804 | tracks[i].track); | ||
1805 | sony_toc.tracks[totaltracks]. | ||
1806 | track_start_msf[0] = | ||
1807 | bcd_to_int(single_toc. | ||
1808 | tracks[i]. | ||
1809 | track_start_msf[0]); | ||
1810 | sony_toc.tracks[totaltracks]. | ||
1811 | track_start_msf[1] = | ||
1812 | bcd_to_int(single_toc. | ||
1813 | tracks[i]. | ||
1814 | track_start_msf[1]); | ||
1815 | sony_toc.tracks[totaltracks]. | ||
1816 | track_start_msf[2] = | ||
1817 | bcd_to_int(single_toc. | ||
1818 | tracks[i]. | ||
1819 | track_start_msf[2]); | ||
1820 | if (i == 0) | ||
1821 | single_toc. | ||
1822 | start_track_lba = | ||
1823 | msf_to_log(sony_toc. | ||
1824 | tracks | ||
1825 | [totaltracks]. | ||
1826 | track_start_msf); | ||
1827 | if (mint > | ||
1828 | sony_toc.tracks[totaltracks]. | ||
1829 | track) | ||
1830 | mint = | ||
1831 | sony_toc. | ||
1832 | tracks[totaltracks]. | ||
1833 | track; | ||
1834 | if (maxt < | ||
1835 | sony_toc.tracks[totaltracks]. | ||
1836 | track) | ||
1837 | maxt = | ||
1838 | sony_toc. | ||
1839 | tracks[totaltracks]. | ||
1840 | track; | ||
1841 | } | ||
1842 | } | ||
1843 | sony_toc.first_track_num = mint; | ||
1844 | sony_toc.last_track_num = maxt; | ||
1845 | /* Disk type of last session wins. For example: | ||
1846 | CD-Extra has disk type 0 for the first session, so | ||
1847 | a dumb HiFi CD player thinks it is a plain audio CD. | ||
1848 | We are interested in the disk type of the last session, | ||
1849 | which is 0x20 (XA) for CD-Extra, so we can access the | ||
1850 | data track ... */ | ||
1851 | sony_toc.disk_type = single_toc.disk_type; | ||
1852 | sony_toc.sessions = session; | ||
1853 | |||
1854 | /* don't believe everything :-) */ | ||
1855 | if (session == 1) | ||
1856 | single_toc.start_track_lba = 0; | ||
1857 | sony_toc.start_track_lba = | ||
1858 | single_toc.start_track_lba; | ||
1859 | |||
1860 | if (session > 1 && single_toc.pointb0 == 0xb0 && | ||
1861 | sony_toc.lead_out_start_lba == | ||
1862 | single_toc.lead_out_start_lba) { | ||
1863 | break; | ||
1864 | } | ||
1865 | |||
1866 | /* Let's not get carried away... */ | ||
1867 | if (session > 40) { | ||
1868 | printk(KERN_NOTICE PFX "too many sessions: " | ||
1869 | "%d\n", session); | ||
1870 | break; | ||
1871 | } | ||
1872 | session++; | ||
1873 | } | ||
1874 | sony_toc.track_entries = totaltracks; | ||
1875 | /* add one entry for the LAST track with track number CDROM_LEADOUT */ | ||
1876 | sony_toc.tracks[totaltracks].address = single_toc.address2; | ||
1877 | sony_toc.tracks[totaltracks].control = single_toc.control2; | ||
1878 | sony_toc.tracks[totaltracks].track = CDROM_LEADOUT; | ||
1879 | sony_toc.tracks[totaltracks].track_start_msf[0] = | ||
1880 | sony_toc.lead_out_start_msf[0]; | ||
1881 | sony_toc.tracks[totaltracks].track_start_msf[1] = | ||
1882 | sony_toc.lead_out_start_msf[1]; | ||
1883 | sony_toc.tracks[totaltracks].track_start_msf[2] = | ||
1884 | sony_toc.lead_out_start_msf[2]; | ||
1885 | |||
1886 | sony_toc_read = 1; | ||
1887 | |||
1888 | pr_debug(PFX "Disk session %d, start track: %d, " | ||
1889 | "stop track: %d\n", | ||
1890 | session, single_toc.start_track_lba, | ||
1891 | single_toc.lead_out_start_lba); | ||
1892 | } | ||
1893 | pr_debug(PFX "Leaving %s\n", __FUNCTION__); | ||
1894 | } | ||
1895 | |||
1896 | |||
1897 | /* | ||
1898 | * Uniform cdrom interface function | ||
1899 | * return multisession offset and sector information | ||
1900 | */ | ||
1901 | static int scd_get_last_session(struct cdrom_device_info *cdi, | ||
1902 | struct cdrom_multisession *ms_info) | ||
1903 | { | ||
1904 | if (ms_info == NULL) | ||
1905 | return 1; | ||
1906 | |||
1907 | if (!sony_toc_read) { | ||
1908 | if (down_interruptible(&sony_sem)) | ||
1909 | return -ERESTARTSYS; | ||
1910 | sony_get_toc(); | ||
1911 | up(&sony_sem); | ||
1912 | } | ||
1913 | |||
1914 | ms_info->addr_format = CDROM_LBA; | ||
1915 | ms_info->addr.lba = sony_toc.start_track_lba; | ||
1916 | ms_info->xa_flag = sony_toc.disk_type == SONY_XA_DISK_TYPE || | ||
1917 | sony_toc.disk_type == 0x10 /* CDI */ ; | ||
1918 | |||
1919 | return 0; | ||
1920 | } | ||
1921 | |||
1922 | /* | ||
1923 | * Search for a specific track in the table of contents. | ||
1924 | */ | ||
1925 | static int find_track(int track) | ||
1926 | { | ||
1927 | int i; | ||
1928 | |||
1929 | for (i = 0; i <= sony_toc.track_entries; i++) { | ||
1930 | if (sony_toc.tracks[i].track == track) { | ||
1931 | return i; | ||
1932 | } | ||
1933 | } | ||
1934 | |||
1935 | return -1; | ||
1936 | } | ||
1937 | |||
1938 | |||
1939 | /* | ||
1940 | * Read the subcode and put it in last_sony_subcode for future use. | ||
1941 | */ | ||
1942 | static int read_subcode(void) | ||
1943 | { | ||
1944 | unsigned int res_size; | ||
1945 | |||
1946 | |||
1947 | do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD, | ||
1948 | NULL, | ||
1949 | 0, (unsigned char *) &last_sony_subcode, &res_size); | ||
1950 | if ((res_size < 2) | ||
1951 | || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) { | ||
1952 | printk(KERN_ERR PFX "Sony CDROM error %s (read_subcode)\n", | ||
1953 | translate_error(last_sony_subcode.exec_status[1])); | ||
1954 | return -EIO; | ||
1955 | } | ||
1956 | |||
1957 | last_sony_subcode.track_num = | ||
1958 | bcd_to_int(last_sony_subcode.track_num); | ||
1959 | last_sony_subcode.index_num = | ||
1960 | bcd_to_int(last_sony_subcode.index_num); | ||
1961 | last_sony_subcode.abs_msf[0] = | ||
1962 | bcd_to_int(last_sony_subcode.abs_msf[0]); | ||
1963 | last_sony_subcode.abs_msf[1] = | ||
1964 | bcd_to_int(last_sony_subcode.abs_msf[1]); | ||
1965 | last_sony_subcode.abs_msf[2] = | ||
1966 | bcd_to_int(last_sony_subcode.abs_msf[2]); | ||
1967 | |||
1968 | last_sony_subcode.rel_msf[0] = | ||
1969 | bcd_to_int(last_sony_subcode.rel_msf[0]); | ||
1970 | last_sony_subcode.rel_msf[1] = | ||
1971 | bcd_to_int(last_sony_subcode.rel_msf[1]); | ||
1972 | last_sony_subcode.rel_msf[2] = | ||
1973 | bcd_to_int(last_sony_subcode.rel_msf[2]); | ||
1974 | return 0; | ||
1975 | } | ||
1976 | |||
1977 | /* | ||
1978 | * Uniform cdrom interface function | ||
1979 | * return the media catalog number found on some older audio cds | ||
1980 | */ | ||
1981 | static int | ||
1982 | scd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
1983 | { | ||
1984 | unsigned char resbuffer[2 + 14]; | ||
1985 | unsigned char *mcnp = mcn->medium_catalog_number; | ||
1986 | unsigned char *resp = resbuffer + 3; | ||
1987 | unsigned int res_size; | ||
1988 | |||
1989 | memset(mcn->medium_catalog_number, 0, 14); | ||
1990 | if (down_interruptible(&sony_sem)) | ||
1991 | return -ERESTARTSYS; | ||
1992 | do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD, | ||
1993 | NULL, 0, resbuffer, &res_size); | ||
1994 | up(&sony_sem); | ||
1995 | if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20)); | ||
1996 | else { | ||
1997 | /* packed bcd to single ASCII digits */ | ||
1998 | *mcnp++ = (*resp >> 4) + '0'; | ||
1999 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2000 | *mcnp++ = (*resp >> 4) + '0'; | ||
2001 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2002 | *mcnp++ = (*resp >> 4) + '0'; | ||
2003 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2004 | *mcnp++ = (*resp >> 4) + '0'; | ||
2005 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2006 | *mcnp++ = (*resp >> 4) + '0'; | ||
2007 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2008 | *mcnp++ = (*resp >> 4) + '0'; | ||
2009 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
2010 | *mcnp++ = (*resp >> 4) + '0'; | ||
2011 | } | ||
2012 | *mcnp = '\0'; | ||
2013 | return 0; | ||
2014 | } | ||
2015 | |||
2016 | |||
2017 | /* | ||
2018 | * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If | ||
2019 | * the drive is playing, the subchannel needs to be read (since it would be | ||
2020 | * changing). If the drive is paused or completed, the subcode information has | ||
2021 | * already been stored, just use that. The ioctl call wants things in decimal | ||
2022 | * (not BCD), so all the conversions are done. | ||
2023 | */ | ||
2024 | static int sony_get_subchnl_info(struct cdrom_subchnl *schi) | ||
2025 | { | ||
2026 | /* Get attention stuff */ | ||
2027 | while (handle_sony_cd_attention()); | ||
2028 | |||
2029 | sony_get_toc(); | ||
2030 | if (!sony_toc_read) { | ||
2031 | return -EIO; | ||
2032 | } | ||
2033 | |||
2034 | switch (sony_audio_status) { | ||
2035 | case CDROM_AUDIO_NO_STATUS: | ||
2036 | case CDROM_AUDIO_PLAY: | ||
2037 | if (read_subcode() < 0) { | ||
2038 | return -EIO; | ||
2039 | } | ||
2040 | break; | ||
2041 | |||
2042 | case CDROM_AUDIO_PAUSED: | ||
2043 | case CDROM_AUDIO_COMPLETED: | ||
2044 | break; | ||
2045 | |||
2046 | #if 0 | ||
2047 | case CDROM_AUDIO_NO_STATUS: | ||
2048 | schi->cdsc_audiostatus = sony_audio_status; | ||
2049 | return 0; | ||
2050 | break; | ||
2051 | #endif | ||
2052 | case CDROM_AUDIO_INVALID: | ||
2053 | case CDROM_AUDIO_ERROR: | ||
2054 | default: | ||
2055 | return -EIO; | ||
2056 | } | ||
2057 | |||
2058 | schi->cdsc_audiostatus = sony_audio_status; | ||
2059 | schi->cdsc_adr = last_sony_subcode.address; | ||
2060 | schi->cdsc_ctrl = last_sony_subcode.control; | ||
2061 | schi->cdsc_trk = last_sony_subcode.track_num; | ||
2062 | schi->cdsc_ind = last_sony_subcode.index_num; | ||
2063 | if (schi->cdsc_format == CDROM_MSF) { | ||
2064 | schi->cdsc_absaddr.msf.minute = | ||
2065 | last_sony_subcode.abs_msf[0]; | ||
2066 | schi->cdsc_absaddr.msf.second = | ||
2067 | last_sony_subcode.abs_msf[1]; | ||
2068 | schi->cdsc_absaddr.msf.frame = | ||
2069 | last_sony_subcode.abs_msf[2]; | ||
2070 | |||
2071 | schi->cdsc_reladdr.msf.minute = | ||
2072 | last_sony_subcode.rel_msf[0]; | ||
2073 | schi->cdsc_reladdr.msf.second = | ||
2074 | last_sony_subcode.rel_msf[1]; | ||
2075 | schi->cdsc_reladdr.msf.frame = | ||
2076 | last_sony_subcode.rel_msf[2]; | ||
2077 | } else if (schi->cdsc_format == CDROM_LBA) { | ||
2078 | schi->cdsc_absaddr.lba = | ||
2079 | msf_to_log(last_sony_subcode.abs_msf); | ||
2080 | schi->cdsc_reladdr.lba = | ||
2081 | msf_to_log(last_sony_subcode.rel_msf); | ||
2082 | } | ||
2083 | |||
2084 | return 0; | ||
2085 | } | ||
2086 | |||
2087 | /* Get audio data from the drive. This is fairly complex because I | ||
2088 | am looking for status and data at the same time, but if I get status | ||
2089 | then I just look for data. I need to get the status immediately so | ||
2090 | the switch from audio to data tracks will happen quickly. */ | ||
2091 | static void | ||
2092 | read_audio_data(char *buffer, unsigned char res_reg[], int *res_size) | ||
2093 | { | ||
2094 | unsigned long retry_count; | ||
2095 | int result_read; | ||
2096 | |||
2097 | |||
2098 | res_reg[0] = 0; | ||
2099 | res_reg[1] = 0; | ||
2100 | *res_size = 0; | ||
2101 | result_read = 0; | ||
2102 | |||
2103 | /* Wait for the drive to tell us we have something */ | ||
2104 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
2105 | continue_read_audio_wait: | ||
2106 | while (time_before(jiffies, retry_count) && !(is_data_ready()) | ||
2107 | && !(is_result_ready() || result_read)) { | ||
2108 | while (handle_sony_cd_attention()); | ||
2109 | |||
2110 | sony_sleep(); | ||
2111 | } | ||
2112 | if (!(is_data_ready())) { | ||
2113 | if (is_result_ready() && !result_read) { | ||
2114 | get_result(res_reg, res_size); | ||
2115 | |||
2116 | /* Read block status and continue waiting for data. */ | ||
2117 | if ((res_reg[0] & 0xf0) == 0x50) { | ||
2118 | result_read = 1; | ||
2119 | goto continue_read_audio_wait; | ||
2120 | } | ||
2121 | /* Invalid data from the drive. Shut down the operation. */ | ||
2122 | else if ((res_reg[0] & 0xf0) != 0x20) { | ||
2123 | printk(KERN_WARNING PFX "Got result that " | ||
2124 | "should have been error: %d\n", | ||
2125 | res_reg[0]); | ||
2126 | res_reg[0] = 0x20; | ||
2127 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
2128 | *res_size = 2; | ||
2129 | } | ||
2130 | abort_read(); | ||
2131 | } else { | ||
2132 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
2133 | res_reg[0] = 0x20; | ||
2134 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
2135 | *res_size = 2; | ||
2136 | abort_read(); | ||
2137 | } | ||
2138 | } else { | ||
2139 | clear_data_ready(); | ||
2140 | |||
2141 | /* If data block, then get 2340 bytes offset by 12. */ | ||
2142 | if (sony_raw_data_mode) { | ||
2143 | insb(sony_cd_read_reg, buffer + CD_XA_HEAD, | ||
2144 | CD_FRAMESIZE_RAW1); | ||
2145 | } else { | ||
2146 | /* Audio gets the whole 2352 bytes. */ | ||
2147 | insb(sony_cd_read_reg, buffer, CD_FRAMESIZE_RAW); | ||
2148 | } | ||
2149 | |||
2150 | /* If I haven't already gotten the result, get it now. */ | ||
2151 | if (!result_read) { | ||
2152 | /* Wait for the drive to tell us we have something */ | ||
2153 | retry_count = jiffies + SONY_JIFFIES_TIMEOUT; | ||
2154 | while (time_before(jiffies, retry_count) | ||
2155 | && !(is_result_ready())) { | ||
2156 | while (handle_sony_cd_attention()); | ||
2157 | |||
2158 | sony_sleep(); | ||
2159 | } | ||
2160 | |||
2161 | if (!is_result_ready()) { | ||
2162 | pr_debug(PFX "timeout out %d\n", __LINE__); | ||
2163 | res_reg[0] = 0x20; | ||
2164 | res_reg[1] = SONY_TIMEOUT_OP_ERR; | ||
2165 | *res_size = 2; | ||
2166 | abort_read(); | ||
2167 | return; | ||
2168 | } else { | ||
2169 | get_result(res_reg, res_size); | ||
2170 | } | ||
2171 | } | ||
2172 | |||
2173 | if ((res_reg[0] & 0xf0) == 0x50) { | ||
2174 | if ((res_reg[0] == SONY_NO_CIRC_ERR_BLK_STAT) | ||
2175 | || (res_reg[0] == SONY_NO_LECC_ERR_BLK_STAT) | ||
2176 | || (res_reg[0] == SONY_RECOV_LECC_ERR_BLK_STAT) | ||
2177 | || (res_reg[0] == SONY_NO_ERR_DETECTION_STAT)) { | ||
2178 | /* Ok, nothing to do. */ | ||
2179 | } else { | ||
2180 | printk(KERN_ERR PFX "Data block error: 0x%x\n", | ||
2181 | res_reg[0]); | ||
2182 | res_reg[0] = 0x20; | ||
2183 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
2184 | *res_size = 2; | ||
2185 | } | ||
2186 | } else if ((res_reg[0] & 0xf0) != 0x20) { | ||
2187 | /* The drive gave me bad status, I don't know what to do. | ||
2188 | Reset the driver and return an error. */ | ||
2189 | printk(KERN_NOTICE PFX "Invalid block status: 0x%x\n", | ||
2190 | res_reg[0]); | ||
2191 | restart_on_error(); | ||
2192 | res_reg[0] = 0x20; | ||
2193 | res_reg[1] = SONY_BAD_DATA_ERR; | ||
2194 | *res_size = 2; | ||
2195 | } | ||
2196 | } | ||
2197 | } | ||
2198 | |||
2199 | /* Perform a raw data read. This will automatically detect the | ||
2200 | track type and read the proper data (audio or data). */ | ||
2201 | static int read_audio(struct cdrom_read_audio *ra) | ||
2202 | { | ||
2203 | int retval; | ||
2204 | unsigned char params[2]; | ||
2205 | unsigned char res_reg[12]; | ||
2206 | unsigned int res_size; | ||
2207 | unsigned int cframe; | ||
2208 | |||
2209 | if (down_interruptible(&sony_sem)) | ||
2210 | return -ERESTARTSYS; | ||
2211 | if (!sony_spun_up) | ||
2212 | scd_spinup(); | ||
2213 | |||
2214 | /* Set the drive to do raw operations. */ | ||
2215 | params[0] = SONY_SD_DECODE_PARAM; | ||
2216 | params[1] = 0x06 | sony_raw_data_mode; | ||
2217 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2218 | params, 2, res_reg, &res_size); | ||
2219 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2220 | printk(KERN_ERR PFX "Unable to set decode params: 0x%2.2x\n", | ||
2221 | res_reg[1]); | ||
2222 | retval = -EIO; | ||
2223 | goto out_up; | ||
2224 | } | ||
2225 | |||
2226 | /* From here down, we have to goto exit_read_audio instead of returning | ||
2227 | because the drive parameters have to be set back to data before | ||
2228 | return. */ | ||
2229 | |||
2230 | retval = 0; | ||
2231 | if (start_request(ra->addr.lba, ra->nframes)) { | ||
2232 | retval = -EIO; | ||
2233 | goto exit_read_audio; | ||
2234 | } | ||
2235 | |||
2236 | /* For every requested frame. */ | ||
2237 | cframe = 0; | ||
2238 | while (cframe < ra->nframes) { | ||
2239 | read_audio_data(audio_buffer, res_reg, &res_size); | ||
2240 | if ((res_reg[0] & 0xf0) == 0x20) { | ||
2241 | if (res_reg[1] == SONY_BAD_DATA_ERR) { | ||
2242 | printk(KERN_ERR PFX "Data error on audio " | ||
2243 | "sector %d\n", | ||
2244 | ra->addr.lba + cframe); | ||
2245 | } else if (res_reg[1] == SONY_ILL_TRACK_R_ERR) { | ||
2246 | /* Illegal track type, change track types and start over. */ | ||
2247 | sony_raw_data_mode = | ||
2248 | (sony_raw_data_mode) ? 0 : 1; | ||
2249 | |||
2250 | /* Set the drive mode. */ | ||
2251 | params[0] = SONY_SD_DECODE_PARAM; | ||
2252 | params[1] = 0x06 | sony_raw_data_mode; | ||
2253 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2254 | params, | ||
2255 | 2, res_reg, &res_size); | ||
2256 | if ((res_size < 2) | ||
2257 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2258 | printk(KERN_ERR PFX "Unable to set " | ||
2259 | "decode params: 0x%2.2x\n", | ||
2260 | res_reg[1]); | ||
2261 | retval = -EIO; | ||
2262 | goto exit_read_audio; | ||
2263 | } | ||
2264 | |||
2265 | /* Restart the request on the current frame. */ | ||
2266 | if (start_request | ||
2267 | (ra->addr.lba + cframe, | ||
2268 | ra->nframes - cframe)) { | ||
2269 | retval = -EIO; | ||
2270 | goto exit_read_audio; | ||
2271 | } | ||
2272 | |||
2273 | /* Don't go back to the top because don't want to get into | ||
2274 | and infinite loop. A lot of code gets duplicated, but | ||
2275 | that's no big deal, I don't guess. */ | ||
2276 | read_audio_data(audio_buffer, res_reg, | ||
2277 | &res_size); | ||
2278 | if ((res_reg[0] & 0xf0) == 0x20) { | ||
2279 | if (res_reg[1] == | ||
2280 | SONY_BAD_DATA_ERR) { | ||
2281 | printk(KERN_ERR PFX "Data error" | ||
2282 | " on audio sector %d\n", | ||
2283 | ra->addr.lba + | ||
2284 | cframe); | ||
2285 | } else { | ||
2286 | printk(KERN_ERR PFX "Error reading audio data on sector %d: %s\n", | ||
2287 | ra->addr.lba + cframe, | ||
2288 | translate_error | ||
2289 | (res_reg[1])); | ||
2290 | retval = -EIO; | ||
2291 | goto exit_read_audio; | ||
2292 | } | ||
2293 | } else if (copy_to_user(ra->buf + | ||
2294 | (CD_FRAMESIZE_RAW | ||
2295 | * cframe), | ||
2296 | audio_buffer, | ||
2297 | CD_FRAMESIZE_RAW)) { | ||
2298 | retval = -EFAULT; | ||
2299 | goto exit_read_audio; | ||
2300 | } | ||
2301 | } else { | ||
2302 | printk(KERN_ERR PFX "Error reading audio " | ||
2303 | "data on sector %d: %s\n", | ||
2304 | ra->addr.lba + cframe, | ||
2305 | translate_error(res_reg[1])); | ||
2306 | retval = -EIO; | ||
2307 | goto exit_read_audio; | ||
2308 | } | ||
2309 | } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe), | ||
2310 | (char *)audio_buffer, | ||
2311 | CD_FRAMESIZE_RAW)) { | ||
2312 | retval = -EFAULT; | ||
2313 | goto exit_read_audio; | ||
2314 | } | ||
2315 | |||
2316 | cframe++; | ||
2317 | } | ||
2318 | |||
2319 | get_result(res_reg, &res_size); | ||
2320 | if ((res_reg[0] & 0xf0) == 0x20) { | ||
2321 | printk(KERN_ERR PFX "Error return from audio read: %s\n", | ||
2322 | translate_error(res_reg[1])); | ||
2323 | retval = -EIO; | ||
2324 | goto exit_read_audio; | ||
2325 | } | ||
2326 | |||
2327 | exit_read_audio: | ||
2328 | |||
2329 | /* Set the drive mode back to the proper one for the disk. */ | ||
2330 | params[0] = SONY_SD_DECODE_PARAM; | ||
2331 | if (!sony_xa_mode) { | ||
2332 | params[1] = 0x0f; | ||
2333 | } else { | ||
2334 | params[1] = 0x07; | ||
2335 | } | ||
2336 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2337 | params, 2, res_reg, &res_size); | ||
2338 | if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2339 | printk(KERN_ERR PFX "Unable to reset decode params: 0x%2.2x\n", | ||
2340 | res_reg[1]); | ||
2341 | retval = -EIO; | ||
2342 | } | ||
2343 | |||
2344 | out_up: | ||
2345 | up(&sony_sem); | ||
2346 | |||
2347 | return retval; | ||
2348 | } | ||
2349 | |||
2350 | static int | ||
2351 | do_sony_cd_cmd_chk(const char *name, | ||
2352 | unsigned char cmd, | ||
2353 | unsigned char *params, | ||
2354 | unsigned int num_params, | ||
2355 | unsigned char *result_buffer, unsigned int *result_size) | ||
2356 | { | ||
2357 | do_sony_cd_cmd(cmd, params, num_params, result_buffer, | ||
2358 | result_size); | ||
2359 | if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) { | ||
2360 | printk(KERN_ERR PFX "Error %s (CDROM%s)\n", | ||
2361 | translate_error(result_buffer[1]), name); | ||
2362 | return -EIO; | ||
2363 | } | ||
2364 | return 0; | ||
2365 | } | ||
2366 | |||
2367 | /* | ||
2368 | * Uniform cdrom interface function | ||
2369 | * open the tray | ||
2370 | */ | ||
2371 | static int scd_tray_move(struct cdrom_device_info *cdi, int position) | ||
2372 | { | ||
2373 | int retval; | ||
2374 | |||
2375 | if (down_interruptible(&sony_sem)) | ||
2376 | return -ERESTARTSYS; | ||
2377 | if (position == 1 /* open tray */ ) { | ||
2378 | unsigned char res_reg[12]; | ||
2379 | unsigned int res_size; | ||
2380 | |||
2381 | do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, | ||
2382 | &res_size); | ||
2383 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, | ||
2384 | &res_size); | ||
2385 | |||
2386 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
2387 | retval = do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0, | ||
2388 | res_reg, &res_size); | ||
2389 | } else { | ||
2390 | if (0 == scd_spinup()) | ||
2391 | sony_spun_up = 1; | ||
2392 | retval = 0; | ||
2393 | } | ||
2394 | up(&sony_sem); | ||
2395 | return retval; | ||
2396 | } | ||
2397 | |||
2398 | /* | ||
2399 | * The big ugly ioctl handler. | ||
2400 | */ | ||
2401 | static int scd_audio_ioctl(struct cdrom_device_info *cdi, | ||
2402 | unsigned int cmd, void *arg) | ||
2403 | { | ||
2404 | unsigned char res_reg[12]; | ||
2405 | unsigned int res_size; | ||
2406 | unsigned char params[7]; | ||
2407 | int i, retval; | ||
2408 | |||
2409 | if (down_interruptible(&sony_sem)) | ||
2410 | return -ERESTARTSYS; | ||
2411 | switch (cmd) { | ||
2412 | case CDROMSTART: /* Spin up the drive */ | ||
2413 | retval = do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL, | ||
2414 | 0, res_reg, &res_size); | ||
2415 | break; | ||
2416 | |||
2417 | case CDROMSTOP: /* Spin down the drive */ | ||
2418 | do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, | ||
2419 | &res_size); | ||
2420 | |||
2421 | /* | ||
2422 | * Spin the drive down, ignoring the error if the disk was | ||
2423 | * already not spinning. | ||
2424 | */ | ||
2425 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
2426 | retval = do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL, | ||
2427 | 0, res_reg, &res_size); | ||
2428 | break; | ||
2429 | |||
2430 | case CDROMPAUSE: /* Pause the drive */ | ||
2431 | if (do_sony_cd_cmd_chk | ||
2432 | ("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, | ||
2433 | &res_size)) { | ||
2434 | retval = -EIO; | ||
2435 | break; | ||
2436 | } | ||
2437 | /* Get the current position and save it for resuming */ | ||
2438 | if (read_subcode() < 0) { | ||
2439 | retval = -EIO; | ||
2440 | break; | ||
2441 | } | ||
2442 | cur_pos_msf[0] = last_sony_subcode.abs_msf[0]; | ||
2443 | cur_pos_msf[1] = last_sony_subcode.abs_msf[1]; | ||
2444 | cur_pos_msf[2] = last_sony_subcode.abs_msf[2]; | ||
2445 | sony_audio_status = CDROM_AUDIO_PAUSED; | ||
2446 | retval = 0; | ||
2447 | break; | ||
2448 | |||
2449 | case CDROMRESUME: /* Start the drive after being paused */ | ||
2450 | if (sony_audio_status != CDROM_AUDIO_PAUSED) { | ||
2451 | retval = -EINVAL; | ||
2452 | break; | ||
2453 | } | ||
2454 | |||
2455 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
2456 | &res_size); | ||
2457 | |||
2458 | /* Start the drive at the saved position. */ | ||
2459 | params[1] = int_to_bcd(cur_pos_msf[0]); | ||
2460 | params[2] = int_to_bcd(cur_pos_msf[1]); | ||
2461 | params[3] = int_to_bcd(cur_pos_msf[2]); | ||
2462 | params[4] = int_to_bcd(final_pos_msf[0]); | ||
2463 | params[5] = int_to_bcd(final_pos_msf[1]); | ||
2464 | params[6] = int_to_bcd(final_pos_msf[2]); | ||
2465 | params[0] = 0x03; | ||
2466 | if (do_sony_cd_cmd_chk | ||
2467 | ("RESUME", SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, | ||
2468 | &res_size) < 0) { | ||
2469 | retval = -EIO; | ||
2470 | break; | ||
2471 | } | ||
2472 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
2473 | retval = 0; | ||
2474 | break; | ||
2475 | |||
2476 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | ||
2477 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
2478 | &res_size); | ||
2479 | |||
2480 | /* The parameters are given in int, must be converted */ | ||
2481 | for (i = 1; i < 7; i++) { | ||
2482 | params[i] = | ||
2483 | int_to_bcd(((unsigned char *) arg)[i - 1]); | ||
2484 | } | ||
2485 | params[0] = 0x03; | ||
2486 | if (do_sony_cd_cmd_chk | ||
2487 | ("PLAYMSF", SONY_AUDIO_PLAYBACK_CMD, params, 7, | ||
2488 | res_reg, &res_size) < 0) { | ||
2489 | retval = -EIO; | ||
2490 | break; | ||
2491 | } | ||
2492 | |||
2493 | /* Save the final position for pauses and resumes */ | ||
2494 | final_pos_msf[0] = bcd_to_int(params[4]); | ||
2495 | final_pos_msf[1] = bcd_to_int(params[5]); | ||
2496 | final_pos_msf[2] = bcd_to_int(params[6]); | ||
2497 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
2498 | retval = 0; | ||
2499 | break; | ||
2500 | |||
2501 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
2502 | { | ||
2503 | struct cdrom_tochdr *hdr; | ||
2504 | |||
2505 | sony_get_toc(); | ||
2506 | if (!sony_toc_read) { | ||
2507 | retval = -EIO; | ||
2508 | break; | ||
2509 | } | ||
2510 | |||
2511 | hdr = (struct cdrom_tochdr *) arg; | ||
2512 | hdr->cdth_trk0 = sony_toc.first_track_num; | ||
2513 | hdr->cdth_trk1 = sony_toc.last_track_num; | ||
2514 | } | ||
2515 | retval = 0; | ||
2516 | break; | ||
2517 | |||
2518 | case CDROMREADTOCENTRY: /* Read a given table of contents entry */ | ||
2519 | { | ||
2520 | struct cdrom_tocentry *entry; | ||
2521 | int track_idx; | ||
2522 | unsigned char *msf_val = NULL; | ||
2523 | |||
2524 | sony_get_toc(); | ||
2525 | if (!sony_toc_read) { | ||
2526 | retval = -EIO; | ||
2527 | break; | ||
2528 | } | ||
2529 | |||
2530 | entry = (struct cdrom_tocentry *) arg; | ||
2531 | |||
2532 | track_idx = find_track(entry->cdte_track); | ||
2533 | if (track_idx < 0) { | ||
2534 | retval = -EINVAL; | ||
2535 | break; | ||
2536 | } | ||
2537 | |||
2538 | entry->cdte_adr = | ||
2539 | sony_toc.tracks[track_idx].address; | ||
2540 | entry->cdte_ctrl = | ||
2541 | sony_toc.tracks[track_idx].control; | ||
2542 | msf_val = | ||
2543 | sony_toc.tracks[track_idx].track_start_msf; | ||
2544 | |||
2545 | /* Logical buffer address or MSF format requested? */ | ||
2546 | if (entry->cdte_format == CDROM_LBA) { | ||
2547 | entry->cdte_addr.lba = msf_to_log(msf_val); | ||
2548 | } else if (entry->cdte_format == CDROM_MSF) { | ||
2549 | entry->cdte_addr.msf.minute = *msf_val; | ||
2550 | entry->cdte_addr.msf.second = | ||
2551 | *(msf_val + 1); | ||
2552 | entry->cdte_addr.msf.frame = | ||
2553 | *(msf_val + 2); | ||
2554 | } | ||
2555 | } | ||
2556 | retval = 0; | ||
2557 | break; | ||
2558 | |||
2559 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
2560 | { | ||
2561 | struct cdrom_ti *ti = (struct cdrom_ti *) arg; | ||
2562 | int track_idx; | ||
2563 | |||
2564 | sony_get_toc(); | ||
2565 | if (!sony_toc_read) { | ||
2566 | retval = -EIO; | ||
2567 | break; | ||
2568 | } | ||
2569 | |||
2570 | if ((ti->cdti_trk0 < sony_toc.first_track_num) | ||
2571 | || (ti->cdti_trk0 > sony_toc.last_track_num) | ||
2572 | || (ti->cdti_trk1 < ti->cdti_trk0)) { | ||
2573 | retval = -EINVAL; | ||
2574 | break; | ||
2575 | } | ||
2576 | |||
2577 | track_idx = find_track(ti->cdti_trk0); | ||
2578 | if (track_idx < 0) { | ||
2579 | retval = -EINVAL; | ||
2580 | break; | ||
2581 | } | ||
2582 | params[1] = | ||
2583 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2584 | track_start_msf[0]); | ||
2585 | params[2] = | ||
2586 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2587 | track_start_msf[1]); | ||
2588 | params[3] = | ||
2589 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2590 | track_start_msf[2]); | ||
2591 | |||
2592 | /* | ||
2593 | * If we want to stop after the last track, use the lead-out | ||
2594 | * MSF to do that. | ||
2595 | */ | ||
2596 | if (ti->cdti_trk1 >= sony_toc.last_track_num) { | ||
2597 | track_idx = find_track(CDROM_LEADOUT); | ||
2598 | } else { | ||
2599 | track_idx = find_track(ti->cdti_trk1 + 1); | ||
2600 | } | ||
2601 | if (track_idx < 0) { | ||
2602 | retval = -EINVAL; | ||
2603 | break; | ||
2604 | } | ||
2605 | params[4] = | ||
2606 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2607 | track_start_msf[0]); | ||
2608 | params[5] = | ||
2609 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2610 | track_start_msf[1]); | ||
2611 | params[6] = | ||
2612 | int_to_bcd(sony_toc.tracks[track_idx]. | ||
2613 | track_start_msf[2]); | ||
2614 | params[0] = 0x03; | ||
2615 | |||
2616 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, | ||
2617 | &res_size); | ||
2618 | |||
2619 | do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, | ||
2620 | res_reg, &res_size); | ||
2621 | |||
2622 | if ((res_size < 2) | ||
2623 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2624 | printk(KERN_ERR PFX | ||
2625 | "Params: %x %x %x %x %x %x %x\n", | ||
2626 | params[0], params[1], params[2], | ||
2627 | params[3], params[4], params[5], | ||
2628 | params[6]); | ||
2629 | printk(KERN_ERR PFX | ||
2630 | "Error %s (CDROMPLAYTRKIND)\n", | ||
2631 | translate_error(res_reg[1])); | ||
2632 | retval = -EIO; | ||
2633 | break; | ||
2634 | } | ||
2635 | |||
2636 | /* Save the final position for pauses and resumes */ | ||
2637 | final_pos_msf[0] = bcd_to_int(params[4]); | ||
2638 | final_pos_msf[1] = bcd_to_int(params[5]); | ||
2639 | final_pos_msf[2] = bcd_to_int(params[6]); | ||
2640 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
2641 | retval = 0; | ||
2642 | break; | ||
2643 | } | ||
2644 | |||
2645 | case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ | ||
2646 | { | ||
2647 | struct cdrom_volctrl *volctrl = | ||
2648 | (struct cdrom_volctrl *) arg; | ||
2649 | |||
2650 | params[0] = SONY_SD_AUDIO_VOLUME; | ||
2651 | params[1] = volctrl->channel0; | ||
2652 | params[2] = volctrl->channel1; | ||
2653 | retval = do_sony_cd_cmd_chk("VOLCTRL", | ||
2654 | SONY_SET_DRIVE_PARAM_CMD, | ||
2655 | params, 3, res_reg, | ||
2656 | &res_size); | ||
2657 | break; | ||
2658 | } | ||
2659 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
2660 | retval = sony_get_subchnl_info((struct cdrom_subchnl *) arg); | ||
2661 | break; | ||
2662 | |||
2663 | default: | ||
2664 | retval = -EINVAL; | ||
2665 | break; | ||
2666 | } | ||
2667 | up(&sony_sem); | ||
2668 | return retval; | ||
2669 | } | ||
2670 | |||
2671 | static int scd_dev_ioctl(struct cdrom_device_info *cdi, | ||
2672 | unsigned int cmd, unsigned long arg) | ||
2673 | { | ||
2674 | void __user *argp = (void __user *)arg; | ||
2675 | int retval; | ||
2676 | |||
2677 | if (down_interruptible(&sony_sem)) | ||
2678 | return -ERESTARTSYS; | ||
2679 | switch (cmd) { | ||
2680 | case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte | ||
2681 | raw data tracks. */ | ||
2682 | { | ||
2683 | struct cdrom_read_audio ra; | ||
2684 | |||
2685 | |||
2686 | sony_get_toc(); | ||
2687 | if (!sony_toc_read) { | ||
2688 | retval = -EIO; | ||
2689 | break; | ||
2690 | } | ||
2691 | |||
2692 | if (copy_from_user(&ra, argp, sizeof(ra))) { | ||
2693 | retval = -EFAULT; | ||
2694 | break; | ||
2695 | } | ||
2696 | |||
2697 | if (ra.nframes == 0) { | ||
2698 | retval = 0; | ||
2699 | break; | ||
2700 | } | ||
2701 | |||
2702 | if (!access_ok(VERIFY_WRITE, ra.buf, | ||
2703 | CD_FRAMESIZE_RAW * ra.nframes)) | ||
2704 | return -EFAULT; | ||
2705 | |||
2706 | if (ra.addr_format == CDROM_LBA) { | ||
2707 | if ((ra.addr.lba >= | ||
2708 | sony_toc.lead_out_start_lba) | ||
2709 | || (ra.addr.lba + ra.nframes >= | ||
2710 | sony_toc.lead_out_start_lba)) { | ||
2711 | retval = -EINVAL; | ||
2712 | break; | ||
2713 | } | ||
2714 | } else if (ra.addr_format == CDROM_MSF) { | ||
2715 | if ((ra.addr.msf.minute >= 75) | ||
2716 | || (ra.addr.msf.second >= 60) | ||
2717 | || (ra.addr.msf.frame >= 75)) { | ||
2718 | retval = -EINVAL; | ||
2719 | break; | ||
2720 | } | ||
2721 | |||
2722 | ra.addr.lba = ((ra.addr.msf.minute * 4500) | ||
2723 | + (ra.addr.msf.second * 75) | ||
2724 | + ra.addr.msf.frame); | ||
2725 | if ((ra.addr.lba >= | ||
2726 | sony_toc.lead_out_start_lba) | ||
2727 | || (ra.addr.lba + ra.nframes >= | ||
2728 | sony_toc.lead_out_start_lba)) { | ||
2729 | retval = -EINVAL; | ||
2730 | break; | ||
2731 | } | ||
2732 | |||
2733 | /* I know, this can go negative on an unsigned. However, | ||
2734 | the first thing done to the data is to add this value, | ||
2735 | so this should compensate and allow direct msf access. */ | ||
2736 | ra.addr.lba -= LOG_START_OFFSET; | ||
2737 | } else { | ||
2738 | retval = -EINVAL; | ||
2739 | break; | ||
2740 | } | ||
2741 | |||
2742 | retval = read_audio(&ra); | ||
2743 | break; | ||
2744 | } | ||
2745 | retval = 0; | ||
2746 | break; | ||
2747 | |||
2748 | default: | ||
2749 | retval = -EINVAL; | ||
2750 | } | ||
2751 | up(&sony_sem); | ||
2752 | return retval; | ||
2753 | } | ||
2754 | |||
2755 | static int scd_spinup(void) | ||
2756 | { | ||
2757 | unsigned char res_reg[12]; | ||
2758 | unsigned int res_size; | ||
2759 | int num_spin_ups; | ||
2760 | |||
2761 | num_spin_ups = 0; | ||
2762 | |||
2763 | respinup_on_open: | ||
2764 | do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); | ||
2765 | |||
2766 | /* The drive sometimes returns error 0. I don't know why, but ignore | ||
2767 | it. It seems to mean the drive has already done the operation. */ | ||
2768 | if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) { | ||
2769 | printk(KERN_ERR PFX "%s error (scd_open, spin up)\n", | ||
2770 | translate_error(res_reg[1])); | ||
2771 | return 1; | ||
2772 | } | ||
2773 | |||
2774 | do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size); | ||
2775 | |||
2776 | /* The drive sometimes returns error 0. I don't know why, but ignore | ||
2777 | it. It seems to mean the drive has already done the operation. */ | ||
2778 | if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) { | ||
2779 | /* If the drive is already playing, it's ok. */ | ||
2780 | if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) | ||
2781 | || (res_reg[1] == 0)) { | ||
2782 | return 0; | ||
2783 | } | ||
2784 | |||
2785 | /* If the drive says it is not spun up (even though we just did it!) | ||
2786 | then retry the operation at least a few times. */ | ||
2787 | if ((res_reg[1] == SONY_NOT_SPIN_ERR) | ||
2788 | && (num_spin_ups < MAX_CDU31A_RETRIES)) { | ||
2789 | num_spin_ups++; | ||
2790 | goto respinup_on_open; | ||
2791 | } | ||
2792 | |||
2793 | printk(KERN_ERR PFX "Error %s (scd_open, read toc)\n", | ||
2794 | translate_error(res_reg[1])); | ||
2795 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, | ||
2796 | &res_size); | ||
2797 | return 1; | ||
2798 | } | ||
2799 | return 0; | ||
2800 | } | ||
2801 | |||
2802 | /* | ||
2803 | * Open the drive for operations. Spin the drive up and read the table of | ||
2804 | * contents if these have not already been done. | ||
2805 | */ | ||
2806 | static int scd_open(struct cdrom_device_info *cdi, int purpose) | ||
2807 | { | ||
2808 | unsigned char res_reg[12]; | ||
2809 | unsigned int res_size; | ||
2810 | unsigned char params[2]; | ||
2811 | |||
2812 | if (purpose == 1) { | ||
2813 | /* Open for IOCTLs only - no media check */ | ||
2814 | sony_usage++; | ||
2815 | return 0; | ||
2816 | } | ||
2817 | |||
2818 | if (sony_usage == 0) { | ||
2819 | if (scd_spinup() != 0) | ||
2820 | return -EIO; | ||
2821 | sony_get_toc(); | ||
2822 | if (!sony_toc_read) { | ||
2823 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, | ||
2824 | res_reg, &res_size); | ||
2825 | return -EIO; | ||
2826 | } | ||
2827 | |||
2828 | /* For XA on the CDU31A only, we have to do special reads. | ||
2829 | The CDU33A handles XA automagically. */ | ||
2830 | /* if ( (sony_toc.disk_type == SONY_XA_DISK_TYPE) */ | ||
2831 | if ((sony_toc.disk_type != 0x00) | ||
2832 | && (!is_double_speed)) { | ||
2833 | params[0] = SONY_SD_DECODE_PARAM; | ||
2834 | params[1] = 0x07; | ||
2835 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2836 | params, 2, res_reg, &res_size); | ||
2837 | if ((res_size < 2) | ||
2838 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2839 | printk(KERN_WARNING PFX "Unable to set " | ||
2840 | "XA params: 0x%2.2x\n", res_reg[1]); | ||
2841 | } | ||
2842 | sony_xa_mode = 1; | ||
2843 | } | ||
2844 | /* A non-XA disk. Set the parms back if necessary. */ | ||
2845 | else if (sony_xa_mode) { | ||
2846 | params[0] = SONY_SD_DECODE_PARAM; | ||
2847 | params[1] = 0x0f; | ||
2848 | do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, | ||
2849 | params, 2, res_reg, &res_size); | ||
2850 | if ((res_size < 2) | ||
2851 | || ((res_reg[0] & 0xf0) == 0x20)) { | ||
2852 | printk(KERN_WARNING PFX "Unable to reset " | ||
2853 | "XA params: 0x%2.2x\n", res_reg[1]); | ||
2854 | } | ||
2855 | sony_xa_mode = 0; | ||
2856 | } | ||
2857 | |||
2858 | sony_spun_up = 1; | ||
2859 | } | ||
2860 | |||
2861 | sony_usage++; | ||
2862 | |||
2863 | return 0; | ||
2864 | } | ||
2865 | |||
2866 | |||
2867 | /* | ||
2868 | * Close the drive. Spin it down if no task is using it. The spin | ||
2869 | * down will fail if playing audio, so audio play is OK. | ||
2870 | */ | ||
2871 | static void scd_release(struct cdrom_device_info *cdi) | ||
2872 | { | ||
2873 | if (sony_usage == 1) { | ||
2874 | unsigned char res_reg[12]; | ||
2875 | unsigned int res_size; | ||
2876 | |||
2877 | do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, | ||
2878 | &res_size); | ||
2879 | |||
2880 | sony_spun_up = 0; | ||
2881 | } | ||
2882 | sony_usage--; | ||
2883 | } | ||
2884 | |||
2885 | static struct cdrom_device_ops scd_dops = { | ||
2886 | .open = scd_open, | ||
2887 | .release = scd_release, | ||
2888 | .drive_status = scd_drive_status, | ||
2889 | .media_changed = scd_media_changed, | ||
2890 | .tray_move = scd_tray_move, | ||
2891 | .lock_door = scd_lock_door, | ||
2892 | .select_speed = scd_select_speed, | ||
2893 | .get_last_session = scd_get_last_session, | ||
2894 | .get_mcn = scd_get_mcn, | ||
2895 | .reset = scd_reset, | ||
2896 | .audio_ioctl = scd_audio_ioctl, | ||
2897 | .dev_ioctl = scd_dev_ioctl, | ||
2898 | .capability = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK | | ||
2899 | CDC_SELECT_SPEED | CDC_MULTI_SESSION | | ||
2900 | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | | ||
2901 | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, | ||
2902 | .n_minors = 1, | ||
2903 | }; | ||
2904 | |||
2905 | static struct cdrom_device_info scd_info = { | ||
2906 | .ops = &scd_dops, | ||
2907 | .speed = 2, | ||
2908 | .capacity = 1, | ||
2909 | .name = "cdu31a" | ||
2910 | }; | ||
2911 | |||
2912 | static int scd_block_open(struct inode *inode, struct file *file) | ||
2913 | { | ||
2914 | return cdrom_open(&scd_info, inode, file); | ||
2915 | } | ||
2916 | |||
2917 | static int scd_block_release(struct inode *inode, struct file *file) | ||
2918 | { | ||
2919 | return cdrom_release(&scd_info, file); | ||
2920 | } | ||
2921 | |||
2922 | static int scd_block_ioctl(struct inode *inode, struct file *file, | ||
2923 | unsigned cmd, unsigned long arg) | ||
2924 | { | ||
2925 | int retval; | ||
2926 | |||
2927 | /* The eject and close commands should be handled by Uniform CD-ROM | ||
2928 | * driver - but I always got hard lockup instead of eject | ||
2929 | * until I put this here. | ||
2930 | */ | ||
2931 | switch (cmd) { | ||
2932 | case CDROMEJECT: | ||
2933 | scd_lock_door(&scd_info, 0); | ||
2934 | retval = scd_tray_move(&scd_info, 1); | ||
2935 | break; | ||
2936 | case CDROMCLOSETRAY: | ||
2937 | retval = scd_tray_move(&scd_info, 0); | ||
2938 | break; | ||
2939 | default: | ||
2940 | retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg); | ||
2941 | } | ||
2942 | return retval; | ||
2943 | } | ||
2944 | |||
2945 | static int scd_block_media_changed(struct gendisk *disk) | ||
2946 | { | ||
2947 | return cdrom_media_changed(&scd_info); | ||
2948 | } | ||
2949 | |||
2950 | struct block_device_operations scd_bdops = | ||
2951 | { | ||
2952 | .owner = THIS_MODULE, | ||
2953 | .open = scd_block_open, | ||
2954 | .release = scd_block_release, | ||
2955 | .ioctl = scd_block_ioctl, | ||
2956 | .media_changed = scd_block_media_changed, | ||
2957 | }; | ||
2958 | |||
2959 | static struct gendisk *scd_gendisk; | ||
2960 | |||
2961 | /* The different types of disc loading mechanisms supported */ | ||
2962 | static char *load_mech[] __initdata = | ||
2963 | { "caddy", "tray", "pop-up", "unknown" }; | ||
2964 | |||
2965 | static int __init | ||
2966 | get_drive_configuration(unsigned short base_io, | ||
2967 | unsigned char res_reg[], unsigned int *res_size) | ||
2968 | { | ||
2969 | unsigned long retry_count; | ||
2970 | |||
2971 | |||
2972 | if (!request_region(base_io, 4, "cdu31a")) | ||
2973 | return 0; | ||
2974 | |||
2975 | /* Set the base address */ | ||
2976 | cdu31a_port = base_io; | ||
2977 | |||
2978 | /* Set up all the register locations */ | ||
2979 | sony_cd_cmd_reg = cdu31a_port + SONY_CMD_REG_OFFSET; | ||
2980 | sony_cd_param_reg = cdu31a_port + SONY_PARAM_REG_OFFSET; | ||
2981 | sony_cd_write_reg = cdu31a_port + SONY_WRITE_REG_OFFSET; | ||
2982 | sony_cd_control_reg = cdu31a_port + SONY_CONTROL_REG_OFFSET; | ||
2983 | sony_cd_status_reg = cdu31a_port + SONY_STATUS_REG_OFFSET; | ||
2984 | sony_cd_result_reg = cdu31a_port + SONY_RESULT_REG_OFFSET; | ||
2985 | sony_cd_read_reg = cdu31a_port + SONY_READ_REG_OFFSET; | ||
2986 | sony_cd_fifost_reg = cdu31a_port + SONY_FIFOST_REG_OFFSET; | ||
2987 | |||
2988 | /* | ||
2989 | * Check to see if anything exists at the status register location. | ||
2990 | * I don't know if this is a good way to check, but it seems to work | ||
2991 | * ok for me. | ||
2992 | */ | ||
2993 | if (read_status_register() != 0xff) { | ||
2994 | /* | ||
2995 | * Reset the drive and wait for attention from it (to say it's reset). | ||
2996 | * If you don't wait, the next operation will probably fail. | ||
2997 | */ | ||
2998 | reset_drive(); | ||
2999 | retry_count = jiffies + SONY_RESET_TIMEOUT; | ||
3000 | while (time_before(jiffies, retry_count) | ||
3001 | && (!is_attention())) { | ||
3002 | sony_sleep(); | ||
3003 | } | ||
3004 | |||
3005 | #if 0 | ||
3006 | /* If attention is never seen probably not a CDU31a present */ | ||
3007 | if (!is_attention()) { | ||
3008 | res_reg[0] = 0x20; | ||
3009 | goto out_err; | ||
3010 | } | ||
3011 | #endif | ||
3012 | |||
3013 | /* | ||
3014 | * Get the drive configuration. | ||
3015 | */ | ||
3016 | do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD, | ||
3017 | NULL, | ||
3018 | 0, (unsigned char *) res_reg, res_size); | ||
3019 | if (*res_size <= 2 || (res_reg[0] & 0xf0) != 0) | ||
3020 | goto out_err; | ||
3021 | return 1; | ||
3022 | } | ||
3023 | |||
3024 | /* Return an error */ | ||
3025 | res_reg[0] = 0x20; | ||
3026 | out_err: | ||
3027 | release_region(cdu31a_port, 4); | ||
3028 | cdu31a_port = 0; | ||
3029 | return 0; | ||
3030 | } | ||
3031 | |||
3032 | #ifndef MODULE | ||
3033 | /* | ||
3034 | * Set up base I/O and interrupts, called from main.c. | ||
3035 | */ | ||
3036 | |||
3037 | static int __init cdu31a_setup(char *strings) | ||
3038 | { | ||
3039 | int ints[4]; | ||
3040 | |||
3041 | (void) get_options(strings, ARRAY_SIZE(ints), ints); | ||
3042 | |||
3043 | if (ints[0] > 0) { | ||
3044 | cdu31a_port = ints[1]; | ||
3045 | } | ||
3046 | if (ints[0] > 1) { | ||
3047 | cdu31a_irq = ints[2]; | ||
3048 | } | ||
3049 | if ((strings != NULL) && (*strings != '\0')) { | ||
3050 | if (strcmp(strings, "PAS") == 0) { | ||
3051 | sony_pas_init = 1; | ||
3052 | } else { | ||
3053 | printk(KERN_NOTICE PFX "Unknown interface type: %s\n", | ||
3054 | strings); | ||
3055 | } | ||
3056 | } | ||
3057 | |||
3058 | return 1; | ||
3059 | } | ||
3060 | |||
3061 | __setup("cdu31a=", cdu31a_setup); | ||
3062 | |||
3063 | #endif | ||
3064 | |||
3065 | /* | ||
3066 | * Initialize the driver. | ||
3067 | */ | ||
3068 | int __init cdu31a_init(void) | ||
3069 | { | ||
3070 | struct s_sony_drive_config drive_config; | ||
3071 | struct gendisk *disk; | ||
3072 | int deficiency = 0; | ||
3073 | unsigned int res_size; | ||
3074 | char msg[255]; | ||
3075 | char buf[40]; | ||
3076 | int i; | ||
3077 | int tmp_irq; | ||
3078 | |||
3079 | /* | ||
3080 | * According to Alex Freed (freed@europa.orion.adobe.com), this is | ||
3081 | * required for the Fusion CD-16 package. If the sound driver is | ||
3082 | * loaded, it should work fine, but just in case... | ||
3083 | * | ||
3084 | * The following turn on the CD-ROM interface for a Fusion CD-16. | ||
3085 | */ | ||
3086 | if (sony_pas_init) { | ||
3087 | outb(0xbc, 0x9a01); | ||
3088 | outb(0xe2, 0x9a01); | ||
3089 | } | ||
3090 | |||
3091 | /* Setting the base I/O address to 0xffff will disable it. */ | ||
3092 | if (cdu31a_port == 0xffff) | ||
3093 | goto errout3; | ||
3094 | |||
3095 | if (cdu31a_port != 0) { | ||
3096 | /* Need IRQ 0 because we can't sleep here. */ | ||
3097 | tmp_irq = cdu31a_irq; | ||
3098 | cdu31a_irq = 0; | ||
3099 | if (!get_drive_configuration(cdu31a_port, | ||
3100 | drive_config.exec_status, | ||
3101 | &res_size)) | ||
3102 | goto errout3; | ||
3103 | cdu31a_irq = tmp_irq; | ||
3104 | } else { | ||
3105 | cdu31a_irq = 0; | ||
3106 | for (i = 0; cdu31a_addresses[i].base; i++) { | ||
3107 | if (get_drive_configuration(cdu31a_addresses[i].base, | ||
3108 | drive_config.exec_status, | ||
3109 | &res_size)) { | ||
3110 | cdu31a_irq = cdu31a_addresses[i].int_num; | ||
3111 | break; | ||
3112 | } | ||
3113 | } | ||
3114 | if (!cdu31a_port) | ||
3115 | goto errout3; | ||
3116 | } | ||
3117 | |||
3118 | if (register_blkdev(MAJOR_NR, "cdu31a")) | ||
3119 | goto errout2; | ||
3120 | |||
3121 | disk = alloc_disk(1); | ||
3122 | if (!disk) | ||
3123 | goto errout1; | ||
3124 | disk->major = MAJOR_NR; | ||
3125 | disk->first_minor = 0; | ||
3126 | sprintf(disk->disk_name, "cdu31a"); | ||
3127 | disk->fops = &scd_bdops; | ||
3128 | disk->flags = GENHD_FL_CD; | ||
3129 | |||
3130 | if (SONY_HWC_DOUBLE_SPEED(drive_config)) | ||
3131 | is_double_speed = 1; | ||
3132 | |||
3133 | tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */ | ||
3134 | cdu31a_irq = 0; | ||
3135 | |||
3136 | sony_speed = is_double_speed; /* Set 2X drives to 2X by default */ | ||
3137 | set_drive_params(sony_speed); | ||
3138 | |||
3139 | cdu31a_irq = tmp_irq; | ||
3140 | |||
3141 | if (cdu31a_irq > 0) { | ||
3142 | if (request_irq | ||
3143 | (cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT, | ||
3144 | "cdu31a", NULL)) { | ||
3145 | printk(KERN_WARNING PFX "Unable to grab IRQ%d for " | ||
3146 | "the CDU31A driver\n", cdu31a_irq); | ||
3147 | cdu31a_irq = 0; | ||
3148 | } | ||
3149 | } | ||
3150 | |||
3151 | sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n", | ||
3152 | drive_config.vendor_id, | ||
3153 | drive_config.product_id, | ||
3154 | drive_config.product_rev_level); | ||
3155 | sprintf(buf, " Capabilities: %s", | ||
3156 | load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]); | ||
3157 | strcat(msg, buf); | ||
3158 | if (SONY_HWC_AUDIO_PLAYBACK(drive_config)) | ||
3159 | strcat(msg, ", audio"); | ||
3160 | else | ||
3161 | deficiency |= CDC_PLAY_AUDIO; | ||
3162 | if (SONY_HWC_EJECT(drive_config)) | ||
3163 | strcat(msg, ", eject"); | ||
3164 | else | ||
3165 | deficiency |= CDC_OPEN_TRAY; | ||
3166 | if (SONY_HWC_LED_SUPPORT(drive_config)) | ||
3167 | strcat(msg, ", LED"); | ||
3168 | if (SONY_HWC_ELECTRIC_VOLUME(drive_config)) | ||
3169 | strcat(msg, ", elec. Vol"); | ||
3170 | if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config)) | ||
3171 | strcat(msg, ", sep. Vol"); | ||
3172 | if (is_double_speed) | ||
3173 | strcat(msg, ", double speed"); | ||
3174 | else | ||
3175 | deficiency |= CDC_SELECT_SPEED; | ||
3176 | if (cdu31a_irq > 0) { | ||
3177 | sprintf(buf, ", irq %d", cdu31a_irq); | ||
3178 | strcat(msg, buf); | ||
3179 | } | ||
3180 | strcat(msg, "\n"); | ||
3181 | printk(KERN_INFO PFX "%s",msg); | ||
3182 | |||
3183 | cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock); | ||
3184 | if (!cdu31a_queue) | ||
3185 | goto errout0; | ||
3186 | blk_queue_hardsect_size(cdu31a_queue, 2048); | ||
3187 | |||
3188 | init_timer(&cdu31a_abort_timer); | ||
3189 | cdu31a_abort_timer.function = handle_abort_timeout; | ||
3190 | |||
3191 | scd_info.mask = deficiency; | ||
3192 | scd_gendisk = disk; | ||
3193 | if (register_cdrom(&scd_info)) | ||
3194 | goto err; | ||
3195 | disk->queue = cdu31a_queue; | ||
3196 | add_disk(disk); | ||
3197 | |||
3198 | disk_changed = 1; | ||
3199 | return 0; | ||
3200 | |||
3201 | err: | ||
3202 | blk_cleanup_queue(cdu31a_queue); | ||
3203 | errout0: | ||
3204 | if (cdu31a_irq) | ||
3205 | free_irq(cdu31a_irq, NULL); | ||
3206 | printk(KERN_ERR PFX "Unable to register with Uniform cdrom driver\n"); | ||
3207 | put_disk(disk); | ||
3208 | errout1: | ||
3209 | if (unregister_blkdev(MAJOR_NR, "cdu31a")) { | ||
3210 | printk(KERN_WARNING PFX "Can't unregister block device\n"); | ||
3211 | } | ||
3212 | errout2: | ||
3213 | release_region(cdu31a_port, 4); | ||
3214 | errout3: | ||
3215 | return -EIO; | ||
3216 | } | ||
3217 | |||
3218 | |||
3219 | void __exit cdu31a_exit(void) | ||
3220 | { | ||
3221 | del_gendisk(scd_gendisk); | ||
3222 | put_disk(scd_gendisk); | ||
3223 | if (unregister_cdrom(&scd_info)) { | ||
3224 | printk(KERN_WARNING PFX "Can't unregister from Uniform " | ||
3225 | "cdrom driver\n"); | ||
3226 | return; | ||
3227 | } | ||
3228 | if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) { | ||
3229 | printk(KERN_WARNING PFX "Can't unregister\n"); | ||
3230 | return; | ||
3231 | } | ||
3232 | |||
3233 | blk_cleanup_queue(cdu31a_queue); | ||
3234 | |||
3235 | if (cdu31a_irq > 0) | ||
3236 | free_irq(cdu31a_irq, NULL); | ||
3237 | |||
3238 | release_region(cdu31a_port, 4); | ||
3239 | printk(KERN_INFO PFX "module released.\n"); | ||
3240 | } | ||
3241 | |||
3242 | #ifdef MODULE | ||
3243 | module_init(cdu31a_init); | ||
3244 | #endif | ||
3245 | module_exit(cdu31a_exit); | ||
3246 | |||
3247 | MODULE_LICENSE("GPL"); | ||
3248 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU31A_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/cdu31a.h b/drivers/cdrom/cdu31a.h new file mode 100644 index 000000000000..61d4768c412e --- /dev/null +++ b/drivers/cdrom/cdu31a.h | |||
@@ -0,0 +1,411 @@ | |||
1 | /* | ||
2 | * Definitions for a Sony interface CDROM drive. | ||
3 | * | ||
4 | * Corey Minyard (minyard@wf-rch.cirr.com) | ||
5 | * | ||
6 | * Copyright (C) 1993 Corey Minyard | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * General defines. | ||
26 | */ | ||
27 | #define SONY_XA_DISK_TYPE 0x20 | ||
28 | |||
29 | /* | ||
30 | * Offsets (from the base address) and bits for the various write registers | ||
31 | * of the drive. | ||
32 | */ | ||
33 | #define SONY_CMD_REG_OFFSET 0 | ||
34 | #define SONY_PARAM_REG_OFFSET 1 | ||
35 | #define SONY_WRITE_REG_OFFSET 2 | ||
36 | #define SONY_CONTROL_REG_OFFSET 3 | ||
37 | # define SONY_ATTN_CLR_BIT 0x01 | ||
38 | # define SONY_RES_RDY_CLR_BIT 0x02 | ||
39 | # define SONY_DATA_RDY_CLR_BIT 0x04 | ||
40 | # define SONY_ATTN_INT_EN_BIT 0x08 | ||
41 | # define SONY_RES_RDY_INT_EN_BIT 0x10 | ||
42 | # define SONY_DATA_RDY_INT_EN_BIT 0x20 | ||
43 | # define SONY_PARAM_CLR_BIT 0x40 | ||
44 | # define SONY_DRIVE_RESET_BIT 0x80 | ||
45 | |||
46 | /* | ||
47 | * Offsets (from the base address) and bits for the various read registers | ||
48 | * of the drive. | ||
49 | */ | ||
50 | #define SONY_STATUS_REG_OFFSET 0 | ||
51 | # define SONY_ATTN_BIT 0x01 | ||
52 | # define SONY_RES_RDY_BIT 0x02 | ||
53 | # define SONY_DATA_RDY_BIT 0x04 | ||
54 | # define SONY_ATTN_INT_ST_BIT 0x08 | ||
55 | # define SONY_RES_RDY_INT_ST_BIT 0x10 | ||
56 | # define SONY_DATA_RDY_INT_ST_BIT 0x20 | ||
57 | # define SONY_DATA_REQUEST_BIT 0x40 | ||
58 | # define SONY_BUSY_BIT 0x80 | ||
59 | #define SONY_RESULT_REG_OFFSET 1 | ||
60 | #define SONY_READ_REG_OFFSET 2 | ||
61 | #define SONY_FIFOST_REG_OFFSET 3 | ||
62 | # define SONY_PARAM_WRITE_RDY_BIT 0x01 | ||
63 | # define SONY_PARAM_REG_EMPTY_BIT 0x02 | ||
64 | # define SONY_RES_REG_NOT_EMP_BIT 0x04 | ||
65 | # define SONY_RES_REG_FULL_BIT 0x08 | ||
66 | |||
67 | #define LOG_START_OFFSET 150 /* Offset of first logical sector */ | ||
68 | |||
69 | #define SONY_DETECT_TIMEOUT (8*HZ/10) /* Maximum amount of time | ||
70 | that drive detection code | ||
71 | will wait for response | ||
72 | from drive (in 1/100th's | ||
73 | of seconds). */ | ||
74 | |||
75 | #define SONY_JIFFIES_TIMEOUT (10*HZ) /* Maximum number of times the | ||
76 | drive will wait/try for an | ||
77 | operation */ | ||
78 | #define SONY_RESET_TIMEOUT HZ /* Maximum number of times the | ||
79 | drive will wait/try a reset | ||
80 | operation */ | ||
81 | #define SONY_READY_RETRIES 20000 /* How many times to retry a | ||
82 | spin waiting for a register | ||
83 | to come ready */ | ||
84 | |||
85 | #define MAX_CDU31A_RETRIES 3 /* How many times to retry an | ||
86 | operation */ | ||
87 | |||
88 | /* Commands to request or set drive control parameters and disc information */ | ||
89 | #define SONY_REQ_DRIVE_CONFIG_CMD 0x00 /* Returns s_sony_drive_config */ | ||
90 | #define SONY_REQ_DRIVE_MODE_CMD 0x01 | ||
91 | #define SONY_REQ_DRIVE_PARAM_CMD 0x02 | ||
92 | #define SONY_REQ_MECH_STATUS_CMD 0x03 | ||
93 | #define SONY_REQ_AUDIO_STATUS_CMD 0x04 | ||
94 | #define SONY_SET_DRIVE_PARAM_CMD 0x10 | ||
95 | #define SONY_REQ_TOC_DATA_CMD 0x20 /* Returns s_sony_toc */ | ||
96 | #define SONY_REQ_SUBCODE_ADDRESS_CMD 0x21 /* Returns s_sony_subcode */ | ||
97 | #define SONY_REQ_UPC_EAN_CMD 0x22 | ||
98 | #define SONY_REQ_ISRC_CMD 0x23 | ||
99 | #define SONY_REQ_TOC_DATA_SPEC_CMD 0x24 /* Returns s_sony_session_toc */ | ||
100 | |||
101 | /* Commands to request information from the drive */ | ||
102 | #define SONY_READ_TOC_CMD 0x30 /* let the drive firmware grab the TOC */ | ||
103 | #define SONY_SEEK_CMD 0x31 | ||
104 | #define SONY_READ_CMD 0x32 | ||
105 | #define SONY_READ_BLKERR_STAT_CMD 0x34 | ||
106 | #define SONY_ABORT_CMD 0x35 | ||
107 | #define SONY_READ_TOC_SPEC_CMD 0x36 | ||
108 | |||
109 | /* Commands to control audio */ | ||
110 | #define SONY_AUDIO_PLAYBACK_CMD 0x40 | ||
111 | #define SONY_AUDIO_STOP_CMD 0x41 | ||
112 | #define SONY_AUDIO_SCAN_CMD 0x42 | ||
113 | |||
114 | /* Miscellaneous control commands */ | ||
115 | #define SONY_EJECT_CMD 0x50 | ||
116 | #define SONY_SPIN_UP_CMD 0x51 | ||
117 | #define SONY_SPIN_DOWN_CMD 0x52 | ||
118 | |||
119 | /* Diagnostic commands */ | ||
120 | #define SONY_WRITE_BUFFER_CMD 0x60 | ||
121 | #define SONY_READ_BUFFER_CMD 0x61 | ||
122 | #define SONY_DIAGNOSTICS_CMD 0x62 | ||
123 | |||
124 | |||
125 | /* | ||
126 | * The following are command parameters for the set drive parameter command | ||
127 | */ | ||
128 | #define SONY_SD_DECODE_PARAM 0x00 | ||
129 | #define SONY_SD_INTERFACE_PARAM 0x01 | ||
130 | #define SONY_SD_BUFFERING_PARAM 0x02 | ||
131 | #define SONY_SD_AUDIO_PARAM 0x03 | ||
132 | #define SONY_SD_AUDIO_VOLUME 0x04 | ||
133 | #define SONY_SD_MECH_CONTROL 0x05 | ||
134 | #define SONY_SD_AUTO_SPIN_DOWN_TIME 0x06 | ||
135 | |||
136 | /* | ||
137 | * The following are parameter bits for the mechanical control command | ||
138 | */ | ||
139 | #define SONY_AUTO_SPIN_UP_BIT 0x01 | ||
140 | #define SONY_AUTO_EJECT_BIT 0x02 | ||
141 | #define SONY_DOUBLE_SPEED_BIT 0x04 | ||
142 | |||
143 | /* | ||
144 | * The following extract information from the drive configuration about | ||
145 | * the drive itself. | ||
146 | */ | ||
147 | #define SONY_HWC_GET_LOAD_MECH(c) (c.hw_config[0] & 0x03) | ||
148 | #define SONY_HWC_EJECT(c) (c.hw_config[0] & 0x04) | ||
149 | #define SONY_HWC_LED_SUPPORT(c) (c.hw_config[0] & 0x08) | ||
150 | #define SONY_HWC_DOUBLE_SPEED(c) (c.hw_config[0] & 0x10) | ||
151 | #define SONY_HWC_GET_BUF_MEM_SIZE(c) ((c.hw_config[0] & 0xc0) >> 6) | ||
152 | #define SONY_HWC_AUDIO_PLAYBACK(c) (c.hw_config[1] & 0x01) | ||
153 | #define SONY_HWC_ELECTRIC_VOLUME(c) (c.hw_config[1] & 0x02) | ||
154 | #define SONY_HWC_ELECTRIC_VOLUME_CTL(c) (c.hw_config[1] & 0x04) | ||
155 | |||
156 | #define SONY_HWC_CADDY_LOAD_MECH 0x00 | ||
157 | #define SONY_HWC_TRAY_LOAD_MECH 0x01 | ||
158 | #define SONY_HWC_POPUP_LOAD_MECH 0x02 | ||
159 | #define SONY_HWC_UNKWN_LOAD_MECH 0x03 | ||
160 | |||
161 | #define SONY_HWC_8KB_BUFFER 0x00 | ||
162 | #define SONY_HWC_32KB_BUFFER 0x01 | ||
163 | #define SONY_HWC_64KB_BUFFER 0x02 | ||
164 | #define SONY_HWC_UNKWN_BUFFER 0x03 | ||
165 | |||
166 | /* | ||
167 | * This is the complete status returned from the drive configuration request | ||
168 | * command. | ||
169 | */ | ||
170 | struct s_sony_drive_config | ||
171 | { | ||
172 | unsigned char exec_status[2]; | ||
173 | char vendor_id[8]; | ||
174 | char product_id[16]; | ||
175 | char product_rev_level[8]; | ||
176 | unsigned char hw_config[2]; | ||
177 | }; | ||
178 | |||
179 | /* The following is returned from the request subcode address command */ | ||
180 | struct s_sony_subcode | ||
181 | { | ||
182 | unsigned char exec_status[2]; | ||
183 | unsigned char address :4; | ||
184 | unsigned char control :4; | ||
185 | unsigned char track_num; | ||
186 | unsigned char index_num; | ||
187 | unsigned char rel_msf[3]; | ||
188 | unsigned char reserved1; | ||
189 | unsigned char abs_msf[3]; | ||
190 | }; | ||
191 | |||
192 | #define MAX_TRACKS 100 /* The maximum tracks a disk may have. */ | ||
193 | /* | ||
194 | * The following is returned from the request TOC (Table Of Contents) command. | ||
195 | * (last_track_num-first_track_num+1) values are valid in tracks. | ||
196 | */ | ||
197 | struct s_sony_toc | ||
198 | { | ||
199 | unsigned char exec_status[2]; | ||
200 | unsigned char address0 :4; | ||
201 | unsigned char control0 :4; | ||
202 | unsigned char point0; | ||
203 | unsigned char first_track_num; | ||
204 | unsigned char disk_type; | ||
205 | unsigned char dummy0; | ||
206 | unsigned char address1 :4; | ||
207 | unsigned char control1 :4; | ||
208 | unsigned char point1; | ||
209 | unsigned char last_track_num; | ||
210 | unsigned char dummy1; | ||
211 | unsigned char dummy2; | ||
212 | unsigned char address2 :4; | ||
213 | unsigned char control2 :4; | ||
214 | unsigned char point2; | ||
215 | unsigned char lead_out_start_msf[3]; | ||
216 | struct | ||
217 | { | ||
218 | unsigned char address :4; | ||
219 | unsigned char control :4; | ||
220 | unsigned char track; | ||
221 | unsigned char track_start_msf[3]; | ||
222 | } tracks[MAX_TRACKS]; | ||
223 | |||
224 | unsigned int lead_out_start_lba; | ||
225 | }; | ||
226 | |||
227 | struct s_sony_session_toc | ||
228 | { | ||
229 | unsigned char exec_status[2]; | ||
230 | unsigned char session_number; | ||
231 | unsigned char address0 :4; | ||
232 | unsigned char control0 :4; | ||
233 | unsigned char point0; | ||
234 | unsigned char first_track_num; | ||
235 | unsigned char disk_type; | ||
236 | unsigned char dummy0; | ||
237 | unsigned char address1 :4; | ||
238 | unsigned char control1 :4; | ||
239 | unsigned char point1; | ||
240 | unsigned char last_track_num; | ||
241 | unsigned char dummy1; | ||
242 | unsigned char dummy2; | ||
243 | unsigned char address2 :4; | ||
244 | unsigned char control2 :4; | ||
245 | unsigned char point2; | ||
246 | unsigned char lead_out_start_msf[3]; | ||
247 | unsigned char addressb0 :4; | ||
248 | unsigned char controlb0 :4; | ||
249 | unsigned char pointb0; | ||
250 | unsigned char next_poss_prog_area_msf[3]; | ||
251 | unsigned char num_mode_5_pointers; | ||
252 | unsigned char max_start_outer_leadout_msf[3]; | ||
253 | unsigned char addressb1 :4; | ||
254 | unsigned char controlb1 :4; | ||
255 | unsigned char pointb1; | ||
256 | unsigned char dummyb0_1[4]; | ||
257 | unsigned char num_skip_interval_pointers; | ||
258 | unsigned char num_skip_track_assignments; | ||
259 | unsigned char dummyb0_2; | ||
260 | unsigned char addressb2 :4; | ||
261 | unsigned char controlb2 :4; | ||
262 | unsigned char pointb2; | ||
263 | unsigned char tracksb2[7]; | ||
264 | unsigned char addressb3 :4; | ||
265 | unsigned char controlb3 :4; | ||
266 | unsigned char pointb3; | ||
267 | unsigned char tracksb3[7]; | ||
268 | unsigned char addressb4 :4; | ||
269 | unsigned char controlb4 :4; | ||
270 | unsigned char pointb4; | ||
271 | unsigned char tracksb4[7]; | ||
272 | unsigned char addressc0 :4; | ||
273 | unsigned char controlc0 :4; | ||
274 | unsigned char pointc0; | ||
275 | unsigned char dummyc0[7]; | ||
276 | struct | ||
277 | { | ||
278 | unsigned char address :4; | ||
279 | unsigned char control :4; | ||
280 | unsigned char track; | ||
281 | unsigned char track_start_msf[3]; | ||
282 | } tracks[MAX_TRACKS]; | ||
283 | |||
284 | unsigned int start_track_lba; | ||
285 | unsigned int lead_out_start_lba; | ||
286 | unsigned int mint; | ||
287 | unsigned int maxt; | ||
288 | }; | ||
289 | |||
290 | struct s_all_sessions_toc | ||
291 | { | ||
292 | unsigned char sessions; | ||
293 | unsigned int track_entries; | ||
294 | unsigned char first_track_num; | ||
295 | unsigned char last_track_num; | ||
296 | unsigned char disk_type; | ||
297 | unsigned char lead_out_start_msf[3]; | ||
298 | struct | ||
299 | { | ||
300 | unsigned char address :4; | ||
301 | unsigned char control :4; | ||
302 | unsigned char track; | ||
303 | unsigned char track_start_msf[3]; | ||
304 | } tracks[MAX_TRACKS]; | ||
305 | |||
306 | unsigned int start_track_lba; | ||
307 | unsigned int lead_out_start_lba; | ||
308 | }; | ||
309 | |||
310 | |||
311 | /* | ||
312 | * The following are errors returned from the drive. | ||
313 | */ | ||
314 | |||
315 | /* Command error group */ | ||
316 | #define SONY_ILL_CMD_ERR 0x10 | ||
317 | #define SONY_ILL_PARAM_ERR 0x11 | ||
318 | |||
319 | /* Mechanism group */ | ||
320 | #define SONY_NOT_LOAD_ERR 0x20 | ||
321 | #define SONY_NO_DISK_ERR 0x21 | ||
322 | #define SONY_NOT_SPIN_ERR 0x22 | ||
323 | #define SONY_SPIN_ERR 0x23 | ||
324 | #define SONY_SPINDLE_SERVO_ERR 0x25 | ||
325 | #define SONY_FOCUS_SERVO_ERR 0x26 | ||
326 | #define SONY_EJECT_MECH_ERR 0x29 | ||
327 | #define SONY_AUDIO_PLAYING_ERR 0x2a | ||
328 | #define SONY_EMERGENCY_EJECT_ERR 0x2c | ||
329 | |||
330 | /* Seek error group */ | ||
331 | #define SONY_FOCUS_ERR 0x30 | ||
332 | #define SONY_FRAME_SYNC_ERR 0x31 | ||
333 | #define SONY_SUBCODE_ADDR_ERR 0x32 | ||
334 | #define SONY_BLOCK_SYNC_ERR 0x33 | ||
335 | #define SONY_HEADER_ADDR_ERR 0x34 | ||
336 | |||
337 | /* Read error group */ | ||
338 | #define SONY_ILL_TRACK_R_ERR 0x40 | ||
339 | #define SONY_MODE_0_R_ERR 0x41 | ||
340 | #define SONY_ILL_MODE_R_ERR 0x42 | ||
341 | #define SONY_ILL_BLOCK_SIZE_R_ERR 0x43 | ||
342 | #define SONY_MODE_R_ERR 0x44 | ||
343 | #define SONY_FORM_R_ERR 0x45 | ||
344 | #define SONY_LEAD_OUT_R_ERR 0x46 | ||
345 | #define SONY_BUFFER_OVERRUN_R_ERR 0x47 | ||
346 | |||
347 | /* Data error group */ | ||
348 | #define SONY_UNREC_CIRC_ERR 0x53 | ||
349 | #define SONY_UNREC_LECC_ERR 0x57 | ||
350 | |||
351 | /* Subcode error group */ | ||
352 | #define SONY_NO_TOC_ERR 0x60 | ||
353 | #define SONY_SUBCODE_DATA_NVAL_ERR 0x61 | ||
354 | #define SONY_FOCUS_ON_TOC_READ_ERR 0x63 | ||
355 | #define SONY_FRAME_SYNC_ON_TOC_READ_ERR 0x64 | ||
356 | #define SONY_TOC_DATA_ERR 0x65 | ||
357 | |||
358 | /* Hardware failure group */ | ||
359 | #define SONY_HW_FAILURE_ERR 0x70 | ||
360 | #define SONY_LEAD_IN_A_ERR 0x91 | ||
361 | #define SONY_LEAD_OUT_A_ERR 0x92 | ||
362 | #define SONY_DATA_TRACK_A_ERR 0x93 | ||
363 | |||
364 | /* | ||
365 | * The following are returned from the Read With Block Error Status command. | ||
366 | * They are not errors but information (Errors from the 0x5x group above may | ||
367 | * also be returned | ||
368 | */ | ||
369 | #define SONY_NO_CIRC_ERR_BLK_STAT 0x50 | ||
370 | #define SONY_NO_LECC_ERR_BLK_STAT 0x54 | ||
371 | #define SONY_RECOV_LECC_ERR_BLK_STAT 0x55 | ||
372 | #define SONY_NO_ERR_DETECTION_STAT 0x59 | ||
373 | |||
374 | /* | ||
375 | * The following is not an error returned by the drive, but by the code | ||
376 | * that talks to the drive. It is returned because of a timeout. | ||
377 | */ | ||
378 | #define SONY_TIMEOUT_OP_ERR 0x01 | ||
379 | #define SONY_SIGNAL_OP_ERR 0x02 | ||
380 | #define SONY_BAD_DATA_ERR 0x03 | ||
381 | |||
382 | |||
383 | /* | ||
384 | * The following are attention code for asynchronous events from the drive. | ||
385 | */ | ||
386 | |||
387 | /* Standard attention group */ | ||
388 | #define SONY_EMER_EJECT_ATTN 0x2c | ||
389 | #define SONY_HW_FAILURE_ATTN 0x70 | ||
390 | #define SONY_MECH_LOADED_ATTN 0x80 | ||
391 | #define SONY_EJECT_PUSHED_ATTN 0x81 | ||
392 | |||
393 | /* Audio attention group */ | ||
394 | #define SONY_AUDIO_PLAY_DONE_ATTN 0x90 | ||
395 | #define SONY_LEAD_IN_ERR_ATTN 0x91 | ||
396 | #define SONY_LEAD_OUT_ERR_ATTN 0x92 | ||
397 | #define SONY_DATA_TRACK_ERR_ATTN 0x93 | ||
398 | #define SONY_AUDIO_PLAYBACK_ERR_ATTN 0x94 | ||
399 | |||
400 | /* Auto spin up group */ | ||
401 | #define SONY_SPIN_UP_COMPLETE_ATTN 0x24 | ||
402 | #define SONY_SPINDLE_SERVO_ERR_ATTN 0x25 | ||
403 | #define SONY_FOCUS_SERVO_ERR_ATTN 0x26 | ||
404 | #define SONY_TOC_READ_DONE_ATTN 0x62 | ||
405 | #define SONY_FOCUS_ON_TOC_READ_ERR_ATTN 0x63 | ||
406 | #define SONY_SYNC_ON_TOC_READ_ERR_ATTN 0x65 | ||
407 | |||
408 | /* Auto eject group */ | ||
409 | #define SONY_SPIN_DOWN_COMPLETE_ATTN 0x27 | ||
410 | #define SONY_EJECT_COMPLETE_ATTN 0x28 | ||
411 | #define SONY_EJECT_MECH_ERR_ATTN 0x29 | ||
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c new file mode 100644 index 000000000000..da80b14335a5 --- /dev/null +++ b/drivers/cdrom/cm206.c | |||
@@ -0,0 +1,1626 @@ | |||
1 | /* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card. | ||
2 | Copyright (c) 1995--1997 David A. van Leeuwen. | ||
3 | $Id: cm206.c,v 1.5 1997/12/26 11:02:51 david Exp $ | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program 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 | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | |||
19 | History: | ||
20 | Started 25 jan 1994. Waiting for documentation... | ||
21 | 22 feb 1995: 0.1a first reasonably safe polling driver. | ||
22 | Two major bugs, one in read_sector and one in | ||
23 | do_cm206_request, happened to cancel! | ||
24 | 25 feb 1995: 0.2a first reasonable interrupt driven version of above. | ||
25 | uart writes are still done in polling mode. | ||
26 | 25 feb 1995: 0.21a writes also in interrupt mode, still some | ||
27 | small bugs to be found... Larger buffer. | ||
28 | 2 mrt 1995: 0.22 Bug found (cd-> nowhere, interrupt was called in | ||
29 | initialization), read_ahead of 16. Timeouts implemented. | ||
30 | unclear if they do something... | ||
31 | 7 mrt 1995: 0.23 Start of background read-ahead. | ||
32 | 18 mrt 1995: 0.24 Working background read-ahead. (still problems) | ||
33 | 26 mrt 1995: 0.25 Multi-session ioctl added (kernel v1.2). | ||
34 | Statistics implemented, though separate stats206.h. | ||
35 | Accessible trough ioctl 0x1000 (just a number). | ||
36 | Hard to choose between v1.2 development and 1.1.75. | ||
37 | Bottom-half doesn't work with 1.2... | ||
38 | 0.25a: fixed... typo. Still problems... | ||
39 | 1 apr 1995: 0.26 Module support added. Most bugs found. Use kernel 1.2.n. | ||
40 | 5 apr 1995: 0.27 Auto-probe for the adapter card base address. | ||
41 | Auto-probe for the adaptor card irq line. | ||
42 | 7 apr 1995: 0.28 Added lilo setup support for base address and irq. | ||
43 | Use major number 32 (not in this source), officially | ||
44 | assigned to this driver. | ||
45 | 9 apr 1995: 0.29 Added very limited audio support. Toc_header, stop, pause, | ||
46 | resume, eject. Play_track ignores track info, because we can't | ||
47 | read a table-of-contents entry. Toc_entry is implemented | ||
48 | as a `placebo' function: always returns start of disc. | ||
49 | 3 may 1995: 0.30 Audio support completed. The get_toc_entry function | ||
50 | is implemented as a binary search. | ||
51 | 15 may 1995: 0.31 More work on audio stuff. Workman is not easy to | ||
52 | satisfy; changed binary search into linear search. | ||
53 | Auto-probe for base address somewhat relaxed. | ||
54 | 1 jun 1995: 0.32 Removed probe_irq_on/off for module version. | ||
55 | 10 jun 1995: 0.33 Workman still behaves funny, but you should be | ||
56 | able to eject and substitute another disc. | ||
57 | |||
58 | An adaptation of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg | ||
59 | |||
60 | 18 jul 1995: 0.34 Patch by Heiko Eissfeldt included, mainly considering | ||
61 | verify_area's in the ioctls. Some bugs introduced by | ||
62 | EM considering the base port and irq fixed. | ||
63 | |||
64 | 18 dec 1995: 0.35 Add some code for error checking... no luck... | ||
65 | |||
66 | We jump to reach our goal: version 1.0 in the next stable linux kernel. | ||
67 | |||
68 | 19 mar 1996: 0.95 Different implementation of CDROM_GET_UPC, on | ||
69 | request of Thomas Quinot. | ||
70 | 25 mar 1996: 0.96 Interpretation of opening with O_WRONLY or O_RDWR: | ||
71 | open only for ioctl operation, e.g., for operation of | ||
72 | tray etc. | ||
73 | 4 apr 1996: 0.97 First implementation of layer between VFS and cdrom | ||
74 | driver, a generic interface. Much of the functionality | ||
75 | of cm206_open() and cm206_ioctl() is transferred to a | ||
76 | new file cdrom.c and its header ucdrom.h. | ||
77 | |||
78 | Upgrade to Linux kernel 1.3.78. | ||
79 | |||
80 | 11 apr 1996 0.98 Upgrade to Linux kernel 1.3.85 | ||
81 | More code moved to cdrom.c | ||
82 | |||
83 | 0.99 Some more small changes to decrease number | ||
84 | of oopses at module load; | ||
85 | |||
86 | 27 jul 1996 0.100 Many hours of debugging, kernel change from 1.2.13 | ||
87 | to 2.0.7 seems to have introduced some weird behavior | ||
88 | in (interruptible_)sleep_on(&cd->data): the process | ||
89 | seems to be woken without any explicit wake_up in my own | ||
90 | code. Patch to try 100x in case such untriggered wake_up's | ||
91 | occur. | ||
92 | |||
93 | 28 jul 1996 0.101 Rewriting of the code that receives the command echo, | ||
94 | using a fifo to store echoed bytes. | ||
95 | |||
96 | Branch from 0.99: | ||
97 | |||
98 | 0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t | ||
99 | (emoenke) various typos found by others. extra | ||
100 | module-load oops protection. | ||
101 | |||
102 | 0.99.1.1 Initialization constant cdrom_dops.speed | ||
103 | changed from float (2.0) to int (2); Cli()-sti() pair | ||
104 | around cm260_reset() in module initialization code. | ||
105 | |||
106 | 0.99.1.2 Changes literally as proposed by Scott Snyder | ||
107 | <snyder@d0sgif.fnal.gov> for the 2.1 kernel line, which | ||
108 | have to do mainly with the poor minor support i had. The | ||
109 | major new concept is to change a cdrom driver's | ||
110 | operations struct from the capabilities struct. This | ||
111 | reflects the fact that there is one major for a driver, | ||
112 | whilst there can be many minors whith completely | ||
113 | different capabilities. | ||
114 | |||
115 | 0.99.1.3 More changes for operations/info separation. | ||
116 | |||
117 | 0.99.1.4 Added speed selection (someone had to do this | ||
118 | first). | ||
119 | |||
120 | 23 jan 1997 0.99.1.5 MODULE_PARMS call added. | ||
121 | |||
122 | 23 jan 1997 0.100.1.2--0.100.1.5 following similar lines as | ||
123 | 0.99.1.1--0.99.1.5. I get too many complaints about the | ||
124 | drive making read errors. What't wrong with the 2.0+ | ||
125 | kernel line? Why get i (and othe cm206 owners) weird | ||
126 | results? Why were things good in the good old 1.1--1.2 | ||
127 | era? Why don't i throw away the drive? | ||
128 | |||
129 | 2 feb 1997 0.102 Added `volatile' to values in cm206_struct. Seems to | ||
130 | reduce many of the problems. Rewrote polling routines | ||
131 | to use fixed delays between polls. | ||
132 | 0.103 Changed printk behavior. | ||
133 | 0.104 Added a 0.100 -> 0.100.1.1 change | ||
134 | |||
135 | 11 feb 1997 0.105 Allow auto_probe during module load, disable | ||
136 | with module option "auto_probe=0". Moved some debugging | ||
137 | statements to lower priority. Implemented select_speed() | ||
138 | function. | ||
139 | |||
140 | 13 feb 1997 1.0 Final version for 2.0 kernel line. | ||
141 | |||
142 | All following changes will be for the 2.1 kernel line. | ||
143 | |||
144 | 15 feb 1997 1.1 Keep up with kernel 2.1.26, merge in changes from | ||
145 | cdrom.c 0.100.1.1--1.0. Add some more MODULE_PARMS. | ||
146 | |||
147 | 14 sep 1997 1.2 Upgrade to Linux 2.1.55. Added blksize_size[], patch | ||
148 | sent by James Bottomley <James.Bottomley@columbiasc.ncr.com>. | ||
149 | |||
150 | 21 dec 1997 1.4 Upgrade to Linux 2.1.72. | ||
151 | |||
152 | 24 jan 1998 Removed the cm206_disc_status() function, as it was now dead | ||
153 | code. The Uniform CDROM driver now provides this functionality. | ||
154 | |||
155 | 9 Nov. 1999 Make kernel-parameter implementation work with 2.3.x | ||
156 | Removed init_module & cleanup_module in favor of | ||
157 | module_init & module_exit. | ||
158 | Torben Mathiasen <tmm@image.dk> | ||
159 | * | ||
160 | * Parts of the code are based upon lmscd.c written by Kai Petzke, | ||
161 | * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin | ||
162 | * Harriss, but any off-the-shelf dynamic programming algorithm won't | ||
163 | * be able to find them. | ||
164 | * | ||
165 | * The cm206 drive interface and the cm260 adapter card seem to be | ||
166 | * sufficiently different from their cm205/cm250 counterparts | ||
167 | * in order to write a complete new driver. | ||
168 | * | ||
169 | * I call all routines connected to the Linux kernel something | ||
170 | * with `cm206' in it, as this stuff is too series-dependent. | ||
171 | * | ||
172 | * Currently, my limited knowledge is based on: | ||
173 | * - The Linux Kernel Hacker's guide, v. 0.5, by Michael K. Johnson | ||
174 | * - Linux Kernel Programmierung, by Michael Beck and others | ||
175 | * - Philips/LMS cm206 and cm226 product specification | ||
176 | * - Philips/LMS cm260 product specification | ||
177 | * | ||
178 | * David van Leeuwen, david@tm.tno.nl. */ | ||
179 | #define REVISION "$Revision: 1.5 $" | ||
180 | |||
181 | #include <linux/module.h> | ||
182 | |||
183 | #include <linux/errno.h> /* These include what we really need */ | ||
184 | #include <linux/delay.h> | ||
185 | #include <linux/string.h> | ||
186 | #include <linux/sched.h> | ||
187 | #include <linux/interrupt.h> | ||
188 | #include <linux/timer.h> | ||
189 | #include <linux/cdrom.h> | ||
190 | #include <linux/devfs_fs_kernel.h> | ||
191 | #include <linux/ioport.h> | ||
192 | #include <linux/mm.h> | ||
193 | #include <linux/slab.h> | ||
194 | #include <linux/init.h> | ||
195 | |||
196 | /* #include <linux/ucdrom.h> */ | ||
197 | |||
198 | #include <asm/io.h> | ||
199 | |||
200 | #define MAJOR_NR CM206_CDROM_MAJOR | ||
201 | |||
202 | #include <linux/blkdev.h> | ||
203 | |||
204 | #undef DEBUG | ||
205 | #define STATISTICS /* record times and frequencies of events */ | ||
206 | #define AUTO_PROBE_MODULE | ||
207 | #define USE_INSW | ||
208 | |||
209 | #include "cm206.h" | ||
210 | |||
211 | /* This variable defines whether or not to probe for adapter base port | ||
212 | address and interrupt request. It can be overridden by the boot | ||
213 | parameter `auto'. | ||
214 | */ | ||
215 | static int auto_probe = 1; /* Yes, why not? */ | ||
216 | |||
217 | static int cm206_base = CM206_BASE; | ||
218 | static int cm206_irq = CM206_IRQ; | ||
219 | #ifdef MODULE | ||
220 | static int cm206[2] = { 0, 0 }; /* for compatible `insmod' parameter passing */ | ||
221 | #endif | ||
222 | |||
223 | MODULE_PARM(cm206_base, "i"); /* base */ | ||
224 | MODULE_PARM(cm206_irq, "i"); /* irq */ | ||
225 | MODULE_PARM(cm206, "1-2i"); /* base,irq or irq,base */ | ||
226 | MODULE_PARM(auto_probe, "i"); /* auto probe base and irq */ | ||
227 | MODULE_LICENSE("GPL"); | ||
228 | |||
229 | #define POLLOOP 100 /* milliseconds */ | ||
230 | #define READ_AHEAD 1 /* defines private buffer, waste! */ | ||
231 | #define BACK_AHEAD 1 /* defines adapter-read ahead */ | ||
232 | #define DATA_TIMEOUT (3*HZ) /* measured in jiffies (10 ms) */ | ||
233 | #define UART_TIMEOUT (5*HZ/100) | ||
234 | #define DSB_TIMEOUT (7*HZ) /* time for the slowest command to finish */ | ||
235 | #define UR_SIZE 4 /* uart receive buffer fifo size */ | ||
236 | |||
237 | #define LINUX_BLOCK_SIZE 512 /* WHERE is this defined? */ | ||
238 | #define RAW_SECTOR_SIZE 2352 /* ok, is also defined in cdrom.h */ | ||
239 | #define ISO_SECTOR_SIZE 2048 | ||
240 | #define BLOCKS_ISO (ISO_SECTOR_SIZE/LINUX_BLOCK_SIZE) /* 4 */ | ||
241 | #define CD_SYNC_HEAD 16 /* CD_SYNC + CD_HEAD */ | ||
242 | |||
243 | #ifdef STATISTICS /* keep track of errors in counters */ | ||
244 | #define stats(i) { ++cd->stats[st_ ## i]; \ | ||
245 | cd->last_stat[st_ ## i] = cd->stat_counter++; \ | ||
246 | } | ||
247 | #else | ||
248 | #define stats(i) (void) 0; | ||
249 | #endif | ||
250 | |||
251 | #define Debug(a) {printk (KERN_DEBUG); printk a;} | ||
252 | #ifdef DEBUG | ||
253 | #define debug(a) Debug(a) | ||
254 | #else | ||
255 | #define debug(a) (void) 0; | ||
256 | #endif | ||
257 | |||
258 | typedef unsigned char uch; /* 8-bits */ | ||
259 | typedef unsigned short ush; /* 16-bits */ | ||
260 | |||
261 | struct toc_struct { /* private copy of Table of Contents */ | ||
262 | uch track, fsm[3], q0; | ||
263 | }; | ||
264 | |||
265 | struct cm206_struct { | ||
266 | volatile ush intr_ds; /* data status read on last interrupt */ | ||
267 | volatile ush intr_ls; /* uart line status read on last interrupt */ | ||
268 | volatile uch ur[UR_SIZE]; /* uart receive buffer fifo */ | ||
269 | volatile uch ur_w, ur_r; /* write/read buffer index */ | ||
270 | volatile uch dsb, cc; /* drive status byte and condition (error) code */ | ||
271 | int command; /* command to be written to the uart */ | ||
272 | int openfiles; | ||
273 | ush sector[READ_AHEAD * RAW_SECTOR_SIZE / 2]; /* buffered cd-sector */ | ||
274 | int sector_first, sector_last; /* range of these sectors */ | ||
275 | wait_queue_head_t uart; /* wait queues for interrupt */ | ||
276 | wait_queue_head_t data; | ||
277 | struct timer_list timer; /* time-out */ | ||
278 | char timed_out; | ||
279 | signed char max_sectors; /* number of sectors that fit in adapter mem */ | ||
280 | char wait_back; /* we're waiting for a background-read */ | ||
281 | char background; /* is a read going on in the background? */ | ||
282 | int adapter_first; /* if so, that's the starting sector */ | ||
283 | int adapter_last; | ||
284 | char fifo_overflowed; | ||
285 | uch disc_status[7]; /* result of get_disc_status command */ | ||
286 | #ifdef STATISTICS | ||
287 | int stats[NR_STATS]; | ||
288 | int last_stat[NR_STATS]; /* `time' at which stat was stat */ | ||
289 | int stat_counter; | ||
290 | #endif | ||
291 | struct toc_struct toc[101]; /* The whole table of contents + lead-out */ | ||
292 | uch q[10]; /* Last read q-channel info */ | ||
293 | uch audio_status[5]; /* last read position on pause */ | ||
294 | uch media_changed; /* record if media changed */ | ||
295 | }; | ||
296 | |||
297 | #define DISC_STATUS cd->disc_status[0] | ||
298 | #define FIRST_TRACK cd->disc_status[1] | ||
299 | #define LAST_TRACK cd->disc_status[2] | ||
300 | #define PAUSED cd->audio_status[0] /* misuse this memory byte! */ | ||
301 | #define PLAY_TO cd->toc[0] /* toc[0] records end-time in play */ | ||
302 | |||
303 | static struct cm206_struct *cd; /* the main memory structure */ | ||
304 | static struct request_queue *cm206_queue; | ||
305 | static DEFINE_SPINLOCK(cm206_lock); | ||
306 | |||
307 | /* First, we define some polling functions. These are actually | ||
308 | only being used in the initialization. */ | ||
309 | |||
310 | void send_command_polled(int command) | ||
311 | { | ||
312 | int loop = POLLOOP; | ||
313 | while (!(inw(r_line_status) & ls_transmitter_buffer_empty) | ||
314 | && loop > 0) { | ||
315 | mdelay(1); /* one millisec delay */ | ||
316 | --loop; | ||
317 | } | ||
318 | outw(command, r_uart_transmit); | ||
319 | } | ||
320 | |||
321 | uch receive_echo_polled(void) | ||
322 | { | ||
323 | int loop = POLLOOP; | ||
324 | while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) { | ||
325 | mdelay(1); | ||
326 | --loop; | ||
327 | } | ||
328 | return ((uch) inw(r_uart_receive)); | ||
329 | } | ||
330 | |||
331 | uch send_receive_polled(int command) | ||
332 | { | ||
333 | send_command_polled(command); | ||
334 | return receive_echo_polled(); | ||
335 | } | ||
336 | |||
337 | inline void clear_ur(void) | ||
338 | { | ||
339 | if (cd->ur_r != cd->ur_w) { | ||
340 | debug(("Deleting bytes from fifo:")); | ||
341 | for (; cd->ur_r != cd->ur_w; | ||
342 | cd->ur_r++, cd->ur_r %= UR_SIZE) | ||
343 | debug((" 0x%x", cd->ur[cd->ur_r])); | ||
344 | debug(("\n")); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | static struct tasklet_struct cm206_tasklet; | ||
349 | |||
350 | /* The interrupt handler. When the cm260 generates an interrupt, very | ||
351 | much care has to be taken in reading out the registers in the right | ||
352 | order; in case of a receive_buffer_full interrupt, first the | ||
353 | uart_receive must be read, and then the line status again to | ||
354 | de-assert the interrupt line. It took me a couple of hours to find | ||
355 | this out:-( | ||
356 | |||
357 | The function reset_cm206 appears to cause an interrupt, because | ||
358 | pulling up the INIT line clears both the uart-write-buffer /and/ | ||
359 | the uart-write-buffer-empty mask. We call this a `lost interrupt,' | ||
360 | as there seems so reason for this to happen. | ||
361 | */ | ||
362 | |||
363 | static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs) | ||
364 | { | ||
365 | volatile ush fool; | ||
366 | cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error, | ||
367 | crc_error, sync_error, toc_ready | ||
368 | interrupts */ | ||
369 | cd->intr_ls = inw(r_line_status); /* resets overrun bit */ | ||
370 | debug(("Intr, 0x%x 0x%x, %d\n", cd->intr_ds, cd->intr_ls, | ||
371 | cd->background)); | ||
372 | if (cd->intr_ls & ls_attention) | ||
373 | stats(attention); | ||
374 | /* receive buffer full? */ | ||
375 | if (cd->intr_ls & ls_receive_buffer_full) { | ||
376 | cd->ur[cd->ur_w] = inb(r_uart_receive); /* get order right! */ | ||
377 | cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */ | ||
378 | debug(("receiving #%d: 0x%x\n", cd->ur_w, | ||
379 | cd->ur[cd->ur_w])); | ||
380 | cd->ur_w++; | ||
381 | cd->ur_w %= UR_SIZE; | ||
382 | if (cd->ur_w == cd->ur_r) | ||
383 | debug(("cd->ur overflow!\n")); | ||
384 | if (waitqueue_active(&cd->uart) && cd->background < 2) { | ||
385 | del_timer(&cd->timer); | ||
386 | wake_up_interruptible(&cd->uart); | ||
387 | } | ||
388 | } | ||
389 | /* data ready in fifo? */ | ||
390 | else if (cd->intr_ds & ds_data_ready) { | ||
391 | if (cd->background) | ||
392 | ++cd->adapter_last; | ||
393 | if (waitqueue_active(&cd->data) | ||
394 | && (cd->wait_back || !cd->background)) { | ||
395 | del_timer(&cd->timer); | ||
396 | wake_up_interruptible(&cd->data); | ||
397 | } | ||
398 | stats(data_ready); | ||
399 | } | ||
400 | /* ready to issue a write command? */ | ||
401 | else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) { | ||
402 | outw(dc_normal | (inw(r_data_status) & 0x7f), | ||
403 | r_data_control); | ||
404 | outw(cd->command, r_uart_transmit); | ||
405 | cd->command = 0; | ||
406 | if (!cd->background) | ||
407 | wake_up_interruptible(&cd->uart); | ||
408 | } | ||
409 | /* now treat errors (at least, identify them for debugging) */ | ||
410 | else if (cd->intr_ds & ds_fifo_overflow) { | ||
411 | debug(("Fifo overflow at sectors 0x%x\n", | ||
412 | cd->sector_first)); | ||
413 | fool = inw(r_fifo_output_buffer); /* de-assert the interrupt */ | ||
414 | cd->fifo_overflowed = 1; /* signal one word less should be read */ | ||
415 | stats(fifo_overflow); | ||
416 | } else if (cd->intr_ds & ds_data_error) { | ||
417 | debug(("Data error at sector 0x%x\n", cd->sector_first)); | ||
418 | stats(data_error); | ||
419 | } else if (cd->intr_ds & ds_crc_error) { | ||
420 | debug(("CRC error at sector 0x%x\n", cd->sector_first)); | ||
421 | stats(crc_error); | ||
422 | } else if (cd->intr_ds & ds_sync_error) { | ||
423 | debug(("Sync at sector 0x%x\n", cd->sector_first)); | ||
424 | stats(sync_error); | ||
425 | } else if (cd->intr_ds & ds_toc_ready) { | ||
426 | /* do something appropriate */ | ||
427 | } | ||
428 | /* couldn't see why this interrupt, maybe due to init */ | ||
429 | else { | ||
430 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
431 | stats(lost_intr); | ||
432 | } | ||
433 | if (cd->background | ||
434 | && (cd->adapter_last - cd->adapter_first == cd->max_sectors | ||
435 | || cd->fifo_overflowed)) | ||
436 | tasklet_schedule(&cm206_tasklet); /* issue a stop read command */ | ||
437 | stats(interrupt); | ||
438 | return IRQ_HANDLED; | ||
439 | } | ||
440 | |||
441 | /* we have put the address of the wait queue in who */ | ||
442 | void cm206_timeout(unsigned long who) | ||
443 | { | ||
444 | cd->timed_out = 1; | ||
445 | debug(("Timing out\n")); | ||
446 | wake_up_interruptible((wait_queue_head_t *) who); | ||
447 | } | ||
448 | |||
449 | /* This function returns 1 if a timeout occurred, 0 if an interrupt | ||
450 | happened */ | ||
451 | int sleep_or_timeout(wait_queue_head_t * wait, int timeout) | ||
452 | { | ||
453 | cd->timed_out = 0; | ||
454 | init_timer(&cd->timer); | ||
455 | cd->timer.data = (unsigned long) wait; | ||
456 | cd->timer.expires = jiffies + timeout; | ||
457 | add_timer(&cd->timer); | ||
458 | debug(("going to sleep\n")); | ||
459 | interruptible_sleep_on(wait); | ||
460 | del_timer(&cd->timer); | ||
461 | if (cd->timed_out) { | ||
462 | cd->timed_out = 0; | ||
463 | return 1; | ||
464 | } else | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | void cm206_delay(int nr_jiffies) | ||
469 | { | ||
470 | DECLARE_WAIT_QUEUE_HEAD(wait); | ||
471 | sleep_or_timeout(&wait, nr_jiffies); | ||
472 | } | ||
473 | |||
474 | void send_command(int command) | ||
475 | { | ||
476 | debug(("Sending 0x%x\n", command)); | ||
477 | if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) { | ||
478 | cd->command = command; | ||
479 | cli(); /* don't interrupt before sleep */ | ||
480 | outw(dc_mask_sync_error | dc_no_stop_on_error | | ||
481 | (inw(r_data_status) & 0x7f), r_data_control); | ||
482 | /* interrupt routine sends command */ | ||
483 | if (sleep_or_timeout(&cd->uart, UART_TIMEOUT)) { | ||
484 | debug(("Time out on write-buffer\n")); | ||
485 | stats(write_timeout); | ||
486 | outw(command, r_uart_transmit); | ||
487 | } | ||
488 | debug(("Write commmand delayed\n")); | ||
489 | } else | ||
490 | outw(command, r_uart_transmit); | ||
491 | } | ||
492 | |||
493 | uch receive_byte(int timeout) | ||
494 | { | ||
495 | uch ret; | ||
496 | cli(); | ||
497 | debug(("cli\n")); | ||
498 | ret = cd->ur[cd->ur_r]; | ||
499 | if (cd->ur_r != cd->ur_w) { | ||
500 | sti(); | ||
501 | debug(("returning #%d: 0x%x\n", cd->ur_r, | ||
502 | cd->ur[cd->ur_r])); | ||
503 | cd->ur_r++; | ||
504 | cd->ur_r %= UR_SIZE; | ||
505 | return ret; | ||
506 | } else if (sleep_or_timeout(&cd->uart, timeout)) { /* does sti() */ | ||
507 | debug(("Time out on receive-buffer\n")); | ||
508 | #ifdef STATISTICS | ||
509 | if (timeout == UART_TIMEOUT) | ||
510 | stats(receive_timeout) /* no `;'! */ | ||
511 | else | ||
512 | stats(dsb_timeout); | ||
513 | #endif | ||
514 | return 0xda; | ||
515 | } | ||
516 | ret = cd->ur[cd->ur_r]; | ||
517 | debug(("slept; returning #%d: 0x%x\n", cd->ur_r, | ||
518 | cd->ur[cd->ur_r])); | ||
519 | cd->ur_r++; | ||
520 | cd->ur_r %= UR_SIZE; | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | inline uch receive_echo(void) | ||
525 | { | ||
526 | return receive_byte(UART_TIMEOUT); | ||
527 | } | ||
528 | |||
529 | inline uch send_receive(int command) | ||
530 | { | ||
531 | send_command(command); | ||
532 | return receive_echo(); | ||
533 | } | ||
534 | |||
535 | inline uch wait_dsb(void) | ||
536 | { | ||
537 | return receive_byte(DSB_TIMEOUT); | ||
538 | } | ||
539 | |||
540 | int type_0_command(int command, int expect_dsb) | ||
541 | { | ||
542 | int e; | ||
543 | clear_ur(); | ||
544 | if (command != (e = send_receive(command))) { | ||
545 | debug(("command 0x%x echoed as 0x%x\n", command, e)); | ||
546 | stats(echo); | ||
547 | return -1; | ||
548 | } | ||
549 | if (expect_dsb) { | ||
550 | cd->dsb = wait_dsb(); /* wait for command to finish */ | ||
551 | } | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | int type_1_command(int command, int bytes, uch * status) | ||
556 | { /* returns info */ | ||
557 | int i; | ||
558 | if (type_0_command(command, 0)) | ||
559 | return -1; | ||
560 | for (i = 0; i < bytes; i++) | ||
561 | status[i] = send_receive(c_gimme); | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | /* This function resets the adapter card. We'd better not do this too | ||
566 | * often, because it tends to generate `lost interrupts.' */ | ||
567 | void reset_cm260(void) | ||
568 | { | ||
569 | outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control); | ||
570 | udelay(10); /* 3.3 mu sec minimum */ | ||
571 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
572 | } | ||
573 | |||
574 | /* fsm: frame-sec-min from linear address; one of many */ | ||
575 | void fsm(int lba, uch * fsm) | ||
576 | { | ||
577 | fsm[0] = lba % 75; | ||
578 | lba /= 75; | ||
579 | lba += 2; | ||
580 | fsm[1] = lba % 60; | ||
581 | fsm[2] = lba / 60; | ||
582 | } | ||
583 | |||
584 | inline int fsm2lba(uch * fsm) | ||
585 | { | ||
586 | return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]); | ||
587 | } | ||
588 | |||
589 | inline int f_s_m2lba(uch f, uch s, uch m) | ||
590 | { | ||
591 | return f + 75 * (s - 2 + 60 * m); | ||
592 | } | ||
593 | |||
594 | int start_read(int start) | ||
595 | { | ||
596 | uch read_sector[4] = { c_read_data, }; | ||
597 | int i, e; | ||
598 | |||
599 | fsm(start, &read_sector[1]); | ||
600 | clear_ur(); | ||
601 | for (i = 0; i < 4; i++) | ||
602 | if (read_sector[i] != (e = send_receive(read_sector[i]))) { | ||
603 | debug(("read_sector: %x echoes %x\n", | ||
604 | read_sector[i], e)); | ||
605 | stats(echo); | ||
606 | if (e == 0xff) { /* this seems to happen often */ | ||
607 | e = receive_echo(); | ||
608 | debug(("Second try %x\n", e)); | ||
609 | if (e != read_sector[i]) | ||
610 | return -1; | ||
611 | } | ||
612 | } | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | int stop_read(void) | ||
617 | { | ||
618 | int e; | ||
619 | type_0_command(c_stop, 0); | ||
620 | if ((e = receive_echo()) != 0xff) { | ||
621 | debug(("c_stop didn't send 0xff, but 0x%x\n", e)); | ||
622 | stats(stop_0xff); | ||
623 | return -1; | ||
624 | } | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | /* This function starts to read sectors in adapter memory, the | ||
629 | interrupt routine should stop the read. In fact, the bottom_half | ||
630 | routine takes care of this. Set a flag `background' in the cd | ||
631 | struct to indicate the process. */ | ||
632 | |||
633 | int read_background(int start, int reading) | ||
634 | { | ||
635 | if (cd->background) | ||
636 | return -1; /* can't do twice */ | ||
637 | outw(dc_normal | BACK_AHEAD, r_data_control); | ||
638 | if (!reading && start_read(start)) | ||
639 | return -2; | ||
640 | cd->adapter_first = cd->adapter_last = start; | ||
641 | cd->background = 1; /* flag a read is going on */ | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | #ifdef USE_INSW | ||
646 | #define transport_data insw | ||
647 | #else | ||
648 | /* this routine implements insw(,,). There was a time i had the | ||
649 | impression that there would be any difference in error-behaviour. */ | ||
650 | void transport_data(int port, ush * dest, int count) | ||
651 | { | ||
652 | int i; | ||
653 | ush *d; | ||
654 | for (i = 0, d = dest; i < count; i++, d++) | ||
655 | *d = inw(port); | ||
656 | } | ||
657 | #endif | ||
658 | |||
659 | |||
660 | #define MAX_TRIES 100 | ||
661 | int read_sector(int start) | ||
662 | { | ||
663 | int tries = 0; | ||
664 | if (cd->background) { | ||
665 | cd->background = 0; | ||
666 | cd->adapter_last = -1; /* invalidate adapter memory */ | ||
667 | stop_read(); | ||
668 | } | ||
669 | cd->fifo_overflowed = 0; | ||
670 | reset_cm260(); /* empty fifo etc. */ | ||
671 | if (start_read(start)) | ||
672 | return -1; | ||
673 | do { | ||
674 | if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { | ||
675 | debug(("Read timed out sector 0x%x\n", start)); | ||
676 | stats(read_timeout); | ||
677 | stop_read(); | ||
678 | return -3; | ||
679 | } | ||
680 | tries++; | ||
681 | } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES); | ||
682 | if (tries > 1) | ||
683 | debug(("Took me some tries\n")) | ||
684 | else | ||
685 | if (tries == MAX_TRIES) | ||
686 | debug(("MAX_TRIES tries for read sector\n")); | ||
687 | transport_data(r_fifo_output_buffer, cd->sector, | ||
688 | READ_AHEAD * RAW_SECTOR_SIZE / 2); | ||
689 | if (read_background(start + READ_AHEAD, 1)) | ||
690 | stats(read_background); | ||
691 | cd->sector_first = start; | ||
692 | cd->sector_last = start + READ_AHEAD; | ||
693 | stats(read_restarted); | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* The function of bottom-half is to send a stop command to the drive | ||
698 | This isn't easy because the routine is not `owned' by any process; | ||
699 | we can't go to sleep! The variable cd->background gives the status: | ||
700 | 0 no read pending | ||
701 | 1 a read is pending | ||
702 | 2 c_stop waits for write_buffer_empty | ||
703 | 3 c_stop waits for receive_buffer_full: echo | ||
704 | 4 c_stop waits for receive_buffer_full: 0xff | ||
705 | */ | ||
706 | |||
707 | static void cm206_tasklet_func(unsigned long ignore) | ||
708 | { | ||
709 | debug(("bh: %d\n", cd->background)); | ||
710 | switch (cd->background) { | ||
711 | case 1: | ||
712 | stats(bh); | ||
713 | if (!(cd->intr_ls & ls_transmitter_buffer_empty)) { | ||
714 | cd->command = c_stop; | ||
715 | outw(dc_mask_sync_error | dc_no_stop_on_error | | ||
716 | (inw(r_data_status) & 0x7f), r_data_control); | ||
717 | cd->background = 2; | ||
718 | break; /* we'd better not time-out here! */ | ||
719 | } else | ||
720 | outw(c_stop, r_uart_transmit); | ||
721 | /* fall into case 2: */ | ||
722 | case 2: | ||
723 | /* the write has been satisfied by interrupt routine */ | ||
724 | cd->background = 3; | ||
725 | break; | ||
726 | case 3: | ||
727 | if (cd->ur_r != cd->ur_w) { | ||
728 | if (cd->ur[cd->ur_r] != c_stop) { | ||
729 | debug(("cm206_bh: c_stop echoed 0x%x\n", | ||
730 | cd->ur[cd->ur_r])); | ||
731 | stats(echo); | ||
732 | } | ||
733 | cd->ur_r++; | ||
734 | cd->ur_r %= UR_SIZE; | ||
735 | } | ||
736 | cd->background++; | ||
737 | break; | ||
738 | case 4: | ||
739 | if (cd->ur_r != cd->ur_w) { | ||
740 | if (cd->ur[cd->ur_r] != 0xff) { | ||
741 | debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r])); | ||
742 | stats(stop_0xff); | ||
743 | } | ||
744 | cd->ur_r++; | ||
745 | cd->ur_r %= UR_SIZE; | ||
746 | } | ||
747 | cd->background = 0; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0); | ||
752 | |||
753 | /* This command clears the dsb_possible_media_change flag, so we must | ||
754 | * retain it. | ||
755 | */ | ||
756 | void get_drive_status(void) | ||
757 | { | ||
758 | uch status[2]; | ||
759 | type_1_command(c_drive_status, 2, status); /* this might be done faster */ | ||
760 | cd->dsb = status[0]; | ||
761 | cd->cc = status[1]; | ||
762 | cd->media_changed |= | ||
763 | !!(cd->dsb & (dsb_possible_media_change | | ||
764 | dsb_drive_not_ready | dsb_tray_not_closed)); | ||
765 | } | ||
766 | |||
767 | void get_disc_status(void) | ||
768 | { | ||
769 | if (type_1_command(c_disc_status, 7, cd->disc_status)) { | ||
770 | debug(("get_disc_status: error\n")); | ||
771 | } | ||
772 | } | ||
773 | |||
774 | /* The new open. The real opening strategy is defined in cdrom.c. */ | ||
775 | |||
776 | static int cm206_open(struct cdrom_device_info *cdi, int purpose) | ||
777 | { | ||
778 | if (!cd->openfiles) { /* reset only first time */ | ||
779 | cd->background = 0; | ||
780 | reset_cm260(); | ||
781 | cd->adapter_last = -1; /* invalidate adapter memory */ | ||
782 | cd->sector_last = -1; | ||
783 | } | ||
784 | ++cd->openfiles; | ||
785 | stats(open); | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static void cm206_release(struct cdrom_device_info *cdi) | ||
790 | { | ||
791 | if (cd->openfiles == 1) { | ||
792 | if (cd->background) { | ||
793 | cd->background = 0; | ||
794 | stop_read(); | ||
795 | } | ||
796 | cd->sector_last = -1; /* Make our internal buffer invalid */ | ||
797 | FIRST_TRACK = 0; /* No valid disc status */ | ||
798 | } | ||
799 | --cd->openfiles; | ||
800 | } | ||
801 | |||
802 | /* Empty buffer empties $sectors$ sectors of the adapter card buffer, | ||
803 | * and then reads a sector in kernel memory. */ | ||
804 | void empty_buffer(int sectors) | ||
805 | { | ||
806 | while (sectors >= 0) { | ||
807 | transport_data(r_fifo_output_buffer, | ||
808 | cd->sector + cd->fifo_overflowed, | ||
809 | RAW_SECTOR_SIZE / 2 - cd->fifo_overflowed); | ||
810 | --sectors; | ||
811 | ++cd->adapter_first; /* update the current adapter sector */ | ||
812 | cd->fifo_overflowed = 0; /* reset overflow bit */ | ||
813 | stats(sector_transferred); | ||
814 | } | ||
815 | cd->sector_first = cd->adapter_first - 1; | ||
816 | cd->sector_last = cd->adapter_first; /* update the buffer sector */ | ||
817 | } | ||
818 | |||
819 | /* try_adapter. This function determines if the requested sector is | ||
820 | in adapter memory, or will appear there soon. Returns 0 upon | ||
821 | success */ | ||
822 | int try_adapter(int sector) | ||
823 | { | ||
824 | if (cd->adapter_first <= sector && sector < cd->adapter_last) { | ||
825 | /* sector is in adapter memory */ | ||
826 | empty_buffer(sector - cd->adapter_first); | ||
827 | return 0; | ||
828 | } else if (cd->background == 1 && cd->adapter_first <= sector | ||
829 | && sector < cd->adapter_first + cd->max_sectors) { | ||
830 | /* a read is going on, we can wait for it */ | ||
831 | cd->wait_back = 1; | ||
832 | while (sector >= cd->adapter_last) { | ||
833 | if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { | ||
834 | debug(("Timed out during background wait: %d %d %d %d\n", sector, cd->adapter_last, cd->adapter_first, cd->background)); | ||
835 | stats(back_read_timeout); | ||
836 | cd->wait_back = 0; | ||
837 | return -1; | ||
838 | } | ||
839 | } | ||
840 | cd->wait_back = 0; | ||
841 | empty_buffer(sector - cd->adapter_first); | ||
842 | return 0; | ||
843 | } else | ||
844 | return -2; | ||
845 | } | ||
846 | |||
847 | /* This is not a very smart implementation. We could optimize for | ||
848 | consecutive block numbers. I'm not convinced this would really | ||
849 | bring down the processor load. */ | ||
850 | static void do_cm206_request(request_queue_t * q) | ||
851 | { | ||
852 | long int i, cd_sec_no; | ||
853 | int quarter, error; | ||
854 | uch *source, *dest; | ||
855 | struct request *req; | ||
856 | |||
857 | while (1) { /* repeat until all requests have been satisfied */ | ||
858 | req = elv_next_request(q); | ||
859 | if (!req) | ||
860 | return; | ||
861 | |||
862 | if (req->cmd != READ) { | ||
863 | debug(("Non-read command %d on cdrom\n", req->cmd)); | ||
864 | end_request(req, 0); | ||
865 | continue; | ||
866 | } | ||
867 | spin_unlock_irq(q->queue_lock); | ||
868 | error = 0; | ||
869 | for (i = 0; i < req->nr_sectors; i++) { | ||
870 | int e1, e2; | ||
871 | cd_sec_no = (req->sector + i) / BLOCKS_ISO; /* 4 times 512 bytes */ | ||
872 | quarter = (req->sector + i) % BLOCKS_ISO; | ||
873 | dest = req->buffer + i * LINUX_BLOCK_SIZE; | ||
874 | /* is already in buffer memory? */ | ||
875 | if (cd->sector_first <= cd_sec_no | ||
876 | && cd_sec_no < cd->sector_last) { | ||
877 | source = | ||
878 | ((uch *) cd->sector) + 16 + | ||
879 | quarter * LINUX_BLOCK_SIZE + | ||
880 | (cd_sec_no - | ||
881 | cd->sector_first) * RAW_SECTOR_SIZE; | ||
882 | memcpy(dest, source, LINUX_BLOCK_SIZE); | ||
883 | } else if (!(e1 = try_adapter(cd_sec_no)) || | ||
884 | !(e2 = read_sector(cd_sec_no))) { | ||
885 | source = | ||
886 | ((uch *) cd->sector) + 16 + | ||
887 | quarter * LINUX_BLOCK_SIZE; | ||
888 | memcpy(dest, source, LINUX_BLOCK_SIZE); | ||
889 | } else { | ||
890 | error = 1; | ||
891 | debug(("cm206_request: %d %d\n", e1, e2)); | ||
892 | } | ||
893 | } | ||
894 | spin_lock_irq(q->queue_lock); | ||
895 | end_request(req, !error); | ||
896 | } | ||
897 | } | ||
898 | |||
899 | /* Audio support. I've tried very hard, but the cm206 drive doesn't | ||
900 | seem to have a get_toc (table-of-contents) function, while i'm | ||
901 | pretty sure it must read the toc upon disc insertion. Therefore | ||
902 | this function has been implemented through a binary search | ||
903 | strategy. All track starts that happen to be found are stored in | ||
904 | cd->toc[], for future use. | ||
905 | |||
906 | I've spent a whole day on a bug that only shows under Workman--- | ||
907 | I don't get it. Tried everything, nothing works. If workman asks | ||
908 | for track# 0xaa, it'll get the wrong time back. Any other program | ||
909 | receives the correct value. I'm stymied. | ||
910 | */ | ||
911 | |||
912 | /* seek seeks to address lba. It does wait to arrive there. */ | ||
913 | void seek(int lba) | ||
914 | { | ||
915 | int i; | ||
916 | uch seek_command[4] = { c_seek, }; | ||
917 | |||
918 | fsm(lba, &seek_command[1]); | ||
919 | for (i = 0; i < 4; i++) | ||
920 | type_0_command(seek_command[i], 0); | ||
921 | cd->dsb = wait_dsb(); | ||
922 | } | ||
923 | |||
924 | uch bcdbin(unsigned char bcd) | ||
925 | { /* stolen from mcd.c! */ | ||
926 | return (bcd >> 4) * 10 + (bcd & 0xf); | ||
927 | } | ||
928 | |||
929 | inline uch normalize_track(uch track) | ||
930 | { | ||
931 | if (track < 1) | ||
932 | return 1; | ||
933 | if (track > LAST_TRACK) | ||
934 | return LAST_TRACK + 1; | ||
935 | return track; | ||
936 | } | ||
937 | |||
938 | /* This function does a binary search for track start. It records all | ||
939 | * tracks seen in the process. Input $track$ must be between 1 and | ||
940 | * #-of-tracks+1. Note that the start of the disc must be in toc[1].fsm. | ||
941 | */ | ||
942 | int get_toc_lba(uch track) | ||
943 | { | ||
944 | int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm); | ||
945 | int i, lba, l, old_lba = 0; | ||
946 | uch *q = cd->q; | ||
947 | uch ct; /* current track */ | ||
948 | int binary = 0; | ||
949 | const int skip = 3 * 60 * 75; /* 3 minutes */ | ||
950 | |||
951 | for (i = track; i > 0; i--) | ||
952 | if (cd->toc[i].track) { | ||
953 | min = fsm2lba(cd->toc[i].fsm); | ||
954 | break; | ||
955 | } | ||
956 | lba = min + skip; | ||
957 | do { | ||
958 | seek(lba); | ||
959 | type_1_command(c_read_current_q, 10, q); | ||
960 | ct = normalize_track(q[1]); | ||
961 | if (!cd->toc[ct].track) { | ||
962 | l = q[9] - bcdbin(q[5]) + 75 * (q[8] - | ||
963 | bcdbin(q[4]) - 2 + | ||
964 | 60 * (q[7] - | ||
965 | bcdbin(q | ||
966 | [3]))); | ||
967 | cd->toc[ct].track = q[1]; /* lead out still 0xaa */ | ||
968 | fsm(l, cd->toc[ct].fsm); | ||
969 | cd->toc[ct].q0 = q[0]; /* contains adr and ctrl info */ | ||
970 | if (ct == track) | ||
971 | return l; | ||
972 | } | ||
973 | old_lba = lba; | ||
974 | if (binary) { | ||
975 | if (ct < track) | ||
976 | min = lba; | ||
977 | else | ||
978 | max = lba; | ||
979 | lba = (min + max) / 2; | ||
980 | } else { | ||
981 | if (ct < track) | ||
982 | lba += skip; | ||
983 | else { | ||
984 | binary = 1; | ||
985 | max = lba; | ||
986 | min = lba - skip; | ||
987 | lba = (min + max) / 2; | ||
988 | } | ||
989 | } | ||
990 | } while (lba != old_lba); | ||
991 | return lba; | ||
992 | } | ||
993 | |||
994 | void update_toc_entry(uch track) | ||
995 | { | ||
996 | track = normalize_track(track); | ||
997 | if (!cd->toc[track].track) | ||
998 | get_toc_lba(track); | ||
999 | } | ||
1000 | |||
1001 | /* return 0 upon success */ | ||
1002 | int read_toc_header(struct cdrom_tochdr *hp) | ||
1003 | { | ||
1004 | if (!FIRST_TRACK) | ||
1005 | get_disc_status(); | ||
1006 | if (hp) { | ||
1007 | int i; | ||
1008 | hp->cdth_trk0 = FIRST_TRACK; | ||
1009 | hp->cdth_trk1 = LAST_TRACK; | ||
1010 | /* fill in first track position */ | ||
1011 | for (i = 0; i < 3; i++) | ||
1012 | cd->toc[1].fsm[i] = cd->disc_status[3 + i]; | ||
1013 | update_toc_entry(LAST_TRACK + 1); /* find most entries */ | ||
1014 | return 0; | ||
1015 | } | ||
1016 | return -1; | ||
1017 | } | ||
1018 | |||
1019 | void play_from_to_msf(struct cdrom_msf *msfp) | ||
1020 | { | ||
1021 | uch play_command[] = { c_play, | ||
1022 | msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0, | ||
1023 | msfp->cdmsf_frame1, msfp->cdmsf_sec1, msfp->cdmsf_min1, 2, | ||
1024 | 2 | ||
1025 | }; | ||
1026 | int i; | ||
1027 | for (i = 0; i < 9; i++) | ||
1028 | type_0_command(play_command[i], 0); | ||
1029 | for (i = 0; i < 3; i++) | ||
1030 | PLAY_TO.fsm[i] = play_command[i + 4]; | ||
1031 | PLAY_TO.track = 0; /* say no track end */ | ||
1032 | cd->dsb = wait_dsb(); | ||
1033 | } | ||
1034 | |||
1035 | void play_from_to_track(int from, int to) | ||
1036 | { | ||
1037 | uch play_command[8] = { c_play, }; | ||
1038 | int i; | ||
1039 | |||
1040 | if (from == 0) { /* continue paused play */ | ||
1041 | for (i = 0; i < 3; i++) { | ||
1042 | play_command[i + 1] = cd->audio_status[i + 2]; | ||
1043 | play_command[i + 4] = PLAY_TO.fsm[i]; | ||
1044 | } | ||
1045 | } else { | ||
1046 | update_toc_entry(from); | ||
1047 | update_toc_entry(to + 1); | ||
1048 | for (i = 0; i < 3; i++) { | ||
1049 | play_command[i + 1] = cd->toc[from].fsm[i]; | ||
1050 | PLAY_TO.fsm[i] = play_command[i + 4] = | ||
1051 | cd->toc[to + 1].fsm[i]; | ||
1052 | } | ||
1053 | PLAY_TO.track = to; | ||
1054 | } | ||
1055 | for (i = 0; i < 7; i++) | ||
1056 | type_0_command(play_command[i], 0); | ||
1057 | for (i = 0; i < 2; i++) | ||
1058 | type_0_command(0x2, 0); /* volume */ | ||
1059 | cd->dsb = wait_dsb(); | ||
1060 | } | ||
1061 | |||
1062 | int get_current_q(struct cdrom_subchnl *qp) | ||
1063 | { | ||
1064 | int i; | ||
1065 | uch *q = cd->q; | ||
1066 | if (type_1_command(c_read_current_q, 10, q)) | ||
1067 | return 0; | ||
1068 | /* q[0] = bcdbin(q[0]); Don't think so! */ | ||
1069 | for (i = 2; i < 6; i++) | ||
1070 | q[i] = bcdbin(q[i]); | ||
1071 | qp->cdsc_adr = q[0] & 0xf; | ||
1072 | qp->cdsc_ctrl = q[0] >> 4; /* from mcd.c */ | ||
1073 | qp->cdsc_trk = q[1]; | ||
1074 | qp->cdsc_ind = q[2]; | ||
1075 | if (qp->cdsc_format == CDROM_MSF) { | ||
1076 | qp->cdsc_reladdr.msf.minute = q[3]; | ||
1077 | qp->cdsc_reladdr.msf.second = q[4]; | ||
1078 | qp->cdsc_reladdr.msf.frame = q[5]; | ||
1079 | qp->cdsc_absaddr.msf.minute = q[7]; | ||
1080 | qp->cdsc_absaddr.msf.second = q[8]; | ||
1081 | qp->cdsc_absaddr.msf.frame = q[9]; | ||
1082 | } else { | ||
1083 | qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]); | ||
1084 | qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]); | ||
1085 | } | ||
1086 | get_drive_status(); | ||
1087 | if (cd->dsb & dsb_play_in_progress) | ||
1088 | qp->cdsc_audiostatus = CDROM_AUDIO_PLAY; | ||
1089 | else if (PAUSED) | ||
1090 | qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED; | ||
1091 | else | ||
1092 | qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS; | ||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | void invalidate_toc(void) | ||
1097 | { | ||
1098 | memset(cd->toc, 0, sizeof(cd->toc)); | ||
1099 | memset(cd->disc_status, 0, sizeof(cd->disc_status)); | ||
1100 | } | ||
1101 | |||
1102 | /* cdrom.c guarantees that cdte_format == CDROM_MSF */ | ||
1103 | void get_toc_entry(struct cdrom_tocentry *ep) | ||
1104 | { | ||
1105 | uch track = normalize_track(ep->cdte_track); | ||
1106 | update_toc_entry(track); | ||
1107 | ep->cdte_addr.msf.frame = cd->toc[track].fsm[0]; | ||
1108 | ep->cdte_addr.msf.second = cd->toc[track].fsm[1]; | ||
1109 | ep->cdte_addr.msf.minute = cd->toc[track].fsm[2]; | ||
1110 | ep->cdte_adr = cd->toc[track].q0 & 0xf; | ||
1111 | ep->cdte_ctrl = cd->toc[track].q0 >> 4; | ||
1112 | ep->cdte_datamode = 0; | ||
1113 | } | ||
1114 | |||
1115 | /* Audio ioctl. Ioctl commands connected to audio are in such an | ||
1116 | * idiosyncratic i/o format, that we leave these untouched. Return 0 | ||
1117 | * upon success. Memory checking has been done by cdrom_ioctl(), the | ||
1118 | * calling function, as well as LBA/MSF sanitization. | ||
1119 | */ | ||
1120 | int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | ||
1121 | void *arg) | ||
1122 | { | ||
1123 | switch (cmd) { | ||
1124 | case CDROMREADTOCHDR: | ||
1125 | return read_toc_header((struct cdrom_tochdr *) arg); | ||
1126 | case CDROMREADTOCENTRY: | ||
1127 | get_toc_entry((struct cdrom_tocentry *) arg); | ||
1128 | return 0; | ||
1129 | case CDROMPLAYMSF: | ||
1130 | play_from_to_msf((struct cdrom_msf *) arg); | ||
1131 | return 0; | ||
1132 | case CDROMPLAYTRKIND: /* admittedly, not particularly beautiful */ | ||
1133 | play_from_to_track(((struct cdrom_ti *) arg)->cdti_trk0, | ||
1134 | ((struct cdrom_ti *) arg)->cdti_trk1); | ||
1135 | return 0; | ||
1136 | case CDROMSTOP: | ||
1137 | PAUSED = 0; | ||
1138 | if (cd->dsb & dsb_play_in_progress) | ||
1139 | return type_0_command(c_stop, 1); | ||
1140 | else | ||
1141 | return 0; | ||
1142 | case CDROMPAUSE: | ||
1143 | get_drive_status(); | ||
1144 | if (cd->dsb & dsb_play_in_progress) { | ||
1145 | type_0_command(c_stop, 1); | ||
1146 | type_1_command(c_audio_status, 5, | ||
1147 | cd->audio_status); | ||
1148 | PAUSED = 1; /* say we're paused */ | ||
1149 | } | ||
1150 | return 0; | ||
1151 | case CDROMRESUME: | ||
1152 | if (PAUSED) | ||
1153 | play_from_to_track(0, 0); | ||
1154 | PAUSED = 0; | ||
1155 | return 0; | ||
1156 | case CDROMSTART: | ||
1157 | case CDROMVOLCTRL: | ||
1158 | return 0; | ||
1159 | case CDROMSUBCHNL: | ||
1160 | return get_current_q((struct cdrom_subchnl *) arg); | ||
1161 | default: | ||
1162 | return -EINVAL; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | /* Ioctl. These ioctls are specific to the cm206 driver. I have made | ||
1167 | some driver statistics accessible through ioctl calls. | ||
1168 | */ | ||
1169 | |||
1170 | static int cm206_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | ||
1171 | unsigned long arg) | ||
1172 | { | ||
1173 | switch (cmd) { | ||
1174 | #ifdef STATISTICS | ||
1175 | case CM206CTL_GET_STAT: | ||
1176 | if (arg >= NR_STATS) | ||
1177 | return -EINVAL; | ||
1178 | else | ||
1179 | return cd->stats[arg]; | ||
1180 | case CM206CTL_GET_LAST_STAT: | ||
1181 | if (arg >= NR_STATS) | ||
1182 | return -EINVAL; | ||
1183 | else | ||
1184 | return cd->last_stat[arg]; | ||
1185 | #endif | ||
1186 | default: | ||
1187 | debug(("Unknown ioctl call 0x%x\n", cmd)); | ||
1188 | return -EINVAL; | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
1193 | { | ||
1194 | if (cd != NULL) { | ||
1195 | int r; | ||
1196 | get_drive_status(); /* ensure cd->media_changed OK */ | ||
1197 | r = cd->media_changed; | ||
1198 | cd->media_changed = 0; /* clear bit */ | ||
1199 | return r; | ||
1200 | } else | ||
1201 | return -EIO; | ||
1202 | } | ||
1203 | |||
1204 | /* The new generic cdrom support. Routines should be concise, most of | ||
1205 | the logic should be in cdrom.c */ | ||
1206 | |||
1207 | /* returns number of times device is in use */ | ||
1208 | int cm206_open_files(struct cdrom_device_info *cdi) | ||
1209 | { | ||
1210 | if (cd) | ||
1211 | return cd->openfiles; | ||
1212 | return -1; | ||
1213 | } | ||
1214 | |||
1215 | /* controls tray movement */ | ||
1216 | int cm206_tray_move(struct cdrom_device_info *cdi, int position) | ||
1217 | { | ||
1218 | if (position) { /* 1: eject */ | ||
1219 | type_0_command(c_open_tray, 1); | ||
1220 | invalidate_toc(); | ||
1221 | } else | ||
1222 | type_0_command(c_close_tray, 1); /* 0: close */ | ||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
1226 | /* gives current state of the drive */ | ||
1227 | int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
1228 | { | ||
1229 | get_drive_status(); | ||
1230 | if (cd->dsb & dsb_tray_not_closed) | ||
1231 | return CDS_TRAY_OPEN; | ||
1232 | if (!(cd->dsb & dsb_disc_present)) | ||
1233 | return CDS_NO_DISC; | ||
1234 | if (cd->dsb & dsb_drive_not_ready) | ||
1235 | return CDS_DRIVE_NOT_READY; | ||
1236 | return CDS_DISC_OK; | ||
1237 | } | ||
1238 | |||
1239 | /* locks or unlocks door lock==1: lock; return 0 upon success */ | ||
1240 | int cm206_lock_door(struct cdrom_device_info *cdi, int lock) | ||
1241 | { | ||
1242 | uch command = (lock) ? c_lock_tray : c_unlock_tray; | ||
1243 | type_0_command(command, 1); /* wait and get dsb */ | ||
1244 | /* the logic calculates the success, 0 means successful */ | ||
1245 | return lock ^ ((cd->dsb & dsb_tray_locked) != 0); | ||
1246 | } | ||
1247 | |||
1248 | /* Although a session start should be in LBA format, we return it in | ||
1249 | MSF format because it is slightly easier, and the new generic ioctl | ||
1250 | will take care of the necessary conversion. */ | ||
1251 | int cm206_get_last_session(struct cdrom_device_info *cdi, | ||
1252 | struct cdrom_multisession *mssp) | ||
1253 | { | ||
1254 | if (!FIRST_TRACK) | ||
1255 | get_disc_status(); | ||
1256 | if (mssp != NULL) { | ||
1257 | if (DISC_STATUS & cds_multi_session) { /* multi-session */ | ||
1258 | mssp->addr.msf.frame = cd->disc_status[3]; | ||
1259 | mssp->addr.msf.second = cd->disc_status[4]; | ||
1260 | mssp->addr.msf.minute = cd->disc_status[5]; | ||
1261 | mssp->addr_format = CDROM_MSF; | ||
1262 | mssp->xa_flag = 1; | ||
1263 | } else { | ||
1264 | mssp->xa_flag = 0; | ||
1265 | } | ||
1266 | return 1; | ||
1267 | } | ||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
1272 | { | ||
1273 | uch upc[10]; | ||
1274 | char *ret = mcn->medium_catalog_number; | ||
1275 | int i; | ||
1276 | |||
1277 | if (type_1_command(c_read_upc, 10, upc)) | ||
1278 | return -EIO; | ||
1279 | for (i = 0; i < 13; i++) { | ||
1280 | int w = i / 2 + 1, r = i % 2; | ||
1281 | if (r) | ||
1282 | ret[i] = 0x30 | (upc[w] & 0x0f); | ||
1283 | else | ||
1284 | ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f); | ||
1285 | } | ||
1286 | ret[13] = '\0'; | ||
1287 | return 0; | ||
1288 | } | ||
1289 | |||
1290 | int cm206_reset(struct cdrom_device_info *cdi) | ||
1291 | { | ||
1292 | stop_read(); | ||
1293 | reset_cm260(); | ||
1294 | outw(dc_normal | dc_break | READ_AHEAD, r_data_control); | ||
1295 | mdelay(1); /* 750 musec minimum */ | ||
1296 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
1297 | cd->sector_last = -1; /* flag no data buffered */ | ||
1298 | cd->adapter_last = -1; | ||
1299 | invalidate_toc(); | ||
1300 | return 0; | ||
1301 | } | ||
1302 | |||
1303 | int cm206_select_speed(struct cdrom_device_info *cdi, int speed) | ||
1304 | { | ||
1305 | int r; | ||
1306 | switch (speed) { | ||
1307 | case 0: | ||
1308 | r = type_0_command(c_auto_mode, 1); | ||
1309 | break; | ||
1310 | case 1: | ||
1311 | r = type_0_command(c_force_1x, 1); | ||
1312 | break; | ||
1313 | case 2: | ||
1314 | r = type_0_command(c_force_2x, 1); | ||
1315 | break; | ||
1316 | default: | ||
1317 | return -1; | ||
1318 | } | ||
1319 | if (r < 0) | ||
1320 | return r; | ||
1321 | else | ||
1322 | return 1; | ||
1323 | } | ||
1324 | |||
1325 | static struct cdrom_device_ops cm206_dops = { | ||
1326 | .open = cm206_open, | ||
1327 | .release = cm206_release, | ||
1328 | .drive_status = cm206_drive_status, | ||
1329 | .media_changed = cm206_media_changed, | ||
1330 | .tray_move = cm206_tray_move, | ||
1331 | .lock_door = cm206_lock_door, | ||
1332 | .select_speed = cm206_select_speed, | ||
1333 | .get_last_session = cm206_get_last_session, | ||
1334 | .get_mcn = cm206_get_upc, | ||
1335 | .reset = cm206_reset, | ||
1336 | .audio_ioctl = cm206_audio_ioctl, | ||
1337 | .dev_ioctl = cm206_ioctl, | ||
1338 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | | ||
1339 | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | | ||
1340 | CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED | | ||
1341 | CDC_IOCTLS | CDC_DRIVE_STATUS, | ||
1342 | .n_minors = 1, | ||
1343 | }; | ||
1344 | |||
1345 | |||
1346 | static struct cdrom_device_info cm206_info = { | ||
1347 | .ops = &cm206_dops, | ||
1348 | .speed = 2, | ||
1349 | .capacity = 1, | ||
1350 | .name = "cm206", | ||
1351 | }; | ||
1352 | |||
1353 | static int cm206_block_open(struct inode *inode, struct file *file) | ||
1354 | { | ||
1355 | return cdrom_open(&cm206_info, inode, file); | ||
1356 | } | ||
1357 | |||
1358 | static int cm206_block_release(struct inode *inode, struct file *file) | ||
1359 | { | ||
1360 | return cdrom_release(&cm206_info, file); | ||
1361 | } | ||
1362 | |||
1363 | static int cm206_block_ioctl(struct inode *inode, struct file *file, | ||
1364 | unsigned cmd, unsigned long arg) | ||
1365 | { | ||
1366 | return cdrom_ioctl(file, &cm206_info, inode, cmd, arg); | ||
1367 | } | ||
1368 | |||
1369 | static int cm206_block_media_changed(struct gendisk *disk) | ||
1370 | { | ||
1371 | return cdrom_media_changed(&cm206_info); | ||
1372 | } | ||
1373 | |||
1374 | static struct block_device_operations cm206_bdops = | ||
1375 | { | ||
1376 | .owner = THIS_MODULE, | ||
1377 | .open = cm206_block_open, | ||
1378 | .release = cm206_block_release, | ||
1379 | .ioctl = cm206_block_ioctl, | ||
1380 | .media_changed = cm206_block_media_changed, | ||
1381 | }; | ||
1382 | |||
1383 | static struct gendisk *cm206_gendisk; | ||
1384 | |||
1385 | /* This function probes for the adapter card. It returns the base | ||
1386 | address if it has found the adapter card. One can specify a base | ||
1387 | port to probe specifically, or 0 which means span all possible | ||
1388 | bases. | ||
1389 | |||
1390 | Linus says it is too dangerous to use writes for probing, so we | ||
1391 | stick with pure reads for a while. Hope that 8 possible ranges, | ||
1392 | request_region, 15 bits of one port and 6 of another make things | ||
1393 | likely enough to accept the region on the first hit... | ||
1394 | */ | ||
1395 | int __init probe_base_port(int base) | ||
1396 | { | ||
1397 | int b = 0x300, e = 0x370; /* this is the range of start addresses */ | ||
1398 | volatile int fool, i; | ||
1399 | |||
1400 | if (base) | ||
1401 | b = e = base; | ||
1402 | for (base = b; base <= e; base += 0x10) { | ||
1403 | if (!request_region(base, 0x10,"cm206")) | ||
1404 | continue; | ||
1405 | for (i = 0; i < 3; i++) | ||
1406 | fool = inw(base + 2); /* empty possibly uart_receive_buffer */ | ||
1407 | if ((inw(base + 6) & 0xffef) != 0x0001 || /* line_status */ | ||
1408 | (inw(base) & 0xad00) != 0) { /* data status */ | ||
1409 | release_region(base,0x10); | ||
1410 | continue; | ||
1411 | } | ||
1412 | return (base); | ||
1413 | } | ||
1414 | return 0; | ||
1415 | } | ||
1416 | |||
1417 | #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) | ||
1418 | /* Probe for irq# nr. If nr==0, probe for all possible irq's. */ | ||
1419 | int __init probe_irq(int nr) | ||
1420 | { | ||
1421 | int irqs, irq; | ||
1422 | outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ | ||
1423 | sti(); | ||
1424 | irqs = probe_irq_on(); | ||
1425 | reset_cm260(); /* causes interrupt */ | ||
1426 | udelay(100); /* wait for it */ | ||
1427 | irq = probe_irq_off(irqs); | ||
1428 | outw(dc_normal | READ_AHEAD, r_data_control); /* services interrupt */ | ||
1429 | if (nr && irq != nr && irq > 0) | ||
1430 | return 0; /* wrong interrupt happened */ | ||
1431 | else | ||
1432 | return irq; | ||
1433 | } | ||
1434 | #endif | ||
1435 | |||
1436 | int __init cm206_init(void) | ||
1437 | { | ||
1438 | uch e = 0; | ||
1439 | long int size = sizeof(struct cm206_struct); | ||
1440 | struct gendisk *disk; | ||
1441 | |||
1442 | printk(KERN_INFO "cm206 cdrom driver " REVISION); | ||
1443 | cm206_base = probe_base_port(auto_probe ? 0 : cm206_base); | ||
1444 | if (!cm206_base) { | ||
1445 | printk(" can't find adapter!\n"); | ||
1446 | return -EIO; | ||
1447 | } | ||
1448 | printk(" adapter at 0x%x", cm206_base); | ||
1449 | cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL); | ||
1450 | if (!cd) | ||
1451 | goto out_base; | ||
1452 | /* Now we have found the adaptor card, try to reset it. As we have | ||
1453 | * found out earlier, this process generates an interrupt as well, | ||
1454 | * so we might just exploit that fact for irq probing! */ | ||
1455 | #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) | ||
1456 | cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq); | ||
1457 | if (cm206_irq <= 0) { | ||
1458 | printk("can't find IRQ!\n"); | ||
1459 | goto out_probe; | ||
1460 | } else | ||
1461 | printk(" IRQ %d found\n", cm206_irq); | ||
1462 | #else | ||
1463 | cli(); | ||
1464 | reset_cm260(); | ||
1465 | /* Now, the problem here is that reset_cm260 can generate an | ||
1466 | interrupt. It seems that this can cause a kernel oops some time | ||
1467 | later. So we wait a while and `service' this interrupt. */ | ||
1468 | mdelay(1); | ||
1469 | outw(dc_normal | READ_AHEAD, r_data_control); | ||
1470 | sti(); | ||
1471 | printk(" using IRQ %d\n", cm206_irq); | ||
1472 | #endif | ||
1473 | if (send_receive_polled(c_drive_configuration) != | ||
1474 | c_drive_configuration) { | ||
1475 | printk(KERN_INFO " drive not there\n"); | ||
1476 | goto out_probe; | ||
1477 | } | ||
1478 | e = send_receive_polled(c_gimme); | ||
1479 | printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code); | ||
1480 | if (e & dcf_transfer_rate) | ||
1481 | printk(" double"); | ||
1482 | else | ||
1483 | printk(" single"); | ||
1484 | printk(" speed drive"); | ||
1485 | if (e & dcf_motorized_tray) | ||
1486 | printk(", motorized tray"); | ||
1487 | if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206", NULL)) { | ||
1488 | printk("\nUnable to reserve IRQ---aborted\n"); | ||
1489 | goto out_probe; | ||
1490 | } | ||
1491 | printk(".\n"); | ||
1492 | |||
1493 | if (register_blkdev(MAJOR_NR, "cm206")) | ||
1494 | goto out_blkdev; | ||
1495 | |||
1496 | disk = alloc_disk(1); | ||
1497 | if (!disk) | ||
1498 | goto out_disk; | ||
1499 | disk->major = MAJOR_NR; | ||
1500 | disk->first_minor = 0; | ||
1501 | sprintf(disk->disk_name, "cm206cd"); | ||
1502 | disk->fops = &cm206_bdops; | ||
1503 | disk->flags = GENHD_FL_CD; | ||
1504 | cm206_gendisk = disk; | ||
1505 | if (register_cdrom(&cm206_info) != 0) { | ||
1506 | printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); | ||
1507 | goto out_cdrom; | ||
1508 | } | ||
1509 | cm206_queue = blk_init_queue(do_cm206_request, &cm206_lock); | ||
1510 | if (!cm206_queue) | ||
1511 | goto out_queue; | ||
1512 | |||
1513 | blk_queue_hardsect_size(cm206_queue, 2048); | ||
1514 | disk->queue = cm206_queue; | ||
1515 | add_disk(disk); | ||
1516 | |||
1517 | memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ | ||
1518 | cd->sector_last = -1; /* flag no data buffered */ | ||
1519 | cd->adapter_last = -1; | ||
1520 | init_timer(&cd->timer); | ||
1521 | cd->timer.function = cm206_timeout; | ||
1522 | cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97; | ||
1523 | printk(KERN_INFO "%d kB adapter memory available, " | ||
1524 | " %ld bytes kernel memory used.\n", cd->max_sectors * 2, | ||
1525 | size); | ||
1526 | return 0; | ||
1527 | |||
1528 | out_queue: | ||
1529 | unregister_cdrom(&cm206_info); | ||
1530 | out_cdrom: | ||
1531 | put_disk(disk); | ||
1532 | out_disk: | ||
1533 | unregister_blkdev(MAJOR_NR, "cm206"); | ||
1534 | out_blkdev: | ||
1535 | free_irq(cm206_irq, NULL); | ||
1536 | out_probe: | ||
1537 | kfree(cd); | ||
1538 | out_base: | ||
1539 | release_region(cm206_base, 16); | ||
1540 | return -EIO; | ||
1541 | } | ||
1542 | |||
1543 | #ifdef MODULE | ||
1544 | |||
1545 | |||
1546 | static void __init parse_options(void) | ||
1547 | { | ||
1548 | int i; | ||
1549 | for (i = 0; i < 2; i++) { | ||
1550 | if (0x300 <= cm206[i] && i <= 0x370 | ||
1551 | && cm206[i] % 0x10 == 0) { | ||
1552 | cm206_base = cm206[i]; | ||
1553 | auto_probe = 0; | ||
1554 | } else if (3 <= cm206[i] && cm206[i] <= 15) { | ||
1555 | cm206_irq = cm206[i]; | ||
1556 | auto_probe = 0; | ||
1557 | } | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | int __cm206_init(void) | ||
1562 | { | ||
1563 | parse_options(); | ||
1564 | #if !defined(AUTO_PROBE_MODULE) | ||
1565 | auto_probe = 0; | ||
1566 | #endif | ||
1567 | return cm206_init(); | ||
1568 | } | ||
1569 | |||
1570 | void __exit cm206_exit(void) | ||
1571 | { | ||
1572 | del_gendisk(cm206_gendisk); | ||
1573 | put_disk(cm206_gendisk); | ||
1574 | if (unregister_cdrom(&cm206_info)) { | ||
1575 | printk("Can't unregister cdrom cm206\n"); | ||
1576 | return; | ||
1577 | } | ||
1578 | if (unregister_blkdev(MAJOR_NR, "cm206")) { | ||
1579 | printk("Can't unregister major cm206\n"); | ||
1580 | return; | ||
1581 | } | ||
1582 | blk_cleanup_queue(cm206_queue); | ||
1583 | free_irq(cm206_irq, NULL); | ||
1584 | kfree(cd); | ||
1585 | release_region(cm206_base, 16); | ||
1586 | printk(KERN_INFO "cm206 removed\n"); | ||
1587 | } | ||
1588 | |||
1589 | module_init(__cm206_init); | ||
1590 | module_exit(cm206_exit); | ||
1591 | |||
1592 | #else /* !MODULE */ | ||
1593 | |||
1594 | /* This setup function accepts either `auto' or numbers in the range | ||
1595 | * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ | ||
1596 | |||
1597 | static int __init cm206_setup(char *s) | ||
1598 | { | ||
1599 | int i, p[4]; | ||
1600 | |||
1601 | (void) get_options(s, ARRAY_SIZE(p), p); | ||
1602 | |||
1603 | if (!strcmp(s, "auto")) | ||
1604 | auto_probe = 1; | ||
1605 | for (i = 1; i <= p[0]; i++) { | ||
1606 | if (0x300 <= p[i] && i <= 0x370 && p[i] % 0x10 == 0) { | ||
1607 | cm206_base = p[i]; | ||
1608 | auto_probe = 0; | ||
1609 | } else if (3 <= p[i] && p[i] <= 15) { | ||
1610 | cm206_irq = p[i]; | ||
1611 | auto_probe = 0; | ||
1612 | } | ||
1613 | } | ||
1614 | return 1; | ||
1615 | } | ||
1616 | |||
1617 | __setup("cm206=", cm206_setup); | ||
1618 | |||
1619 | #endif /* !MODULE */ | ||
1620 | MODULE_ALIAS_BLOCKDEV_MAJOR(CM206_CDROM_MAJOR); | ||
1621 | |||
1622 | /* | ||
1623 | * Local variables: | ||
1624 | * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" | ||
1625 | * End: | ||
1626 | */ | ||
diff --git a/drivers/cdrom/cm206.h b/drivers/cdrom/cm206.h new file mode 100644 index 000000000000..0ae51c1a0dac --- /dev/null +++ b/drivers/cdrom/cm206.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* cm206.h Header file for cm206.c. | ||
2 | Copyright (c) 1995 David van Leeuwen | ||
3 | */ | ||
4 | |||
5 | #ifndef LINUX_CM206_H | ||
6 | #define LINUX_CM206_H | ||
7 | |||
8 | #include <linux/ioctl.h> | ||
9 | |||
10 | /* First, the cm260 stuff */ | ||
11 | /* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined | ||
12 | below, the values are not used unless autoprobing is turned off and | ||
13 | no LILO boot options or module command line options are given. Change | ||
14 | these values to your own as last resort if autoprobing and options | ||
15 | don't work. */ | ||
16 | |||
17 | #define CM206_BASE 0x340 | ||
18 | #define CM206_IRQ 11 | ||
19 | |||
20 | #define r_data_status (cm206_base) | ||
21 | #define r_uart_receive (cm206_base+0x2) | ||
22 | #define r_fifo_output_buffer (cm206_base+0x4) | ||
23 | #define r_line_status (cm206_base+0x6) | ||
24 | #define r_data_control (cm206_base+0x8) | ||
25 | #define r_uart_transmit (cm206_base+0xa) | ||
26 | #define r_test_clock (cm206_base+0xc) | ||
27 | #define r_test_control (cm206_base+0xe) | ||
28 | |||
29 | /* the data_status flags */ | ||
30 | #define ds_ram_size 0x4000 | ||
31 | #define ds_toc_ready 0x2000 | ||
32 | #define ds_fifo_empty 0x1000 | ||
33 | #define ds_sync_error 0x800 | ||
34 | #define ds_crc_error 0x400 | ||
35 | #define ds_data_error 0x200 | ||
36 | #define ds_fifo_overflow 0x100 | ||
37 | #define ds_data_ready 0x80 | ||
38 | |||
39 | /* the line_status flags */ | ||
40 | #define ls_attention 0x10 | ||
41 | #define ls_parity_error 0x8 | ||
42 | #define ls_overrun 0x4 | ||
43 | #define ls_receive_buffer_full 0x2 | ||
44 | #define ls_transmitter_buffer_empty 0x1 | ||
45 | |||
46 | /* the data control register flags */ | ||
47 | #define dc_read_q_channel 0x4000 | ||
48 | #define dc_mask_sync_error 0x2000 | ||
49 | #define dc_toc_enable 0x1000 | ||
50 | #define dc_no_stop_on_error 0x800 | ||
51 | #define dc_break 0x400 | ||
52 | #define dc_initialize 0x200 | ||
53 | #define dc_mask_transmit_ready 0x100 | ||
54 | #define dc_flag_enable 0x80 | ||
55 | |||
56 | /* Define the default data control register flags here */ | ||
57 | #define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \ | ||
58 | dc_mask_transmit_ready) | ||
59 | |||
60 | /* now some constants related to the cm206 */ | ||
61 | /* another drive status byte, echoed by the cm206 on most commands */ | ||
62 | |||
63 | #define dsb_error_condition 0x1 | ||
64 | #define dsb_play_in_progress 0x4 | ||
65 | #define dsb_possible_media_change 0x8 | ||
66 | #define dsb_disc_present 0x10 | ||
67 | #define dsb_drive_not_ready 0x20 | ||
68 | #define dsb_tray_locked 0x40 | ||
69 | #define dsb_tray_not_closed 0x80 | ||
70 | |||
71 | #define dsb_not_useful (dsb_drive_not_ready | dsb_tray_not_closed) | ||
72 | |||
73 | /* the cm206 command set */ | ||
74 | |||
75 | #define c_close_tray 0 | ||
76 | #define c_lock_tray 0x01 | ||
77 | #define c_unlock_tray 0x04 | ||
78 | #define c_open_tray 0x05 | ||
79 | #define c_seek 0x10 | ||
80 | #define c_read_data 0x20 | ||
81 | #define c_force_1x 0x21 | ||
82 | #define c_force_2x 0x22 | ||
83 | #define c_auto_mode 0x23 | ||
84 | #define c_play 0x30 | ||
85 | #define c_set_audio_mode 0x31 | ||
86 | #define c_read_current_q 0x41 | ||
87 | #define c_stream_q 0x42 | ||
88 | #define c_drive_status 0x50 | ||
89 | #define c_disc_status 0x51 | ||
90 | #define c_audio_status 0x52 | ||
91 | #define c_drive_configuration 0x53 | ||
92 | #define c_read_upc 0x60 | ||
93 | #define c_stop 0x70 | ||
94 | #define c_calc_checksum 0xe5 | ||
95 | |||
96 | #define c_gimme 0xf8 | ||
97 | |||
98 | /* finally, the (error) condition that the drive can be in * | ||
99 | * OK, this is not always an error, but let's prefix it with e_ */ | ||
100 | |||
101 | #define e_none 0 | ||
102 | #define e_illegal_command 0x01 | ||
103 | #define e_sync 0x02 | ||
104 | #define e_seek 0x03 | ||
105 | #define e_parity 0x04 | ||
106 | #define e_focus 0x05 | ||
107 | #define e_header_sync 0x06 | ||
108 | #define e_code_incompatibility 0x07 | ||
109 | #define e_reset_done 0x08 | ||
110 | #define e_bad_parameter 0x09 | ||
111 | #define e_radial 0x0a | ||
112 | #define e_sub_code 0x0b | ||
113 | #define e_no_data_track 0x0c | ||
114 | #define e_scan 0x0d | ||
115 | #define e_tray_open 0x0f | ||
116 | #define e_no_disc 0x10 | ||
117 | #define e_tray stalled 0x11 | ||
118 | |||
119 | /* drive configuration masks */ | ||
120 | |||
121 | #define dcf_revision_code 0x7 | ||
122 | #define dcf_transfer_rate 0x60 | ||
123 | #define dcf_motorized_tray 0x80 | ||
124 | |||
125 | /* disc status byte */ | ||
126 | |||
127 | #define cds_multi_session 0x2 | ||
128 | #define cds_all_audio 0x8 | ||
129 | #define cds_xa_mode 0xf0 | ||
130 | |||
131 | /* finally some ioctls for the driver */ | ||
132 | |||
133 | #define CM206CTL_GET_STAT _IO( 0x20, 0 ) | ||
134 | #define CM206CTL_GET_LAST_STAT _IO( 0x20, 1 ) | ||
135 | |||
136 | #ifdef STATISTICS | ||
137 | |||
138 | /* This is an ugly way to guarantee that the names of the statistics | ||
139 | * are the same in the code and in the diagnostics program. */ | ||
140 | |||
141 | #ifdef __KERNEL__ | ||
142 | #define x(a) st_ ## a | ||
143 | #define y enum | ||
144 | #else | ||
145 | #define x(a) #a | ||
146 | #define y char * stats_name[] = | ||
147 | #endif | ||
148 | |||
149 | y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error), | ||
150 | x(crc_error), x(sync_error), x(lost_intr), x(echo), | ||
151 | x(write_timeout), x(receive_timeout), x(read_timeout), | ||
152 | x(dsb_timeout), x(stop_0xff), x(back_read_timeout), | ||
153 | x(sector_transferred), x(read_restarted), x(read_background), | ||
154 | x(bh), x(open), x(ioctl_multisession), x(attention) | ||
155 | #ifdef __KERNEL__ | ||
156 | , x(last_entry) | ||
157 | #endif | ||
158 | }; | ||
159 | |||
160 | #ifdef __KERNEL__ | ||
161 | #define NR_STATS st_last_entry | ||
162 | #else | ||
163 | #define NR_STATS (sizeof(stats_name)/sizeof(char*)) | ||
164 | #endif | ||
165 | |||
166 | #undef y | ||
167 | #undef x | ||
168 | |||
169 | #endif /* STATISTICS */ | ||
170 | |||
171 | #endif /* LINUX_CM206_H */ | ||
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c new file mode 100644 index 000000000000..7eac10e63b23 --- /dev/null +++ b/drivers/cdrom/gscd.c | |||
@@ -0,0 +1,1031 @@ | |||
1 | #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>" | ||
2 | |||
3 | /* | ||
4 | linux/drivers/block/gscd.c - GoldStar R420 CDROM driver | ||
5 | |||
6 | Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de> | ||
7 | based upon pre-works by Eberhard Moenkeberg <emoenke@gwdg.de> | ||
8 | |||
9 | |||
10 | For all kind of other information about the GoldStar CDROM | ||
11 | and this Linux device driver I installed a WWW-URL: | ||
12 | http://linux.rz.fh-hannover.de/~raupach | ||
13 | |||
14 | |||
15 | If you are the editor of a Linux CD, you should | ||
16 | enable gscd.c within your boot floppy kernel and | ||
17 | send me one of your CDs for free. | ||
18 | |||
19 | |||
20 | -------------------------------------------------------------------- | ||
21 | This program is free software; you can redistribute it and/or modify | ||
22 | it under the terms of the GNU General Public License as published by | ||
23 | the Free Software Foundation; either version 2, or (at your option) | ||
24 | any later version. | ||
25 | |||
26 | This program is distributed in the hope that it will be useful, | ||
27 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | GNU General Public License for more details. | ||
30 | |||
31 | You should have received a copy of the GNU General Public License | ||
32 | along with this program; if not, write to the Free Software | ||
33 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
34 | |||
35 | -------------------------------------------------------------------- | ||
36 | |||
37 | 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
38 | Removed init_module & cleanup_module in favor of | ||
39 | module_init & module_exit. | ||
40 | Torben Mathiasen <tmm@image.dk> | ||
41 | |||
42 | */ | ||
43 | |||
44 | /* These settings are for various debug-level. Leave they untouched ... */ | ||
45 | #define NO_GSCD_DEBUG | ||
46 | #define NO_IOCTL_DEBUG | ||
47 | #define NO_MODULE_DEBUG | ||
48 | #define NO_FUTURE_WORK | ||
49 | /*------------------------*/ | ||
50 | |||
51 | #include <linux/module.h> | ||
52 | |||
53 | #include <linux/slab.h> | ||
54 | #include <linux/errno.h> | ||
55 | #include <linux/signal.h> | ||
56 | #include <linux/sched.h> | ||
57 | #include <linux/timer.h> | ||
58 | #include <linux/fs.h> | ||
59 | #include <linux/mm.h> | ||
60 | #include <linux/kernel.h> | ||
61 | #include <linux/cdrom.h> | ||
62 | #include <linux/ioport.h> | ||
63 | #include <linux/major.h> | ||
64 | #include <linux/string.h> | ||
65 | #include <linux/init.h> | ||
66 | |||
67 | #include <asm/system.h> | ||
68 | #include <asm/io.h> | ||
69 | #include <asm/uaccess.h> | ||
70 | |||
71 | #define MAJOR_NR GOLDSTAR_CDROM_MAJOR | ||
72 | #include <linux/blkdev.h> | ||
73 | #include "gscd.h" | ||
74 | |||
75 | static int gscdPresent = 0; | ||
76 | |||
77 | static unsigned char gscd_buf[2048]; /* buffer for block size conversion */ | ||
78 | static int gscd_bn = -1; | ||
79 | static short gscd_port = GSCD_BASE_ADDR; | ||
80 | module_param_named(gscd, gscd_port, short, 0); | ||
81 | |||
82 | /* Kommt spaeter vielleicht noch mal dran ... | ||
83 | * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); | ||
84 | */ | ||
85 | |||
86 | static void gscd_read_cmd(struct request *req); | ||
87 | static void gscd_hsg2msf(long hsg, struct msf *msf); | ||
88 | static void gscd_bin2bcd(unsigned char *p); | ||
89 | |||
90 | /* Schnittstellen zum Kern/FS */ | ||
91 | |||
92 | static void __do_gscd_request(unsigned long dummy); | ||
93 | static int gscd_ioctl(struct inode *, struct file *, unsigned int, | ||
94 | unsigned long); | ||
95 | static int gscd_open(struct inode *, struct file *); | ||
96 | static int gscd_release(struct inode *, struct file *); | ||
97 | static int check_gscd_med_chg(struct gendisk *disk); | ||
98 | |||
99 | /* GoldStar Funktionen */ | ||
100 | |||
101 | static void cmd_out(int, char *, char *, int); | ||
102 | static void cmd_status(void); | ||
103 | static void init_cd_drive(int); | ||
104 | |||
105 | static int get_status(void); | ||
106 | static void clear_Audio(void); | ||
107 | static void cc_invalidate(void); | ||
108 | |||
109 | /* some things for the next version */ | ||
110 | #ifdef FUTURE_WORK | ||
111 | static void update_state(void); | ||
112 | static long gscd_msf2hsg(struct msf *mp); | ||
113 | static int gscd_bcd2bin(unsigned char bcd); | ||
114 | #endif | ||
115 | |||
116 | |||
117 | /* lo-level cmd-Funktionen */ | ||
118 | |||
119 | static void cmd_info_in(char *, int); | ||
120 | static void cmd_end(void); | ||
121 | static void cmd_read_b(char *, int, int); | ||
122 | static void cmd_read_w(char *, int, int); | ||
123 | static int cmd_unit_alive(void); | ||
124 | static void cmd_write_cmd(char *); | ||
125 | |||
126 | |||
127 | /* GoldStar Variablen */ | ||
128 | |||
129 | static int curr_drv_state; | ||
130 | static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
131 | static int drv_mode; | ||
132 | static int disk_state; | ||
133 | static int speed; | ||
134 | static int ndrives; | ||
135 | |||
136 | static unsigned char drv_num_read; | ||
137 | static unsigned char f_dsk_valid; | ||
138 | static unsigned char current_drive; | ||
139 | static unsigned char f_drv_ok; | ||
140 | |||
141 | |||
142 | static char f_AudioPlay; | ||
143 | static char f_AudioPause; | ||
144 | static int AudioStart_m; | ||
145 | static int AudioStart_f; | ||
146 | static int AudioEnd_m; | ||
147 | static int AudioEnd_f; | ||
148 | |||
149 | static struct timer_list gscd_timer = TIMER_INITIALIZER(NULL, 0, 0); | ||
150 | static DEFINE_SPINLOCK(gscd_lock); | ||
151 | static struct request_queue *gscd_queue; | ||
152 | |||
153 | static struct block_device_operations gscd_fops = { | ||
154 | .owner = THIS_MODULE, | ||
155 | .open = gscd_open, | ||
156 | .release = gscd_release, | ||
157 | .ioctl = gscd_ioctl, | ||
158 | .media_changed = check_gscd_med_chg, | ||
159 | }; | ||
160 | |||
161 | /* | ||
162 | * Checking if the media has been changed | ||
163 | * (not yet implemented) | ||
164 | */ | ||
165 | static int check_gscd_med_chg(struct gendisk *disk) | ||
166 | { | ||
167 | #ifdef GSCD_DEBUG | ||
168 | printk("gscd: check_med_change\n"); | ||
169 | #endif | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | |||
174 | #ifndef MODULE | ||
175 | /* Using new interface for kernel-parameters */ | ||
176 | |||
177 | static int __init gscd_setup(char *str) | ||
178 | { | ||
179 | int ints[2]; | ||
180 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
181 | |||
182 | if (ints[0] > 0) { | ||
183 | gscd_port = ints[1]; | ||
184 | } | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | __setup("gscd=", gscd_setup); | ||
189 | |||
190 | #endif | ||
191 | |||
192 | static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | ||
193 | unsigned long arg) | ||
194 | { | ||
195 | unsigned char to_do[10]; | ||
196 | unsigned char dummy; | ||
197 | |||
198 | |||
199 | switch (cmd) { | ||
200 | case CDROMSTART: /* Spin up the drive */ | ||
201 | /* Don't think we can do this. Even if we could, | ||
202 | * I think the drive times out and stops after a while | ||
203 | * anyway. For now, ignore it. | ||
204 | */ | ||
205 | return 0; | ||
206 | |||
207 | case CDROMRESUME: /* keine Ahnung was das ist */ | ||
208 | return 0; | ||
209 | |||
210 | |||
211 | case CDROMEJECT: | ||
212 | cmd_status(); | ||
213 | to_do[0] = CMD_TRAY_CTL; | ||
214 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
215 | |||
216 | return 0; | ||
217 | |||
218 | default: | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
222 | } | ||
223 | |||
224 | |||
225 | /* | ||
226 | * Take care of the different block sizes between cdrom and Linux. | ||
227 | * When Linux gets variable block sizes this will probably go away. | ||
228 | */ | ||
229 | |||
230 | static void gscd_transfer(struct request *req) | ||
231 | { | ||
232 | while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) { | ||
233 | long offs = (req->sector & 3) * 512; | ||
234 | memcpy(req->buffer, gscd_buf + offs, 512); | ||
235 | req->nr_sectors--; | ||
236 | req->sector++; | ||
237 | req->buffer += 512; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | |||
242 | /* | ||
243 | * I/O request routine called from Linux kernel. | ||
244 | */ | ||
245 | |||
246 | static void do_gscd_request(request_queue_t * q) | ||
247 | { | ||
248 | __do_gscd_request(0); | ||
249 | } | ||
250 | |||
251 | static void __do_gscd_request(unsigned long dummy) | ||
252 | { | ||
253 | struct request *req; | ||
254 | unsigned int block; | ||
255 | unsigned int nsect; | ||
256 | |||
257 | repeat: | ||
258 | req = elv_next_request(gscd_queue); | ||
259 | if (!req) | ||
260 | return; | ||
261 | |||
262 | block = req->sector; | ||
263 | nsect = req->nr_sectors; | ||
264 | |||
265 | if (req->sector == -1) | ||
266 | goto out; | ||
267 | |||
268 | if (req->cmd != READ) { | ||
269 | printk("GSCD: bad cmd %lu\n", rq_data_dir(req)); | ||
270 | end_request(req, 0); | ||
271 | goto repeat; | ||
272 | } | ||
273 | |||
274 | gscd_transfer(req); | ||
275 | |||
276 | /* if we satisfied the request from the buffer, we're done. */ | ||
277 | |||
278 | if (req->nr_sectors == 0) { | ||
279 | end_request(req, 1); | ||
280 | goto repeat; | ||
281 | } | ||
282 | #ifdef GSCD_DEBUG | ||
283 | printk("GSCD: block %d, nsect %d\n", block, nsect); | ||
284 | #endif | ||
285 | gscd_read_cmd(req); | ||
286 | out: | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | |||
291 | |||
292 | /* | ||
293 | * Check the result of the set-mode command. On success, send the | ||
294 | * read-data command. | ||
295 | */ | ||
296 | |||
297 | static void gscd_read_cmd(struct request *req) | ||
298 | { | ||
299 | long block; | ||
300 | struct gscd_Play_msf gscdcmd; | ||
301 | char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */ | ||
302 | |||
303 | cmd_status(); | ||
304 | if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) { | ||
305 | printk("GSCD: no disk or door open\n"); | ||
306 | end_request(req, 0); | ||
307 | } else { | ||
308 | if (disk_state & ST_INVALID) { | ||
309 | printk("GSCD: disk invalid\n"); | ||
310 | end_request(req, 0); | ||
311 | } else { | ||
312 | gscd_bn = -1; /* purge our buffer */ | ||
313 | block = req->sector / 4; | ||
314 | gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ | ||
315 | |||
316 | cmd[2] = gscdcmd.start.min; | ||
317 | cmd[3] = gscdcmd.start.sec; | ||
318 | cmd[4] = gscdcmd.start.frame; | ||
319 | |||
320 | #ifdef GSCD_DEBUG | ||
321 | printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], | ||
322 | cmd[4]); | ||
323 | #endif | ||
324 | cmd_out(TYPE_DATA, (char *) &cmd, | ||
325 | (char *) &gscd_buf[0], 1); | ||
326 | |||
327 | gscd_bn = req->sector / 4; | ||
328 | gscd_transfer(req); | ||
329 | end_request(req, 1); | ||
330 | } | ||
331 | } | ||
332 | SET_TIMER(__do_gscd_request, 1); | ||
333 | } | ||
334 | |||
335 | |||
336 | /* | ||
337 | * Open the device special file. Check that a disk is in. | ||
338 | */ | ||
339 | |||
340 | static int gscd_open(struct inode *ip, struct file *fp) | ||
341 | { | ||
342 | int st; | ||
343 | |||
344 | #ifdef GSCD_DEBUG | ||
345 | printk("GSCD: open\n"); | ||
346 | #endif | ||
347 | |||
348 | if (gscdPresent == 0) | ||
349 | return -ENXIO; /* no hardware */ | ||
350 | |||
351 | get_status(); | ||
352 | st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); | ||
353 | if (st) { | ||
354 | printk("GSCD: no disk or door open\n"); | ||
355 | return -ENXIO; | ||
356 | } | ||
357 | |||
358 | /* if (updateToc() < 0) | ||
359 | return -EIO; | ||
360 | */ | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | |||
366 | /* | ||
367 | * On close, we flush all gscd blocks from the buffer cache. | ||
368 | */ | ||
369 | |||
370 | static int gscd_release(struct inode *inode, struct file *file) | ||
371 | { | ||
372 | |||
373 | #ifdef GSCD_DEBUG | ||
374 | printk("GSCD: release\n"); | ||
375 | #endif | ||
376 | |||
377 | gscd_bn = -1; | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | |||
383 | static int get_status(void) | ||
384 | { | ||
385 | int status; | ||
386 | |||
387 | cmd_status(); | ||
388 | status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01); | ||
389 | |||
390 | if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) { | ||
391 | cc_invalidate(); | ||
392 | return 1; | ||
393 | } else { | ||
394 | return 0; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | |||
399 | static void cc_invalidate(void) | ||
400 | { | ||
401 | drv_num_read = 0xFF; | ||
402 | f_dsk_valid = 0xFF; | ||
403 | current_drive = 0xFF; | ||
404 | f_drv_ok = 0xFF; | ||
405 | |||
406 | clear_Audio(); | ||
407 | |||
408 | } | ||
409 | |||
410 | static void clear_Audio(void) | ||
411 | { | ||
412 | |||
413 | f_AudioPlay = 0; | ||
414 | f_AudioPause = 0; | ||
415 | AudioStart_m = 0; | ||
416 | AudioStart_f = 0; | ||
417 | AudioEnd_m = 0; | ||
418 | AudioEnd_f = 0; | ||
419 | |||
420 | } | ||
421 | |||
422 | /* | ||
423 | * waiting ? | ||
424 | */ | ||
425 | |||
426 | static int wait_drv_ready(void) | ||
427 | { | ||
428 | int found, read; | ||
429 | |||
430 | do { | ||
431 | found = inb(GSCDPORT(0)); | ||
432 | found &= 0x0f; | ||
433 | read = inb(GSCDPORT(0)); | ||
434 | read &= 0x0f; | ||
435 | } while (read != found); | ||
436 | |||
437 | #ifdef GSCD_DEBUG | ||
438 | printk("Wait for: %d\n", read); | ||
439 | #endif | ||
440 | |||
441 | return read; | ||
442 | } | ||
443 | |||
444 | static void cc_Ident(char *respons) | ||
445 | { | ||
446 | char to_do[] = { CMD_IDENT, 0, 0 }; | ||
447 | |||
448 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E); | ||
449 | |||
450 | } | ||
451 | |||
452 | static void cc_SetSpeed(void) | ||
453 | { | ||
454 | char to_do[] = { CMD_SETSPEED, 0, 0 }; | ||
455 | char dummy; | ||
456 | |||
457 | if (speed > 0) { | ||
458 | to_do[1] = speed & 0x0F; | ||
459 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | static void cc_Reset(void) | ||
464 | { | ||
465 | char to_do[] = { CMD_RESET, 0 }; | ||
466 | char dummy; | ||
467 | |||
468 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
469 | } | ||
470 | |||
471 | static void cmd_status(void) | ||
472 | { | ||
473 | char to_do[] = { CMD_STATUS, 0 }; | ||
474 | char dummy; | ||
475 | |||
476 | cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | ||
477 | |||
478 | #ifdef GSCD_DEBUG | ||
479 | printk("GSCD: Status: %d\n", disk_state); | ||
480 | #endif | ||
481 | |||
482 | } | ||
483 | |||
484 | static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count) | ||
485 | { | ||
486 | int result; | ||
487 | |||
488 | |||
489 | result = wait_drv_ready(); | ||
490 | if (result != drv_mode) { | ||
491 | unsigned long test_loops = 0xFFFF; | ||
492 | int i, dummy; | ||
493 | |||
494 | outb(curr_drv_state, GSCDPORT(0)); | ||
495 | |||
496 | /* LOCLOOP_170 */ | ||
497 | do { | ||
498 | result = wait_drv_ready(); | ||
499 | test_loops--; | ||
500 | } while ((result != drv_mode) && (test_loops > 0)); | ||
501 | |||
502 | if (result != drv_mode) { | ||
503 | disk_state = ST_x08 | ST_x04 | ST_INVALID; | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | /* ...and waiting */ | ||
508 | for (i = 1, dummy = 1; i < 0xFFFF; i++) { | ||
509 | dummy *= i; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | /* LOC_172 */ | ||
514 | /* check the unit */ | ||
515 | /* and wake it up */ | ||
516 | if (cmd_unit_alive() != 0x08) { | ||
517 | /* LOC_174 */ | ||
518 | /* game over for this unit */ | ||
519 | disk_state = ST_x08 | ST_x04 | ST_INVALID; | ||
520 | return; | ||
521 | } | ||
522 | |||
523 | /* LOC_176 */ | ||
524 | #ifdef GSCD_DEBUG | ||
525 | printk("LOC_176 "); | ||
526 | #endif | ||
527 | if (drv_mode == 0x09) { | ||
528 | /* magic... */ | ||
529 | printk("GSCD: magic ...\n"); | ||
530 | outb(result, GSCDPORT(2)); | ||
531 | } | ||
532 | |||
533 | /* write the command to the drive */ | ||
534 | cmd_write_cmd(cmd); | ||
535 | |||
536 | /* LOC_178 */ | ||
537 | for (;;) { | ||
538 | result = wait_drv_ready(); | ||
539 | if (result != drv_mode) { | ||
540 | /* LOC_179 */ | ||
541 | if (result == 0x04) { /* Mode 4 */ | ||
542 | /* LOC_205 */ | ||
543 | #ifdef GSCD_DEBUG | ||
544 | printk("LOC_205 "); | ||
545 | #endif | ||
546 | disk_state = inb(GSCDPORT(2)); | ||
547 | |||
548 | do { | ||
549 | result = wait_drv_ready(); | ||
550 | } while (result != drv_mode); | ||
551 | return; | ||
552 | |||
553 | } else { | ||
554 | if (result == 0x06) { /* Mode 6 */ | ||
555 | /* LOC_181 */ | ||
556 | #ifdef GSCD_DEBUG | ||
557 | printk("LOC_181 "); | ||
558 | #endif | ||
559 | |||
560 | if (cmd_type == TYPE_DATA) { | ||
561 | /* read data */ | ||
562 | /* LOC_184 */ | ||
563 | if (drv_mode == 9) { | ||
564 | /* read the data to the buffer (word) */ | ||
565 | |||
566 | /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */ | ||
567 | cmd_read_w | ||
568 | (respo_buf, | ||
569 | respo_count, | ||
570 | CD_FRAMESIZE / | ||
571 | 2); | ||
572 | return; | ||
573 | } else { | ||
574 | /* read the data to the buffer (byte) */ | ||
575 | |||
576 | /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */ | ||
577 | cmd_read_b | ||
578 | (respo_buf, | ||
579 | respo_count, | ||
580 | CD_FRAMESIZE); | ||
581 | return; | ||
582 | } | ||
583 | } else { | ||
584 | /* read the info to the buffer */ | ||
585 | cmd_info_in(respo_buf, | ||
586 | respo_count); | ||
587 | return; | ||
588 | } | ||
589 | |||
590 | return; | ||
591 | } | ||
592 | } | ||
593 | |||
594 | } else { | ||
595 | disk_state = ST_x08 | ST_x04 | ST_INVALID; | ||
596 | return; | ||
597 | } | ||
598 | } /* for (;;) */ | ||
599 | |||
600 | |||
601 | #ifdef GSCD_DEBUG | ||
602 | printk("\n"); | ||
603 | #endif | ||
604 | } | ||
605 | |||
606 | |||
607 | static void cmd_write_cmd(char *pstr) | ||
608 | { | ||
609 | int i, j; | ||
610 | |||
611 | /* LOC_177 */ | ||
612 | #ifdef GSCD_DEBUG | ||
613 | printk("LOC_177 "); | ||
614 | #endif | ||
615 | |||
616 | /* calculate the number of parameter */ | ||
617 | j = *pstr & 0x0F; | ||
618 | |||
619 | /* shift it out */ | ||
620 | for (i = 0; i < j; i++) { | ||
621 | outb(*pstr, GSCDPORT(2)); | ||
622 | pstr++; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | |||
627 | static int cmd_unit_alive(void) | ||
628 | { | ||
629 | int result; | ||
630 | unsigned long max_test_loops; | ||
631 | |||
632 | |||
633 | /* LOC_172 */ | ||
634 | #ifdef GSCD_DEBUG | ||
635 | printk("LOC_172 "); | ||
636 | #endif | ||
637 | |||
638 | outb(curr_drv_state, GSCDPORT(0)); | ||
639 | max_test_loops = 0xFFFF; | ||
640 | |||
641 | do { | ||
642 | result = wait_drv_ready(); | ||
643 | max_test_loops--; | ||
644 | } while ((result != 0x08) && (max_test_loops > 0)); | ||
645 | |||
646 | return result; | ||
647 | } | ||
648 | |||
649 | |||
650 | static void cmd_info_in(char *pb, int count) | ||
651 | { | ||
652 | int result; | ||
653 | char read; | ||
654 | |||
655 | |||
656 | /* read info */ | ||
657 | /* LOC_182 */ | ||
658 | #ifdef GSCD_DEBUG | ||
659 | printk("LOC_182 "); | ||
660 | #endif | ||
661 | |||
662 | do { | ||
663 | read = inb(GSCDPORT(2)); | ||
664 | if (count > 0) { | ||
665 | *pb = read; | ||
666 | pb++; | ||
667 | count--; | ||
668 | } | ||
669 | |||
670 | /* LOC_183 */ | ||
671 | do { | ||
672 | result = wait_drv_ready(); | ||
673 | } while (result == 0x0E); | ||
674 | } while (result == 6); | ||
675 | |||
676 | cmd_end(); | ||
677 | return; | ||
678 | } | ||
679 | |||
680 | |||
681 | static void cmd_read_b(char *pb, int count, int size) | ||
682 | { | ||
683 | int result; | ||
684 | int i; | ||
685 | |||
686 | |||
687 | /* LOC_188 */ | ||
688 | /* LOC_189 */ | ||
689 | #ifdef GSCD_DEBUG | ||
690 | printk("LOC_189 "); | ||
691 | #endif | ||
692 | |||
693 | do { | ||
694 | do { | ||
695 | result = wait_drv_ready(); | ||
696 | } while (result != 6 || result == 0x0E); | ||
697 | |||
698 | if (result != 6) { | ||
699 | cmd_end(); | ||
700 | return; | ||
701 | } | ||
702 | #ifdef GSCD_DEBUG | ||
703 | printk("LOC_191 "); | ||
704 | #endif | ||
705 | |||
706 | for (i = 0; i < size; i++) { | ||
707 | *pb = inb(GSCDPORT(2)); | ||
708 | pb++; | ||
709 | } | ||
710 | count--; | ||
711 | } while (count > 0); | ||
712 | |||
713 | cmd_end(); | ||
714 | return; | ||
715 | } | ||
716 | |||
717 | |||
718 | static void cmd_end(void) | ||
719 | { | ||
720 | int result; | ||
721 | |||
722 | |||
723 | /* LOC_204 */ | ||
724 | #ifdef GSCD_DEBUG | ||
725 | printk("LOC_204 "); | ||
726 | #endif | ||
727 | |||
728 | do { | ||
729 | result = wait_drv_ready(); | ||
730 | if (result == drv_mode) { | ||
731 | return; | ||
732 | } | ||
733 | } while (result != 4); | ||
734 | |||
735 | /* LOC_205 */ | ||
736 | #ifdef GSCD_DEBUG | ||
737 | printk("LOC_205 "); | ||
738 | #endif | ||
739 | |||
740 | disk_state = inb(GSCDPORT(2)); | ||
741 | |||
742 | do { | ||
743 | result = wait_drv_ready(); | ||
744 | } while (result != drv_mode); | ||
745 | return; | ||
746 | |||
747 | } | ||
748 | |||
749 | |||
750 | static void cmd_read_w(char *pb, int count, int size) | ||
751 | { | ||
752 | int result; | ||
753 | int i; | ||
754 | |||
755 | |||
756 | #ifdef GSCD_DEBUG | ||
757 | printk("LOC_185 "); | ||
758 | #endif | ||
759 | |||
760 | do { | ||
761 | /* LOC_185 */ | ||
762 | do { | ||
763 | result = wait_drv_ready(); | ||
764 | } while (result != 6 || result == 0x0E); | ||
765 | |||
766 | if (result != 6) { | ||
767 | cmd_end(); | ||
768 | return; | ||
769 | } | ||
770 | |||
771 | for (i = 0; i < size; i++) { | ||
772 | /* na, hier muss ich noch mal drueber nachdenken */ | ||
773 | *pb = inw(GSCDPORT(2)); | ||
774 | pb++; | ||
775 | } | ||
776 | count--; | ||
777 | } while (count > 0); | ||
778 | |||
779 | cmd_end(); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | static int __init find_drives(void) | ||
784 | { | ||
785 | int *pdrv; | ||
786 | int drvnum; | ||
787 | int subdrv; | ||
788 | int i; | ||
789 | |||
790 | speed = 0; | ||
791 | pdrv = (int *) &drv_states; | ||
792 | curr_drv_state = 0xFE; | ||
793 | subdrv = 0; | ||
794 | drvnum = 0; | ||
795 | |||
796 | for (i = 0; i < 8; i++) { | ||
797 | subdrv++; | ||
798 | cmd_status(); | ||
799 | disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01; | ||
800 | if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) { | ||
801 | /* LOC_240 */ | ||
802 | *pdrv = curr_drv_state; | ||
803 | init_cd_drive(drvnum); | ||
804 | pdrv++; | ||
805 | drvnum++; | ||
806 | } else { | ||
807 | if (subdrv < 2) { | ||
808 | continue; | ||
809 | } else { | ||
810 | subdrv = 0; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | /* curr_drv_state<<1; <-- das geht irgendwie nicht */ | ||
815 | /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */ | ||
816 | curr_drv_state *= 2; | ||
817 | curr_drv_state |= 1; | ||
818 | #ifdef GSCD_DEBUG | ||
819 | printk("DriveState: %d\n", curr_drv_state); | ||
820 | #endif | ||
821 | } | ||
822 | |||
823 | ndrives = drvnum; | ||
824 | return drvnum; | ||
825 | } | ||
826 | |||
827 | static void __init init_cd_drive(int num) | ||
828 | { | ||
829 | char resp[50]; | ||
830 | int i; | ||
831 | |||
832 | printk("GSCD: init unit %d\n", num); | ||
833 | cc_Ident((char *) &resp); | ||
834 | |||
835 | printk("GSCD: identification: "); | ||
836 | for (i = 0; i < 0x1E; i++) { | ||
837 | printk("%c", resp[i]); | ||
838 | } | ||
839 | printk("\n"); | ||
840 | |||
841 | cc_SetSpeed(); | ||
842 | |||
843 | } | ||
844 | |||
845 | #ifdef FUTURE_WORK | ||
846 | /* return_done */ | ||
847 | static void update_state(void) | ||
848 | { | ||
849 | unsigned int AX; | ||
850 | |||
851 | |||
852 | if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) { | ||
853 | if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) { | ||
854 | AX = ST_INVALID; | ||
855 | } | ||
856 | |||
857 | if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) | ||
858 | == 0) { | ||
859 | invalidate(); | ||
860 | f_drv_ok = 0; | ||
861 | } | ||
862 | |||
863 | AX |= 0x8000; | ||
864 | } | ||
865 | |||
866 | if (disk_state & ST_PLAYING) { | ||
867 | AX |= 0x200; | ||
868 | } | ||
869 | |||
870 | AX |= 0x100; | ||
871 | /* pkt_esbx = AX; */ | ||
872 | |||
873 | disk_state = 0; | ||
874 | |||
875 | } | ||
876 | #endif | ||
877 | |||
878 | static struct gendisk *gscd_disk; | ||
879 | |||
880 | static void __exit gscd_exit(void) | ||
881 | { | ||
882 | CLEAR_TIMER; | ||
883 | |||
884 | del_gendisk(gscd_disk); | ||
885 | put_disk(gscd_disk); | ||
886 | if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) { | ||
887 | printk("What's that: can't unregister GoldStar-module\n"); | ||
888 | return; | ||
889 | } | ||
890 | blk_cleanup_queue(gscd_queue); | ||
891 | release_region(gscd_port, GSCD_IO_EXTENT); | ||
892 | printk(KERN_INFO "GoldStar-module released.\n"); | ||
893 | } | ||
894 | |||
895 | /* This is the common initialisation for the GoldStar drive. */ | ||
896 | /* It is called at boot time AND for module init. */ | ||
897 | static int __init gscd_init(void) | ||
898 | { | ||
899 | int i; | ||
900 | int result; | ||
901 | int ret=0; | ||
902 | |||
903 | printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION); | ||
904 | printk(KERN_INFO | ||
905 | "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", | ||
906 | gscd_port); | ||
907 | |||
908 | if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) { | ||
909 | printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already" | ||
910 | " in use.\n", gscd_port); | ||
911 | return -EIO; | ||
912 | } | ||
913 | |||
914 | |||
915 | /* check for card */ | ||
916 | result = wait_drv_ready(); | ||
917 | if (result == 0x09) { | ||
918 | printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n"); | ||
919 | ret = -EIO; | ||
920 | goto err_out1; | ||
921 | } | ||
922 | |||
923 | if (result == 0x0b) { | ||
924 | drv_mode = result; | ||
925 | i = find_drives(); | ||
926 | if (i == 0) { | ||
927 | printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is" | ||
928 | " not found.\n"); | ||
929 | ret = -EIO; | ||
930 | goto err_out1; | ||
931 | } | ||
932 | } | ||
933 | |||
934 | if ((result != 0x0b) && (result != 0x09)) { | ||
935 | printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not " | ||
936 | "exist or H/W error\n"); | ||
937 | ret = -EIO; | ||
938 | goto err_out1; | ||
939 | } | ||
940 | |||
941 | /* reset all drives */ | ||
942 | i = 0; | ||
943 | while (drv_states[i] != 0) { | ||
944 | curr_drv_state = drv_states[i]; | ||
945 | printk(KERN_INFO "GSCD: Reset unit %d ... ", i); | ||
946 | cc_Reset(); | ||
947 | printk("done\n"); | ||
948 | i++; | ||
949 | } | ||
950 | |||
951 | gscd_disk = alloc_disk(1); | ||
952 | if (!gscd_disk) | ||
953 | goto err_out1; | ||
954 | gscd_disk->major = MAJOR_NR; | ||
955 | gscd_disk->first_minor = 0; | ||
956 | gscd_disk->fops = &gscd_fops; | ||
957 | sprintf(gscd_disk->disk_name, "gscd"); | ||
958 | sprintf(gscd_disk->devfs_name, "gscd"); | ||
959 | |||
960 | if (register_blkdev(MAJOR_NR, "gscd")) { | ||
961 | ret = -EIO; | ||
962 | goto err_out2; | ||
963 | } | ||
964 | |||
965 | gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock); | ||
966 | if (!gscd_queue) { | ||
967 | ret = -ENOMEM; | ||
968 | goto err_out3; | ||
969 | } | ||
970 | |||
971 | disk_state = 0; | ||
972 | gscdPresent = 1; | ||
973 | |||
974 | gscd_disk->queue = gscd_queue; | ||
975 | add_disk(gscd_disk); | ||
976 | |||
977 | printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); | ||
978 | return 0; | ||
979 | |||
980 | err_out3: | ||
981 | unregister_blkdev(MAJOR_NR, "gscd"); | ||
982 | err_out2: | ||
983 | put_disk(gscd_disk); | ||
984 | err_out1: | ||
985 | release_region(gscd_port, GSCD_IO_EXTENT); | ||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | static void gscd_hsg2msf(long hsg, struct msf *msf) | ||
990 | { | ||
991 | hsg += CD_MSF_OFFSET; | ||
992 | msf->min = hsg / (CD_FRAMES * CD_SECS); | ||
993 | hsg %= CD_FRAMES * CD_SECS; | ||
994 | msf->sec = hsg / CD_FRAMES; | ||
995 | msf->frame = hsg % CD_FRAMES; | ||
996 | |||
997 | gscd_bin2bcd(&msf->min); /* convert to BCD */ | ||
998 | gscd_bin2bcd(&msf->sec); | ||
999 | gscd_bin2bcd(&msf->frame); | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | static void gscd_bin2bcd(unsigned char *p) | ||
1004 | { | ||
1005 | int u, t; | ||
1006 | |||
1007 | u = *p % 10; | ||
1008 | t = *p / 10; | ||
1009 | *p = u | (t << 4); | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | #ifdef FUTURE_WORK | ||
1014 | static long gscd_msf2hsg(struct msf *mp) | ||
1015 | { | ||
1016 | return gscd_bcd2bin(mp->frame) | ||
1017 | + gscd_bcd2bin(mp->sec) * CD_FRAMES | ||
1018 | + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET; | ||
1019 | } | ||
1020 | |||
1021 | static int gscd_bcd2bin(unsigned char bcd) | ||
1022 | { | ||
1023 | return (bcd >> 4) * 10 + (bcd & 0xF); | ||
1024 | } | ||
1025 | #endif | ||
1026 | |||
1027 | MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"); | ||
1028 | MODULE_LICENSE("GPL"); | ||
1029 | module_init(gscd_init); | ||
1030 | module_exit(gscd_exit); | ||
1031 | MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/gscd.h b/drivers/cdrom/gscd.h new file mode 100644 index 000000000000..a41e64bfc061 --- /dev/null +++ b/drivers/cdrom/gscd.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Definitions for a GoldStar R420 CD-ROM interface | ||
3 | * | ||
4 | * Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de> | ||
5 | * Eberhard Moenkeberg <emoenke@gwdg.de> | ||
6 | * | ||
7 | * Published under the GPL. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | |||
12 | /* The Interface Card default address is 0x340. This will work for most | ||
13 | applications. Address selection is accomplished by jumpers PN801-1 to | ||
14 | PN801-4 on the GoldStar Interface Card. | ||
15 | Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360 | ||
16 | 0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0 */ | ||
17 | |||
18 | /* insert here the I/O port address and extent */ | ||
19 | #define GSCD_BASE_ADDR 0x340 | ||
20 | #define GSCD_IO_EXTENT 4 | ||
21 | |||
22 | |||
23 | /************** nothing to set up below here *********************/ | ||
24 | |||
25 | /* port access macro */ | ||
26 | #define GSCDPORT(x) (gscd_port + (x)) | ||
27 | |||
28 | /* | ||
29 | * commands | ||
30 | * the lower nibble holds the command length | ||
31 | */ | ||
32 | #define CMD_STATUS 0x01 | ||
33 | #define CMD_READSUBQ 0x02 /* 1: ?, 2: UPC, 5: ? */ | ||
34 | #define CMD_SEEK 0x05 /* read_mode M-S-F */ | ||
35 | #define CMD_READ 0x07 /* read_mode M-S-F nsec_h nsec_l */ | ||
36 | #define CMD_RESET 0x11 | ||
37 | #define CMD_SETMODE 0x15 | ||
38 | #define CMD_PLAY 0x17 /* M-S-F M-S-F */ | ||
39 | #define CMD_LOCK_CTL 0x22 /* 0: unlock, 1: lock */ | ||
40 | #define CMD_IDENT 0x31 | ||
41 | #define CMD_SETSPEED 0x32 /* 0: auto */ /* ??? */ | ||
42 | #define CMD_GETMODE 0x41 | ||
43 | #define CMD_PAUSE 0x51 | ||
44 | #define CMD_READTOC 0x61 | ||
45 | #define CMD_DISKINFO 0x71 | ||
46 | #define CMD_TRAY_CTL 0x81 | ||
47 | |||
48 | /* | ||
49 | * disk_state: | ||
50 | */ | ||
51 | #define ST_PLAYING 0x80 | ||
52 | #define ST_UNLOCKED 0x40 | ||
53 | #define ST_NO_DISK 0x20 | ||
54 | #define ST_DOOR_OPEN 0x10 | ||
55 | #define ST_x08 0x08 | ||
56 | #define ST_x04 0x04 | ||
57 | #define ST_INVALID 0x02 | ||
58 | #define ST_x01 0x01 | ||
59 | |||
60 | /* | ||
61 | * cmd_type: | ||
62 | */ | ||
63 | #define TYPE_INFO 0x01 | ||
64 | #define TYPE_DATA 0x02 | ||
65 | |||
66 | /* | ||
67 | * read_mode: | ||
68 | */ | ||
69 | #define MOD_POLLED 0x80 | ||
70 | #define MOD_x08 0x08 | ||
71 | #define MOD_RAW 0x04 | ||
72 | |||
73 | #define READ_DATA(port, buf, nr) insb(port, buf, nr) | ||
74 | |||
75 | #define SET_TIMER(func, jifs) \ | ||
76 | ((mod_timer(&gscd_timer, jiffies + jifs)), \ | ||
77 | (gscd_timer.function = func)) | ||
78 | |||
79 | #define CLEAR_TIMER del_timer_sync(&gscd_timer) | ||
80 | |||
81 | #define MAX_TRACKS 104 | ||
82 | |||
83 | struct msf { | ||
84 | unsigned char min; | ||
85 | unsigned char sec; | ||
86 | unsigned char frame; | ||
87 | }; | ||
88 | |||
89 | struct gscd_Play_msf { | ||
90 | struct msf start; | ||
91 | struct msf end; | ||
92 | }; | ||
93 | |||
94 | struct gscd_DiskInfo { | ||
95 | unsigned char first; | ||
96 | unsigned char last; | ||
97 | struct msf diskLength; | ||
98 | struct msf firstTrack; | ||
99 | }; | ||
100 | |||
101 | struct gscd_Toc { | ||
102 | unsigned char ctrl_addr; | ||
103 | unsigned char track; | ||
104 | unsigned char pointIndex; | ||
105 | struct msf trackTime; | ||
106 | struct msf diskTime; | ||
107 | }; | ||
108 | |||
diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c new file mode 100644 index 000000000000..8e68d858ce64 --- /dev/null +++ b/drivers/cdrom/isp16.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* -- ISP16 cdrom detection and configuration | ||
2 | * | ||
3 | * Copyright (c) 1995,1996 Eric van der Maarel <H.T.M.v.d.Maarel@marin.nl> | ||
4 | * | ||
5 | * Version 0.6 | ||
6 | * | ||
7 | * History: | ||
8 | * 0.5 First release. | ||
9 | * Was included in the sjcd and optcd cdrom drivers. | ||
10 | * 0.6 First "stand-alone" version. | ||
11 | * Removed sound configuration. | ||
12 | * Added "module" support. | ||
13 | * | ||
14 | * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
15 | * Removed init_module & cleanup_module in favor of | ||
16 | * module_init & module_exit. | ||
17 | * Torben Mathiasen <tmm@image.dk> | ||
18 | * | ||
19 | * 19 June 2004 -- check_region() converted to request_region() | ||
20 | * and return statement cleanups. | ||
21 | * Jesper Juhl <juhl-lkml@dif.dk> | ||
22 | * | ||
23 | * Detect cdrom interface on ISP16 sound card. | ||
24 | * Configure cdrom interface. | ||
25 | * | ||
26 | * Algorithm for the card with OPTi 82C928 taken | ||
27 | * from the CDSETUP.SYS driver for MSDOS, | ||
28 | * by OPTi Computers, version 2.03. | ||
29 | * Algorithm for the card with OPTi 82C929 as communicated | ||
30 | * to me by Vadim Model and Leo Spiekman. | ||
31 | * | ||
32 | * This program is free software; you can redistribute it and/or modify | ||
33 | * it under the terms of the GNU General Public License as published by | ||
34 | * the Free Software Foundation; either version 2 of the License, or | ||
35 | * (at your option) any later version. | ||
36 | * | ||
37 | * This program is distributed in the hope that it will be useful, | ||
38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
40 | * GNU General Public License for more details. | ||
41 | * | ||
42 | * You should have received a copy of the GNU General Public License | ||
43 | * along with this program; if not, write to the Free Software | ||
44 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
45 | * | ||
46 | */ | ||
47 | |||
48 | #define ISP16_VERSION_MAJOR 0 | ||
49 | #define ISP16_VERSION_MINOR 6 | ||
50 | |||
51 | #include <linux/module.h> | ||
52 | |||
53 | #include <linux/fs.h> | ||
54 | #include <linux/kernel.h> | ||
55 | #include <linux/string.h> | ||
56 | #include <linux/ioport.h> | ||
57 | #include <linux/init.h> | ||
58 | #include <asm/io.h> | ||
59 | #include "isp16.h" | ||
60 | |||
61 | static short isp16_detect(void); | ||
62 | static short isp16_c928__detect(void); | ||
63 | static short isp16_c929__detect(void); | ||
64 | static short isp16_cdi_config(int base, u_char drive_type, int irq, | ||
65 | int dma); | ||
66 | static short isp16_type; /* dependent on type of interface card */ | ||
67 | static u_char isp16_ctrl; | ||
68 | static u_short isp16_enable_port; | ||
69 | |||
70 | static int isp16_cdrom_base = ISP16_CDROM_IO_BASE; | ||
71 | static int isp16_cdrom_irq = ISP16_CDROM_IRQ; | ||
72 | static int isp16_cdrom_dma = ISP16_CDROM_DMA; | ||
73 | static char *isp16_cdrom_type = ISP16_CDROM_TYPE; | ||
74 | |||
75 | module_param(isp16_cdrom_base, int, 0); | ||
76 | module_param(isp16_cdrom_irq, int, 0); | ||
77 | module_param(isp16_cdrom_dma, int, 0); | ||
78 | module_param(isp16_cdrom_type, charp, 0); | ||
79 | |||
80 | #define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) | ||
81 | #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) | ||
82 | |||
83 | #ifndef MODULE | ||
84 | |||
85 | static int | ||
86 | __init isp16_setup(char *str) | ||
87 | { | ||
88 | int ints[4]; | ||
89 | |||
90 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
91 | if (ints[0] > 0) | ||
92 | isp16_cdrom_base = ints[1]; | ||
93 | if (ints[0] > 1) | ||
94 | isp16_cdrom_irq = ints[2]; | ||
95 | if (ints[0] > 2) | ||
96 | isp16_cdrom_dma = ints[3]; | ||
97 | if (str) | ||
98 | isp16_cdrom_type = str; | ||
99 | |||
100 | return 1; | ||
101 | } | ||
102 | |||
103 | __setup("isp16=", isp16_setup); | ||
104 | |||
105 | #endif /* MODULE */ | ||
106 | |||
107 | /* | ||
108 | * ISP16 initialisation. | ||
109 | * | ||
110 | */ | ||
111 | static int __init isp16_init(void) | ||
112 | { | ||
113 | u_char expected_drive; | ||
114 | |||
115 | printk(KERN_INFO | ||
116 | "ISP16: configuration cdrom interface, version %d.%d.\n", | ||
117 | ISP16_VERSION_MAJOR, ISP16_VERSION_MINOR); | ||
118 | |||
119 | if (!strcmp(isp16_cdrom_type, "noisp16")) { | ||
120 | printk("ISP16: no cdrom interface configured.\n"); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | if (!request_region(ISP16_IO_BASE, ISP16_IO_SIZE, "isp16")) { | ||
125 | printk("ISP16: i/o ports already in use.\n"); | ||
126 | goto out; | ||
127 | } | ||
128 | |||
129 | if ((isp16_type = isp16_detect()) < 0) { | ||
130 | printk("ISP16: no cdrom interface found.\n"); | ||
131 | goto cleanup_out; | ||
132 | } | ||
133 | |||
134 | printk(KERN_INFO | ||
135 | "ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n", | ||
136 | (isp16_type == 2) ? 9 : 8); | ||
137 | |||
138 | if (!strcmp(isp16_cdrom_type, "Sanyo")) | ||
139 | expected_drive = | ||
140 | (isp16_type ? ISP16_SANYO1 : ISP16_SANYO0); | ||
141 | else if (!strcmp(isp16_cdrom_type, "Sony")) | ||
142 | expected_drive = ISP16_SONY; | ||
143 | else if (!strcmp(isp16_cdrom_type, "Panasonic")) | ||
144 | expected_drive = | ||
145 | (isp16_type ? ISP16_PANASONIC1 : ISP16_PANASONIC0); | ||
146 | else if (!strcmp(isp16_cdrom_type, "Mitsumi")) | ||
147 | expected_drive = ISP16_MITSUMI; | ||
148 | else { | ||
149 | printk("ISP16: %s not supported by cdrom interface.\n", | ||
150 | isp16_cdrom_type); | ||
151 | goto cleanup_out; | ||
152 | } | ||
153 | |||
154 | if (isp16_cdi_config(isp16_cdrom_base, expected_drive, | ||
155 | isp16_cdrom_irq, isp16_cdrom_dma) < 0) { | ||
156 | printk | ||
157 | ("ISP16: cdrom interface has not been properly configured.\n"); | ||
158 | goto cleanup_out; | ||
159 | } | ||
160 | printk(KERN_INFO | ||
161 | "ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d," | ||
162 | " type %s.\n", isp16_cdrom_base, isp16_cdrom_irq, | ||
163 | isp16_cdrom_dma, isp16_cdrom_type); | ||
164 | return 0; | ||
165 | |||
166 | cleanup_out: | ||
167 | release_region(ISP16_IO_BASE, ISP16_IO_SIZE); | ||
168 | out: | ||
169 | return -EIO; | ||
170 | } | ||
171 | |||
172 | static short __init isp16_detect(void) | ||
173 | { | ||
174 | |||
175 | if (isp16_c929__detect() >= 0) | ||
176 | return 2; | ||
177 | else | ||
178 | return (isp16_c928__detect()); | ||
179 | } | ||
180 | |||
181 | static short __init isp16_c928__detect(void) | ||
182 | { | ||
183 | u_char ctrl; | ||
184 | u_char enable_cdrom; | ||
185 | u_char io; | ||
186 | short i = -1; | ||
187 | |||
188 | isp16_ctrl = ISP16_C928__CTRL; | ||
189 | isp16_enable_port = ISP16_C928__ENABLE_PORT; | ||
190 | |||
191 | /* read' and write' are a special read and write, respectively */ | ||
192 | |||
193 | /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ | ||
194 | ctrl = ISP16_IN(ISP16_CTRL_PORT) & 0xFC; | ||
195 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
196 | |||
197 | /* read' 3,4 and 5-bit from the cdrom enable port */ | ||
198 | enable_cdrom = ISP16_IN(ISP16_C928__ENABLE_PORT) & 0x38; | ||
199 | |||
200 | if (!(enable_cdrom & 0x20)) { /* 5-bit not set */ | ||
201 | /* read' last 2 bits of ISP16_IO_SET_PORT */ | ||
202 | io = ISP16_IN(ISP16_IO_SET_PORT) & 0x03; | ||
203 | if (((io & 0x01) << 1) == (io & 0x02)) { /* bits are the same */ | ||
204 | if (io == 0) { /* ...the same and 0 */ | ||
205 | i = 0; | ||
206 | enable_cdrom |= 0x20; | ||
207 | } else { /* ...the same and 1 *//* my card, first time 'round */ | ||
208 | i = 1; | ||
209 | enable_cdrom |= 0x28; | ||
210 | } | ||
211 | ISP16_OUT(ISP16_C928__ENABLE_PORT, enable_cdrom); | ||
212 | } else { /* bits are not the same */ | ||
213 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
214 | return i; /* -> not detected: possibly incorrect conclusion */ | ||
215 | } | ||
216 | } else if (enable_cdrom == 0x20) | ||
217 | i = 0; | ||
218 | else if (enable_cdrom == 0x28) /* my card, already initialised */ | ||
219 | i = 1; | ||
220 | |||
221 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
222 | |||
223 | return i; | ||
224 | } | ||
225 | |||
226 | static short __init isp16_c929__detect(void) | ||
227 | { | ||
228 | u_char ctrl; | ||
229 | u_char tmp; | ||
230 | |||
231 | isp16_ctrl = ISP16_C929__CTRL; | ||
232 | isp16_enable_port = ISP16_C929__ENABLE_PORT; | ||
233 | |||
234 | /* read' and write' are a special read and write, respectively */ | ||
235 | |||
236 | /* read' ISP16_CTRL_PORT and save */ | ||
237 | ctrl = ISP16_IN(ISP16_CTRL_PORT); | ||
238 | |||
239 | /* write' zero to the ctrl port and get response */ | ||
240 | ISP16_OUT(ISP16_CTRL_PORT, 0); | ||
241 | tmp = ISP16_IN(ISP16_CTRL_PORT); | ||
242 | |||
243 | if (tmp != 2) /* isp16 with 82C929 not detected */ | ||
244 | return -1; | ||
245 | |||
246 | /* restore ctrl port value */ | ||
247 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
248 | |||
249 | return 2; | ||
250 | } | ||
251 | |||
252 | static short __init | ||
253 | isp16_cdi_config(int base, u_char drive_type, int irq, int dma) | ||
254 | { | ||
255 | u_char base_code; | ||
256 | u_char irq_code; | ||
257 | u_char dma_code; | ||
258 | u_char i; | ||
259 | |||
260 | if ((drive_type == ISP16_MITSUMI) && (dma != 0)) | ||
261 | printk("ISP16: Mitsumi cdrom drive has no dma support.\n"); | ||
262 | |||
263 | switch (base) { | ||
264 | case 0x340: | ||
265 | base_code = ISP16_BASE_340; | ||
266 | break; | ||
267 | case 0x330: | ||
268 | base_code = ISP16_BASE_330; | ||
269 | break; | ||
270 | case 0x360: | ||
271 | base_code = ISP16_BASE_360; | ||
272 | break; | ||
273 | case 0x320: | ||
274 | base_code = ISP16_BASE_320; | ||
275 | break; | ||
276 | default: | ||
277 | printk | ||
278 | ("ISP16: base address 0x%03X not supported by cdrom interface.\n", | ||
279 | base); | ||
280 | return -1; | ||
281 | } | ||
282 | switch (irq) { | ||
283 | case 0: | ||
284 | irq_code = ISP16_IRQ_X; | ||
285 | break; /* disable irq */ | ||
286 | case 5: | ||
287 | irq_code = ISP16_IRQ_5; | ||
288 | printk("ISP16: irq 5 shouldn't be used by cdrom interface," | ||
289 | " due to possible conflicts with the sound card.\n"); | ||
290 | break; | ||
291 | case 7: | ||
292 | irq_code = ISP16_IRQ_7; | ||
293 | printk("ISP16: irq 7 shouldn't be used by cdrom interface," | ||
294 | " due to possible conflicts with the sound card.\n"); | ||
295 | break; | ||
296 | case 3: | ||
297 | irq_code = ISP16_IRQ_3; | ||
298 | break; | ||
299 | case 9: | ||
300 | irq_code = ISP16_IRQ_9; | ||
301 | break; | ||
302 | case 10: | ||
303 | irq_code = ISP16_IRQ_10; | ||
304 | break; | ||
305 | case 11: | ||
306 | irq_code = ISP16_IRQ_11; | ||
307 | break; | ||
308 | default: | ||
309 | printk("ISP16: irq %d not supported by cdrom interface.\n", | ||
310 | irq); | ||
311 | return -1; | ||
312 | } | ||
313 | switch (dma) { | ||
314 | case 0: | ||
315 | dma_code = ISP16_DMA_X; | ||
316 | break; /* disable dma */ | ||
317 | case 1: | ||
318 | printk("ISP16: dma 1 cannot be used by cdrom interface," | ||
319 | " due to conflict with the sound card.\n"); | ||
320 | return -1; | ||
321 | break; | ||
322 | case 3: | ||
323 | dma_code = ISP16_DMA_3; | ||
324 | break; | ||
325 | case 5: | ||
326 | dma_code = ISP16_DMA_5; | ||
327 | break; | ||
328 | case 6: | ||
329 | dma_code = ISP16_DMA_6; | ||
330 | break; | ||
331 | case 7: | ||
332 | dma_code = ISP16_DMA_7; | ||
333 | break; | ||
334 | default: | ||
335 | printk("ISP16: dma %d not supported by cdrom interface.\n", | ||
336 | dma); | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | if (drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && | ||
341 | drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && | ||
342 | drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && | ||
343 | drive_type != ISP16_DRIVE_X) { | ||
344 | printk | ||
345 | ("ISP16: drive type (code 0x%02X) not supported by cdrom" | ||
346 | " interface.\n", drive_type); | ||
347 | return -1; | ||
348 | } | ||
349 | |||
350 | /* set type of interface */ | ||
351 | i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ | ||
352 | ISP16_OUT(ISP16_DRIVE_SET_PORT, i | drive_type); | ||
353 | |||
354 | /* enable cdrom on interface with 82C929 chip */ | ||
355 | if (isp16_type > 1) | ||
356 | ISP16_OUT(isp16_enable_port, ISP16_ENABLE_CDROM); | ||
357 | |||
358 | /* set base address, irq and dma */ | ||
359 | i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ | ||
360 | ISP16_OUT(ISP16_IO_SET_PORT, i | base_code | irq_code | dma_code); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static void __exit isp16_exit(void) | ||
366 | { | ||
367 | release_region(ISP16_IO_BASE, ISP16_IO_SIZE); | ||
368 | printk(KERN_INFO "ISP16: module released.\n"); | ||
369 | } | ||
370 | |||
371 | module_init(isp16_init); | ||
372 | module_exit(isp16_exit); | ||
373 | |||
374 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cdrom/isp16.h b/drivers/cdrom/isp16.h new file mode 100644 index 000000000000..5bd22c8f7a96 --- /dev/null +++ b/drivers/cdrom/isp16.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* -- isp16.h | ||
2 | * | ||
3 | * Header for detection and initialisation of cdrom interface (only) on | ||
4 | * ISP16 (MAD16, Mozart) sound card. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program 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 | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* These are the default values */ | ||
23 | #define ISP16_CDROM_TYPE "Sanyo" | ||
24 | #define ISP16_CDROM_IO_BASE 0x340 | ||
25 | #define ISP16_CDROM_IRQ 0 | ||
26 | #define ISP16_CDROM_DMA 0 | ||
27 | |||
28 | /* Some (Media)Magic */ | ||
29 | /* define types of drive the interface on an ISP16 card may be looking at */ | ||
30 | #define ISP16_DRIVE_X 0x00 | ||
31 | #define ISP16_SONY 0x02 | ||
32 | #define ISP16_PANASONIC0 0x02 | ||
33 | #define ISP16_SANYO0 0x02 | ||
34 | #define ISP16_MITSUMI 0x04 | ||
35 | #define ISP16_PANASONIC1 0x06 | ||
36 | #define ISP16_SANYO1 0x06 | ||
37 | #define ISP16_DRIVE_NOT_USED 0x08 /* not used */ | ||
38 | #define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/ | ||
39 | /* ...for port */ | ||
40 | #define ISP16_DRIVE_SET_PORT 0xF8D | ||
41 | /* set io parameters */ | ||
42 | #define ISP16_BASE_340 0x00 | ||
43 | #define ISP16_BASE_330 0x40 | ||
44 | #define ISP16_BASE_360 0x80 | ||
45 | #define ISP16_BASE_320 0xC0 | ||
46 | #define ISP16_IRQ_X 0x00 | ||
47 | #define ISP16_IRQ_5 0x04 /* shouldn't be used to avoid sound card conflicts */ | ||
48 | #define ISP16_IRQ_7 0x08 /* shouldn't be used to avoid sound card conflicts */ | ||
49 | #define ISP16_IRQ_3 0x0C | ||
50 | #define ISP16_IRQ_9 0x10 | ||
51 | #define ISP16_IRQ_10 0x14 | ||
52 | #define ISP16_IRQ_11 0x18 | ||
53 | #define ISP16_DMA_X 0x03 | ||
54 | #define ISP16_DMA_3 0x00 | ||
55 | #define ISP16_DMA_5 0x00 | ||
56 | #define ISP16_DMA_6 0x01 | ||
57 | #define ISP16_DMA_7 0x02 | ||
58 | #define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */ | ||
59 | /* ...for port */ | ||
60 | #define ISP16_IO_SET_PORT 0xF8E | ||
61 | /* enable the card */ | ||
62 | #define ISP16_C928__ENABLE_PORT 0xF90 /* ISP16 with OPTi 82C928 chip */ | ||
63 | #define ISP16_C929__ENABLE_PORT 0xF91 /* ISP16 with OPTi 82C929 chip */ | ||
64 | #define ISP16_ENABLE_CDROM 0x80 /* seven bit */ | ||
65 | |||
66 | /* the magic stuff */ | ||
67 | #define ISP16_CTRL_PORT 0xF8F | ||
68 | #define ISP16_C928__CTRL 0xE2 /* ISP16 with OPTi 82C928 chip */ | ||
69 | #define ISP16_C929__CTRL 0xE3 /* ISP16 with OPTi 82C929 chip */ | ||
70 | |||
71 | #define ISP16_IO_BASE 0xF8D | ||
72 | #define ISP16_IO_SIZE 5 /* ports used from 0xF8D up to 0xF91 */ | ||
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c new file mode 100644 index 000000000000..ccde7ab491d4 --- /dev/null +++ b/drivers/cdrom/mcdx.c | |||
@@ -0,0 +1,1952 @@ | |||
1 | /* | ||
2 | * The Mitsumi CDROM interface | ||
3 | * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de> | ||
4 | * VERSION: 2.14(hs) | ||
5 | * | ||
6 | * ... anyway, I'm back again, thanks to Marcin, he adopted | ||
7 | * large portions of my code (at least the parts containing | ||
8 | * my main thoughts ...) | ||
9 | * | ||
10 | ****************** H E L P ********************************* | ||
11 | * If you ever plan to update your CD ROM drive and perhaps | ||
12 | * want to sell or simply give away your Mitsumi FX-001[DS] | ||
13 | * -- Please -- | ||
14 | * mail me (heiko@lotte.sax.de). When my last drive goes | ||
15 | * ballistic no more driver support will be available from me! | ||
16 | ************************************************************* | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation; either version 2, or (at your option) | ||
21 | * any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; see the file COPYING. If not, write to | ||
30 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | * | ||
32 | * Thanks to | ||
33 | * The Linux Community at all and ... | ||
34 | * Martin Harriss (he wrote the first Mitsumi Driver) | ||
35 | * Eberhard Moenkeberg (he gave me much support and the initial kick) | ||
36 | * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they | ||
37 | * improved the original driver) | ||
38 | * Jon Tombs, Bjorn Ekwall (module support) | ||
39 | * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) | ||
40 | * Gerd Knorr (he lent me his PhotoCD) | ||
41 | * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) | ||
42 | * Andreas Kies (testing the mysterious hang-ups) | ||
43 | * Heiko Eissfeldt (VERIFY_READ/WRITE) | ||
44 | * Marcin Dalecki (improved performance, shortened code) | ||
45 | * ... somebody forgotten? | ||
46 | * | ||
47 | * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
48 | * Removed init_module & cleanup_module in favor of | ||
49 | * module_init & module_exit. | ||
50 | * Torben Mathiasen <tmm@image.dk> | ||
51 | */ | ||
52 | |||
53 | |||
54 | #if RCS | ||
55 | static const char *mcdx_c_version | ||
56 | = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $"; | ||
57 | #endif | ||
58 | |||
59 | #include <linux/module.h> | ||
60 | |||
61 | #include <linux/errno.h> | ||
62 | #include <linux/interrupt.h> | ||
63 | #include <linux/fs.h> | ||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/cdrom.h> | ||
66 | #include <linux/ioport.h> | ||
67 | #include <linux/mm.h> | ||
68 | #include <linux/slab.h> | ||
69 | #include <linux/init.h> | ||
70 | #include <asm/io.h> | ||
71 | #include <asm/current.h> | ||
72 | #include <asm/uaccess.h> | ||
73 | |||
74 | #include <linux/major.h> | ||
75 | #define MAJOR_NR MITSUMI_X_CDROM_MAJOR | ||
76 | #include <linux/blkdev.h> | ||
77 | #include <linux/devfs_fs_kernel.h> | ||
78 | |||
79 | #include "mcdx.h" | ||
80 | |||
81 | #ifndef HZ | ||
82 | #error HZ not defined | ||
83 | #endif | ||
84 | |||
85 | #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args) | ||
86 | |||
87 | #if !MCDX_QUIET | ||
88 | #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args) | ||
89 | #else | ||
90 | #define xinfo(fmt, args...) { ; } | ||
91 | #endif | ||
92 | |||
93 | #if MCDX_DEBUG | ||
94 | #define xtrace(lvl, fmt, args...) \ | ||
95 | { if (lvl > 0) \ | ||
96 | { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } } | ||
97 | #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args) | ||
98 | #else | ||
99 | #define xtrace(lvl, fmt, args...) { ; } | ||
100 | #define xdebug(fmt, args...) { ; } | ||
101 | #endif | ||
102 | |||
103 | /* CONSTANTS *******************************************************/ | ||
104 | |||
105 | /* Following are the number of sectors we _request_ from the drive | ||
106 | every time an access outside the already requested range is done. | ||
107 | The _direct_ size is the number of sectors we're allowed to skip | ||
108 | directly (performing a read instead of requesting the new sector | ||
109 | needed */ | ||
110 | const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */ | ||
111 | const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */ | ||
112 | |||
113 | enum drivemodes { TOC, DATA, RAW, COOKED }; | ||
114 | enum datamodes { MODE0, MODE1, MODE2 }; | ||
115 | enum resetmodes { SOFT, HARD }; | ||
116 | |||
117 | const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */ | ||
118 | const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */ | ||
119 | const int DOOR = 0x04; /* door locking capability */ | ||
120 | const int MULTI = 0x08; /* multi session capability */ | ||
121 | |||
122 | const unsigned char READ1X = 0xc0; | ||
123 | const unsigned char READ2X = 0xc1; | ||
124 | |||
125 | |||
126 | /* DECLARATIONS ****************************************************/ | ||
127 | struct s_subqcode { | ||
128 | unsigned char control; | ||
129 | unsigned char tno; | ||
130 | unsigned char index; | ||
131 | struct cdrom_msf0 tt; | ||
132 | struct cdrom_msf0 dt; | ||
133 | }; | ||
134 | |||
135 | struct s_diskinfo { | ||
136 | unsigned int n_first; | ||
137 | unsigned int n_last; | ||
138 | struct cdrom_msf0 msf_leadout; | ||
139 | struct cdrom_msf0 msf_first; | ||
140 | }; | ||
141 | |||
142 | struct s_multi { | ||
143 | unsigned char multi; | ||
144 | struct cdrom_msf0 msf_last; | ||
145 | }; | ||
146 | |||
147 | struct s_version { | ||
148 | unsigned char code; | ||
149 | unsigned char ver; | ||
150 | }; | ||
151 | |||
152 | /* Per drive/controller stuff **************************************/ | ||
153 | |||
154 | struct s_drive_stuff { | ||
155 | /* waitqueues */ | ||
156 | wait_queue_head_t busyq; | ||
157 | wait_queue_head_t lockq; | ||
158 | wait_queue_head_t sleepq; | ||
159 | |||
160 | /* flags */ | ||
161 | volatile int introk; /* status of last irq operation */ | ||
162 | volatile int busy; /* drive performs an operation */ | ||
163 | volatile int lock; /* exclusive usage */ | ||
164 | |||
165 | /* cd infos */ | ||
166 | struct s_diskinfo di; | ||
167 | struct s_multi multi; | ||
168 | struct s_subqcode *toc; /* first entry of the toc array */ | ||
169 | struct s_subqcode start; | ||
170 | struct s_subqcode stop; | ||
171 | int xa; /* 1 if xa disk */ | ||
172 | int audio; /* 1 if audio disk */ | ||
173 | int audiostatus; | ||
174 | |||
175 | /* `buffer' control */ | ||
176 | volatile int valid; /* pending, ..., values are valid */ | ||
177 | volatile int pending; /* next sector to be read */ | ||
178 | volatile int low_border; /* first sector not to be skipped direct */ | ||
179 | volatile int high_border; /* first sector `out of area' */ | ||
180 | #ifdef AK2 | ||
181 | volatile int int_err; | ||
182 | #endif /* AK2 */ | ||
183 | |||
184 | /* adds and odds */ | ||
185 | unsigned wreg_data; /* w data */ | ||
186 | unsigned wreg_reset; /* w hardware reset */ | ||
187 | unsigned wreg_hcon; /* w hardware conf */ | ||
188 | unsigned wreg_chn; /* w channel */ | ||
189 | unsigned rreg_data; /* r data */ | ||
190 | unsigned rreg_status; /* r status */ | ||
191 | |||
192 | int irq; /* irq used by this drive */ | ||
193 | int present; /* drive present and its capabilities */ | ||
194 | unsigned char readcmd; /* read cmd depends on single/double speed */ | ||
195 | unsigned char playcmd; /* play should always be single speed */ | ||
196 | unsigned int xxx; /* set if changed, reset while open */ | ||
197 | unsigned int yyy; /* set if changed, reset by media_changed */ | ||
198 | int users; /* keeps track of open/close */ | ||
199 | int lastsector; /* last block accessible */ | ||
200 | int status; /* last operation's error / status */ | ||
201 | int readerrs; /* # of blocks read w/o error */ | ||
202 | struct cdrom_device_info info; | ||
203 | struct gendisk *disk; | ||
204 | }; | ||
205 | |||
206 | |||
207 | /* Prototypes ******************************************************/ | ||
208 | |||
209 | /* The following prototypes are already declared elsewhere. They are | ||
210 | repeated here to show what's going on. And to sense, if they're | ||
211 | changed elsewhere. */ | ||
212 | |||
213 | /* declared in blk.h */ | ||
214 | int mcdx_init(void); | ||
215 | void do_mcdx_request(request_queue_t * q); | ||
216 | |||
217 | static int mcdx_block_open(struct inode *inode, struct file *file) | ||
218 | { | ||
219 | struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; | ||
220 | return cdrom_open(&p->info, inode, file); | ||
221 | } | ||
222 | |||
223 | static int mcdx_block_release(struct inode *inode, struct file *file) | ||
224 | { | ||
225 | struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; | ||
226 | return cdrom_release(&p->info, file); | ||
227 | } | ||
228 | |||
229 | static int mcdx_block_ioctl(struct inode *inode, struct file *file, | ||
230 | unsigned cmd, unsigned long arg) | ||
231 | { | ||
232 | struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; | ||
233 | return cdrom_ioctl(file, &p->info, inode, cmd, arg); | ||
234 | } | ||
235 | |||
236 | static int mcdx_block_media_changed(struct gendisk *disk) | ||
237 | { | ||
238 | struct s_drive_stuff *p = disk->private_data; | ||
239 | return cdrom_media_changed(&p->info); | ||
240 | } | ||
241 | |||
242 | static struct block_device_operations mcdx_bdops = | ||
243 | { | ||
244 | .owner = THIS_MODULE, | ||
245 | .open = mcdx_block_open, | ||
246 | .release = mcdx_block_release, | ||
247 | .ioctl = mcdx_block_ioctl, | ||
248 | .media_changed = mcdx_block_media_changed, | ||
249 | }; | ||
250 | |||
251 | |||
252 | /* Indirect exported functions. These functions are exported by their | ||
253 | addresses, such as mcdx_open and mcdx_close in the | ||
254 | structure mcdx_dops. */ | ||
255 | |||
256 | /* exported by file_ops */ | ||
257 | static int mcdx_open(struct cdrom_device_info *cdi, int purpose); | ||
258 | static void mcdx_close(struct cdrom_device_info *cdi); | ||
259 | static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr); | ||
260 | static int mcdx_tray_move(struct cdrom_device_info *cdi, int position); | ||
261 | static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock); | ||
262 | static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, | ||
263 | unsigned int cmd, void *arg); | ||
264 | |||
265 | /* misc internal support functions */ | ||
266 | static void log2msf(unsigned int, struct cdrom_msf0 *); | ||
267 | static unsigned int msf2log(const struct cdrom_msf0 *); | ||
268 | static unsigned int uint2bcd(unsigned int); | ||
269 | static unsigned int bcd2uint(unsigned char); | ||
270 | static unsigned port(int *); | ||
271 | static int irq(int *); | ||
272 | static void mcdx_delay(struct s_drive_stuff *, long jifs); | ||
273 | static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector, | ||
274 | int nr_sectors); | ||
275 | static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector, | ||
276 | int nr_sectors); | ||
277 | |||
278 | static int mcdx_config(struct s_drive_stuff *, int); | ||
279 | static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *, | ||
280 | int); | ||
281 | static int mcdx_stop(struct s_drive_stuff *, int); | ||
282 | static int mcdx_hold(struct s_drive_stuff *, int); | ||
283 | static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int); | ||
284 | static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int); | ||
285 | static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int); | ||
286 | static int mcdx_requestsubqcode(struct s_drive_stuff *, | ||
287 | struct s_subqcode *, int); | ||
288 | static int mcdx_requestmultidiskinfo(struct s_drive_stuff *, | ||
289 | struct s_multi *, int); | ||
290 | static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *, | ||
291 | int); | ||
292 | static int mcdx_getstatus(struct s_drive_stuff *, int); | ||
293 | static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *); | ||
294 | static int mcdx_talk(struct s_drive_stuff *, | ||
295 | const unsigned char *cmd, size_t, | ||
296 | void *buffer, size_t size, unsigned int timeout, int); | ||
297 | static int mcdx_readtoc(struct s_drive_stuff *); | ||
298 | static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *); | ||
299 | static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *); | ||
300 | static int mcdx_setattentuator(struct s_drive_stuff *, | ||
301 | struct cdrom_volctrl *, int); | ||
302 | |||
303 | /* static variables ************************************************/ | ||
304 | |||
305 | static int mcdx_drive_map[][2] = MCDX_DRIVEMAP; | ||
306 | static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES]; | ||
307 | static DEFINE_SPINLOCK(mcdx_lock); | ||
308 | static struct request_queue *mcdx_queue; | ||
309 | |||
310 | /* You can only set the first two pairs, from old MODULE_PARM code. */ | ||
311 | static int mcdx_set(const char *val, struct kernel_param *kp) | ||
312 | { | ||
313 | get_options((char *)val, 4, (int *)mcdx_drive_map); | ||
314 | return 0; | ||
315 | } | ||
316 | module_param_call(mcdx, mcdx_set, NULL, NULL, 0); | ||
317 | |||
318 | static struct cdrom_device_ops mcdx_dops = { | ||
319 | .open = mcdx_open, | ||
320 | .release = mcdx_close, | ||
321 | .media_changed = mcdx_media_changed, | ||
322 | .tray_move = mcdx_tray_move, | ||
323 | .lock_door = mcdx_lockdoor, | ||
324 | .audio_ioctl = mcdx_audio_ioctl, | ||
325 | .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | | ||
326 | CDC_PLAY_AUDIO | CDC_DRIVE_STATUS, | ||
327 | }; | ||
328 | |||
329 | /* KERNEL INTERFACE FUNCTIONS **************************************/ | ||
330 | |||
331 | |||
332 | static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, | ||
333 | unsigned int cmd, void *arg) | ||
334 | { | ||
335 | struct s_drive_stuff *stuffp = cdi->handle; | ||
336 | |||
337 | if (!stuffp->present) | ||
338 | return -ENXIO; | ||
339 | |||
340 | if (stuffp->xxx) { | ||
341 | if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { | ||
342 | stuffp->lastsector = -1; | ||
343 | } else { | ||
344 | stuffp->lastsector = (CD_FRAMESIZE / 512) | ||
345 | * msf2log(&stuffp->di.msf_leadout) - 1; | ||
346 | } | ||
347 | |||
348 | if (stuffp->toc) { | ||
349 | kfree(stuffp->toc); | ||
350 | stuffp->toc = NULL; | ||
351 | if (-1 == mcdx_readtoc(stuffp)) | ||
352 | return -1; | ||
353 | } | ||
354 | |||
355 | stuffp->xxx = 0; | ||
356 | } | ||
357 | |||
358 | switch (cmd) { | ||
359 | case CDROMSTART:{ | ||
360 | xtrace(IOCTL, "ioctl() START\n"); | ||
361 | /* Spin up the drive. Don't think we can do this. | ||
362 | * For now, ignore it. | ||
363 | */ | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | case CDROMSTOP:{ | ||
368 | xtrace(IOCTL, "ioctl() STOP\n"); | ||
369 | stuffp->audiostatus = CDROM_AUDIO_INVALID; | ||
370 | if (-1 == mcdx_stop(stuffp, 1)) | ||
371 | return -EIO; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | case CDROMPLAYTRKIND:{ | ||
376 | struct cdrom_ti *ti = (struct cdrom_ti *) arg; | ||
377 | |||
378 | xtrace(IOCTL, "ioctl() PLAYTRKIND\n"); | ||
379 | if ((ti->cdti_trk0 < stuffp->di.n_first) | ||
380 | || (ti->cdti_trk0 > stuffp->di.n_last) | ||
381 | || (ti->cdti_trk1 < stuffp->di.n_first)) | ||
382 | return -EINVAL; | ||
383 | if (ti->cdti_trk1 > stuffp->di.n_last) | ||
384 | ti->cdti_trk1 = stuffp->di.n_last; | ||
385 | xtrace(PLAYTRK, "ioctl() track %d to %d\n", | ||
386 | ti->cdti_trk0, ti->cdti_trk1); | ||
387 | return mcdx_playtrk(stuffp, ti); | ||
388 | } | ||
389 | |||
390 | case CDROMPLAYMSF:{ | ||
391 | struct cdrom_msf *msf = (struct cdrom_msf *) arg; | ||
392 | |||
393 | xtrace(IOCTL, "ioctl() PLAYMSF\n"); | ||
394 | |||
395 | if ((stuffp->audiostatus == CDROM_AUDIO_PLAY) | ||
396 | && (-1 == mcdx_hold(stuffp, 1))) | ||
397 | return -EIO; | ||
398 | |||
399 | msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0); | ||
400 | msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0); | ||
401 | msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0); | ||
402 | |||
403 | msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1); | ||
404 | msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1); | ||
405 | msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1); | ||
406 | |||
407 | stuffp->stop.dt.minute = msf->cdmsf_min1; | ||
408 | stuffp->stop.dt.second = msf->cdmsf_sec1; | ||
409 | stuffp->stop.dt.frame = msf->cdmsf_frame1; | ||
410 | |||
411 | return mcdx_playmsf(stuffp, msf); | ||
412 | } | ||
413 | |||
414 | case CDROMRESUME:{ | ||
415 | xtrace(IOCTL, "ioctl() RESUME\n"); | ||
416 | return mcdx_playtrk(stuffp, NULL); | ||
417 | } | ||
418 | |||
419 | case CDROMREADTOCENTRY:{ | ||
420 | struct cdrom_tocentry *entry = | ||
421 | (struct cdrom_tocentry *) arg; | ||
422 | struct s_subqcode *tp = NULL; | ||
423 | xtrace(IOCTL, "ioctl() READTOCENTRY\n"); | ||
424 | |||
425 | if (-1 == mcdx_readtoc(stuffp)) | ||
426 | return -1; | ||
427 | if (entry->cdte_track == CDROM_LEADOUT) | ||
428 | tp = &stuffp->toc[stuffp->di.n_last - | ||
429 | stuffp->di.n_first + 1]; | ||
430 | else if (entry->cdte_track > stuffp->di.n_last | ||
431 | || entry->cdte_track < stuffp->di.n_first) | ||
432 | return -EINVAL; | ||
433 | else | ||
434 | tp = &stuffp->toc[entry->cdte_track - | ||
435 | stuffp->di.n_first]; | ||
436 | |||
437 | if (NULL == tp) | ||
438 | return -EIO; | ||
439 | entry->cdte_adr = tp->control; | ||
440 | entry->cdte_ctrl = tp->control >> 4; | ||
441 | /* Always return stuff in MSF, and let the Uniform cdrom driver | ||
442 | worry about what the user actually wants */ | ||
443 | entry->cdte_addr.msf.minute = | ||
444 | bcd2uint(tp->dt.minute); | ||
445 | entry->cdte_addr.msf.second = | ||
446 | bcd2uint(tp->dt.second); | ||
447 | entry->cdte_addr.msf.frame = | ||
448 | bcd2uint(tp->dt.frame); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | case CDROMSUBCHNL:{ | ||
453 | struct cdrom_subchnl *sub = | ||
454 | (struct cdrom_subchnl *) arg; | ||
455 | struct s_subqcode q; | ||
456 | |||
457 | xtrace(IOCTL, "ioctl() SUBCHNL\n"); | ||
458 | |||
459 | if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) | ||
460 | return -EIO; | ||
461 | |||
462 | xtrace(SUBCHNL, "audiostatus: %x\n", | ||
463 | stuffp->audiostatus); | ||
464 | sub->cdsc_audiostatus = stuffp->audiostatus; | ||
465 | sub->cdsc_adr = q.control; | ||
466 | sub->cdsc_ctrl = q.control >> 4; | ||
467 | sub->cdsc_trk = bcd2uint(q.tno); | ||
468 | sub->cdsc_ind = bcd2uint(q.index); | ||
469 | |||
470 | xtrace(SUBCHNL, "trk %d, ind %d\n", | ||
471 | sub->cdsc_trk, sub->cdsc_ind); | ||
472 | /* Always return stuff in MSF, and let the Uniform cdrom driver | ||
473 | worry about what the user actually wants */ | ||
474 | sub->cdsc_absaddr.msf.minute = | ||
475 | bcd2uint(q.dt.minute); | ||
476 | sub->cdsc_absaddr.msf.second = | ||
477 | bcd2uint(q.dt.second); | ||
478 | sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); | ||
479 | sub->cdsc_reladdr.msf.minute = | ||
480 | bcd2uint(q.tt.minute); | ||
481 | sub->cdsc_reladdr.msf.second = | ||
482 | bcd2uint(q.tt.second); | ||
483 | sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); | ||
484 | xtrace(SUBCHNL, | ||
485 | "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n", | ||
486 | sub->cdsc_absaddr.msf.minute, | ||
487 | sub->cdsc_absaddr.msf.second, | ||
488 | sub->cdsc_absaddr.msf.frame, | ||
489 | sub->cdsc_reladdr.msf.minute, | ||
490 | sub->cdsc_reladdr.msf.second, | ||
491 | sub->cdsc_reladdr.msf.frame); | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | case CDROMREADTOCHDR:{ | ||
497 | struct cdrom_tochdr *toc = | ||
498 | (struct cdrom_tochdr *) arg; | ||
499 | |||
500 | xtrace(IOCTL, "ioctl() READTOCHDR\n"); | ||
501 | toc->cdth_trk0 = stuffp->di.n_first; | ||
502 | toc->cdth_trk1 = stuffp->di.n_last; | ||
503 | xtrace(TOCHDR, | ||
504 | "ioctl() track0 = %d, track1 = %d\n", | ||
505 | stuffp->di.n_first, stuffp->di.n_last); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | case CDROMPAUSE:{ | ||
510 | xtrace(IOCTL, "ioctl() PAUSE\n"); | ||
511 | if (stuffp->audiostatus != CDROM_AUDIO_PLAY) | ||
512 | return -EINVAL; | ||
513 | if (-1 == mcdx_stop(stuffp, 1)) | ||
514 | return -EIO; | ||
515 | stuffp->audiostatus = CDROM_AUDIO_PAUSED; | ||
516 | if (-1 == | ||
517 | mcdx_requestsubqcode(stuffp, &stuffp->start, | ||
518 | 1)) | ||
519 | return -EIO; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | case CDROMMULTISESSION:{ | ||
524 | struct cdrom_multisession *ms = | ||
525 | (struct cdrom_multisession *) arg; | ||
526 | xtrace(IOCTL, "ioctl() MULTISESSION\n"); | ||
527 | /* Always return stuff in LBA, and let the Uniform cdrom driver | ||
528 | worry about what the user actually wants */ | ||
529 | ms->addr.lba = msf2log(&stuffp->multi.msf_last); | ||
530 | ms->xa_flag = !!stuffp->multi.multi; | ||
531 | xtrace(MS, | ||
532 | "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", | ||
533 | ms->xa_flag, ms->addr.lba, | ||
534 | stuffp->multi.msf_last.minute, | ||
535 | stuffp->multi.msf_last.second, | ||
536 | stuffp->multi.msf_last.frame); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | case CDROMEJECT:{ | ||
542 | xtrace(IOCTL, "ioctl() EJECT\n"); | ||
543 | if (stuffp->users > 1) | ||
544 | return -EBUSY; | ||
545 | return (mcdx_tray_move(cdi, 1)); | ||
546 | } | ||
547 | |||
548 | case CDROMCLOSETRAY:{ | ||
549 | xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n"); | ||
550 | return (mcdx_tray_move(cdi, 0)); | ||
551 | } | ||
552 | |||
553 | case CDROMVOLCTRL:{ | ||
554 | struct cdrom_volctrl *volctrl = | ||
555 | (struct cdrom_volctrl *) arg; | ||
556 | xtrace(IOCTL, "ioctl() VOLCTRL\n"); | ||
557 | |||
558 | #if 0 /* not tested! */ | ||
559 | /* adjust for the weirdness of workman (md) */ | ||
560 | /* can't test it (hs) */ | ||
561 | volctrl.channel2 = volctrl.channel1; | ||
562 | volctrl.channel1 = volctrl.channel3 = 0x00; | ||
563 | #endif | ||
564 | return mcdx_setattentuator(stuffp, volctrl, 2); | ||
565 | } | ||
566 | |||
567 | default: | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | void do_mcdx_request(request_queue_t * q) | ||
573 | { | ||
574 | struct s_drive_stuff *stuffp; | ||
575 | struct request *req; | ||
576 | |||
577 | again: | ||
578 | |||
579 | req = elv_next_request(q); | ||
580 | if (!req) | ||
581 | return; | ||
582 | |||
583 | stuffp = req->rq_disk->private_data; | ||
584 | |||
585 | if (!stuffp->present) { | ||
586 | xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name); | ||
587 | xtrace(REQUEST, "end_request(0): bad device\n"); | ||
588 | end_request(req, 0); | ||
589 | return; | ||
590 | } | ||
591 | |||
592 | if (stuffp->audio) { | ||
593 | xwarn("do_request() attempt to read from audio cd\n"); | ||
594 | xtrace(REQUEST, "end_request(0): read from audio\n"); | ||
595 | end_request(req, 0); | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | xtrace(REQUEST, "do_request() (%lu + %lu)\n", | ||
600 | req->sector, req->nr_sectors); | ||
601 | |||
602 | if (req->cmd != READ) { | ||
603 | xwarn("do_request(): non-read command to cd!!\n"); | ||
604 | xtrace(REQUEST, "end_request(0): write\n"); | ||
605 | end_request(req, 0); | ||
606 | return; | ||
607 | } | ||
608 | else { | ||
609 | stuffp->status = 0; | ||
610 | while (req->nr_sectors) { | ||
611 | int i; | ||
612 | |||
613 | i = mcdx_transfer(stuffp, | ||
614 | req->buffer, | ||
615 | req->sector, | ||
616 | req->nr_sectors); | ||
617 | |||
618 | if (i == -1) { | ||
619 | end_request(req, 0); | ||
620 | goto again; | ||
621 | } | ||
622 | req->sector += i; | ||
623 | req->nr_sectors -= i; | ||
624 | req->buffer += (i * 512); | ||
625 | } | ||
626 | end_request(req, 1); | ||
627 | goto again; | ||
628 | |||
629 | xtrace(REQUEST, "end_request(1)\n"); | ||
630 | end_request(req, 1); | ||
631 | } | ||
632 | |||
633 | goto again; | ||
634 | } | ||
635 | |||
636 | static int mcdx_open(struct cdrom_device_info *cdi, int purpose) | ||
637 | { | ||
638 | struct s_drive_stuff *stuffp; | ||
639 | xtrace(OPENCLOSE, "open()\n"); | ||
640 | stuffp = cdi->handle; | ||
641 | if (!stuffp->present) | ||
642 | return -ENXIO; | ||
643 | |||
644 | /* Make the modules looking used ... (thanx bjorn). | ||
645 | * But we shouldn't forget to decrement the module counter | ||
646 | * on error return */ | ||
647 | |||
648 | /* this is only done to test if the drive talks with us */ | ||
649 | if (-1 == mcdx_getstatus(stuffp, 1)) | ||
650 | return -EIO; | ||
651 | |||
652 | if (stuffp->xxx) { | ||
653 | |||
654 | xtrace(OPENCLOSE, "open() media changed\n"); | ||
655 | stuffp->audiostatus = CDROM_AUDIO_INVALID; | ||
656 | stuffp->readcmd = 0; | ||
657 | xtrace(OPENCLOSE, "open() Request multisession info\n"); | ||
658 | if (-1 == | ||
659 | mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6)) | ||
660 | xinfo("No multidiskinfo\n"); | ||
661 | } else { | ||
662 | /* multisession ? */ | ||
663 | if (!stuffp->multi.multi) | ||
664 | stuffp->multi.msf_last.second = 2; | ||
665 | |||
666 | xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n", | ||
667 | stuffp->multi.multi, | ||
668 | stuffp->multi.msf_last.minute, | ||
669 | stuffp->multi.msf_last.second, | ||
670 | stuffp->multi.msf_last.frame); | ||
671 | |||
672 | {; | ||
673 | } /* got multisession information */ | ||
674 | /* request the disks table of contents (aka diskinfo) */ | ||
675 | if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { | ||
676 | |||
677 | stuffp->lastsector = -1; | ||
678 | |||
679 | } else { | ||
680 | |||
681 | stuffp->lastsector = (CD_FRAMESIZE / 512) | ||
682 | * msf2log(&stuffp->di.msf_leadout) - 1; | ||
683 | |||
684 | xtrace(OPENCLOSE, | ||
685 | "open() start %d (%02x:%02x.%02x) %d\n", | ||
686 | stuffp->di.n_first, | ||
687 | stuffp->di.msf_first.minute, | ||
688 | stuffp->di.msf_first.second, | ||
689 | stuffp->di.msf_first.frame, | ||
690 | msf2log(&stuffp->di.msf_first)); | ||
691 | xtrace(OPENCLOSE, | ||
692 | "open() last %d (%02x:%02x.%02x) %d\n", | ||
693 | stuffp->di.n_last, | ||
694 | stuffp->di.msf_leadout.minute, | ||
695 | stuffp->di.msf_leadout.second, | ||
696 | stuffp->di.msf_leadout.frame, | ||
697 | msf2log(&stuffp->di.msf_leadout)); | ||
698 | } | ||
699 | |||
700 | if (stuffp->toc) { | ||
701 | xtrace(MALLOC, "open() free old toc @ %p\n", | ||
702 | stuffp->toc); | ||
703 | kfree(stuffp->toc); | ||
704 | |||
705 | stuffp->toc = NULL; | ||
706 | } | ||
707 | |||
708 | xtrace(OPENCLOSE, "open() init irq generation\n"); | ||
709 | if (-1 == mcdx_config(stuffp, 1)) | ||
710 | return -EIO; | ||
711 | #if FALLBACK | ||
712 | /* Set the read speed */ | ||
713 | xwarn("AAA %x AAA\n", stuffp->readcmd); | ||
714 | if (stuffp->readerrs) | ||
715 | stuffp->readcmd = READ1X; | ||
716 | else | ||
717 | stuffp->readcmd = | ||
718 | stuffp->present | SINGLE ? READ1X : READ2X; | ||
719 | xwarn("XXX %x XXX\n", stuffp->readcmd); | ||
720 | #else | ||
721 | stuffp->readcmd = | ||
722 | stuffp->present | SINGLE ? READ1X : READ2X; | ||
723 | #endif | ||
724 | |||
725 | /* try to get the first sector, iff any ... */ | ||
726 | if (stuffp->lastsector >= 0) { | ||
727 | char buf[512]; | ||
728 | int ans; | ||
729 | int tries; | ||
730 | |||
731 | stuffp->xa = 0; | ||
732 | stuffp->audio = 0; | ||
733 | |||
734 | for (tries = 6; tries; tries--) { | ||
735 | |||
736 | stuffp->introk = 1; | ||
737 | |||
738 | xtrace(OPENCLOSE, "open() try as %s\n", | ||
739 | stuffp->xa ? "XA" : "normal"); | ||
740 | /* set data mode */ | ||
741 | if (-1 == (ans = mcdx_setdatamode(stuffp, | ||
742 | stuffp-> | ||
743 | xa ? | ||
744 | MODE2 : | ||
745 | MODE1, | ||
746 | 1))) { | ||
747 | /* return -EIO; */ | ||
748 | stuffp->xa = 0; | ||
749 | break; | ||
750 | } | ||
751 | |||
752 | if ((stuffp->audio = e_audio(ans))) | ||
753 | break; | ||
754 | |||
755 | while (0 == | ||
756 | (ans = | ||
757 | mcdx_transfer(stuffp, buf, 0, 1))); | ||
758 | |||
759 | if (ans == 1) | ||
760 | break; | ||
761 | stuffp->xa = !stuffp->xa; | ||
762 | } | ||
763 | } | ||
764 | /* xa disks will be read in raw mode, others not */ | ||
765 | if (-1 == mcdx_setdrivemode(stuffp, | ||
766 | stuffp->xa ? RAW : COOKED, | ||
767 | 1)) | ||
768 | return -EIO; | ||
769 | if (stuffp->audio) { | ||
770 | xinfo("open() audio disk found\n"); | ||
771 | } else if (stuffp->lastsector >= 0) { | ||
772 | xinfo("open() %s%s disk found\n", | ||
773 | stuffp->xa ? "XA / " : "", | ||
774 | stuffp->multi. | ||
775 | multi ? "Multi Session" : "Single Session"); | ||
776 | } | ||
777 | } | ||
778 | stuffp->xxx = 0; | ||
779 | stuffp->users++; | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static void mcdx_close(struct cdrom_device_info *cdi) | ||
784 | { | ||
785 | struct s_drive_stuff *stuffp; | ||
786 | |||
787 | xtrace(OPENCLOSE, "close()\n"); | ||
788 | |||
789 | stuffp = cdi->handle; | ||
790 | |||
791 | --stuffp->users; | ||
792 | } | ||
793 | |||
794 | static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
795 | /* Return: 1 if media changed since last call to this function | ||
796 | 0 otherwise */ | ||
797 | { | ||
798 | struct s_drive_stuff *stuffp; | ||
799 | |||
800 | xinfo("mcdx_media_changed called for device %s\n", cdi->name); | ||
801 | |||
802 | stuffp = cdi->handle; | ||
803 | mcdx_getstatus(stuffp, 1); | ||
804 | |||
805 | if (stuffp->yyy == 0) | ||
806 | return 0; | ||
807 | |||
808 | stuffp->yyy = 0; | ||
809 | return 1; | ||
810 | } | ||
811 | |||
812 | #ifndef MODULE | ||
813 | static int __init mcdx_setup(char *str) | ||
814 | { | ||
815 | int pi[4]; | ||
816 | (void) get_options(str, ARRAY_SIZE(pi), pi); | ||
817 | |||
818 | if (pi[0] > 0) | ||
819 | mcdx_drive_map[0][0] = pi[1]; | ||
820 | if (pi[0] > 1) | ||
821 | mcdx_drive_map[0][1] = pi[2]; | ||
822 | return 1; | ||
823 | } | ||
824 | |||
825 | __setup("mcdx=", mcdx_setup); | ||
826 | |||
827 | #endif | ||
828 | |||
829 | /* DIRTY PART ******************************************************/ | ||
830 | |||
831 | static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) | ||
832 | /* This routine is used for sleeping. | ||
833 | * A jifs value <0 means NO sleeping, | ||
834 | * =0 means minimal sleeping (let the kernel | ||
835 | * run for other processes) | ||
836 | * >0 means at least sleep for that amount. | ||
837 | * May be we could use a simple count loop w/ jumps to itself, but | ||
838 | * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */ | ||
839 | { | ||
840 | if (jifs < 0) | ||
841 | return; | ||
842 | |||
843 | xtrace(SLEEP, "*** delay: sleepq\n"); | ||
844 | interruptible_sleep_on_timeout(&stuff->sleepq, jifs); | ||
845 | xtrace(SLEEP, "delay awoken\n"); | ||
846 | if (signal_pending(current)) { | ||
847 | xtrace(SLEEP, "got signal\n"); | ||
848 | } | ||
849 | } | ||
850 | |||
851 | static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs) | ||
852 | { | ||
853 | struct s_drive_stuff *stuffp = dev_id; | ||
854 | unsigned char b; | ||
855 | |||
856 | if (stuffp == NULL) { | ||
857 | xwarn("mcdx: no device for intr %d\n", irq); | ||
858 | return IRQ_NONE; | ||
859 | } | ||
860 | #ifdef AK2 | ||
861 | if (!stuffp->busy && stuffp->pending) | ||
862 | stuffp->int_err = 1; | ||
863 | |||
864 | #endif /* AK2 */ | ||
865 | /* get the interrupt status */ | ||
866 | b = inb(stuffp->rreg_status); | ||
867 | stuffp->introk = ~b & MCDX_RBIT_DTEN; | ||
868 | |||
869 | /* NOTE: We only should get interrupts if the data we | ||
870 | * requested are ready to transfer. | ||
871 | * But the drive seems to generate ``asynchronous'' interrupts | ||
872 | * on several error conditions too. (Despite the err int enable | ||
873 | * setting during initialisation) */ | ||
874 | |||
875 | /* if not ok, read the next byte as the drives status */ | ||
876 | if (!stuffp->introk) { | ||
877 | xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b); | ||
878 | if (~b & MCDX_RBIT_STEN) { | ||
879 | xinfo("intr() irq %d status 0x%02x\n", | ||
880 | irq, inb(stuffp->rreg_data)); | ||
881 | } else { | ||
882 | xinfo("intr() irq %d ambiguous hw status\n", irq); | ||
883 | } | ||
884 | } else { | ||
885 | xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b); | ||
886 | } | ||
887 | |||
888 | stuffp->busy = 0; | ||
889 | wake_up_interruptible(&stuffp->busyq); | ||
890 | return IRQ_HANDLED; | ||
891 | } | ||
892 | |||
893 | |||
894 | static int mcdx_talk(struct s_drive_stuff *stuffp, | ||
895 | const unsigned char *cmd, size_t cmdlen, | ||
896 | void *buffer, size_t size, unsigned int timeout, int tries) | ||
897 | /* Send a command to the drive, wait for the result. | ||
898 | * returns -1 on timeout, drive status otherwise | ||
899 | * If buffer is not zero, the result (length size) is stored there. | ||
900 | * If buffer is zero the size should be the number of bytes to read | ||
901 | * from the drive. These bytes are discarded. | ||
902 | */ | ||
903 | { | ||
904 | int st; | ||
905 | char c; | ||
906 | int discard; | ||
907 | |||
908 | /* Somebody wants the data read? */ | ||
909 | if ((discard = (buffer == NULL))) | ||
910 | buffer = &c; | ||
911 | |||
912 | while (stuffp->lock) { | ||
913 | xtrace(SLEEP, "*** talk: lockq\n"); | ||
914 | interruptible_sleep_on(&stuffp->lockq); | ||
915 | xtrace(SLEEP, "talk: awoken\n"); | ||
916 | } | ||
917 | |||
918 | stuffp->lock = 1; | ||
919 | |||
920 | /* An operation other then reading data destroys the | ||
921 | * data already requested and remembered in stuffp->request, ... */ | ||
922 | stuffp->valid = 0; | ||
923 | |||
924 | #if MCDX_DEBUG & TALK | ||
925 | { | ||
926 | unsigned char i; | ||
927 | xtrace(TALK, | ||
928 | "talk() %d / %d tries, res.size %d, command 0x%02x", | ||
929 | tries, timeout, size, (unsigned char) cmd[0]); | ||
930 | for (i = 1; i < cmdlen; i++) | ||
931 | xtrace(TALK, " 0x%02x", cmd[i]); | ||
932 | xtrace(TALK, "\n"); | ||
933 | } | ||
934 | #endif | ||
935 | |||
936 | /* give up if all tries are done (bad) or if the status | ||
937 | * st != -1 (good) */ | ||
938 | for (st = -1; st == -1 && tries; tries--) { | ||
939 | |||
940 | char *bp = (char *) buffer; | ||
941 | size_t sz = size; | ||
942 | |||
943 | outsb(stuffp->wreg_data, cmd, cmdlen); | ||
944 | xtrace(TALK, "talk() command sent\n"); | ||
945 | |||
946 | /* get the status byte */ | ||
947 | if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { | ||
948 | xinfo("talk() %02x timed out (status), %d tr%s left\n", | ||
949 | cmd[0], tries - 1, tries == 2 ? "y" : "ies"); | ||
950 | continue; | ||
951 | } | ||
952 | st = *bp; | ||
953 | sz--; | ||
954 | if (!discard) | ||
955 | bp++; | ||
956 | |||
957 | xtrace(TALK, "talk() got status 0x%02x\n", st); | ||
958 | |||
959 | /* command error? */ | ||
960 | if (e_cmderr(st)) { | ||
961 | xwarn("command error cmd = %02x %s \n", | ||
962 | cmd[0], cmdlen > 1 ? "..." : ""); | ||
963 | st = -1; | ||
964 | continue; | ||
965 | } | ||
966 | |||
967 | /* audio status? */ | ||
968 | if (stuffp->audiostatus == CDROM_AUDIO_INVALID) | ||
969 | stuffp->audiostatus = | ||
970 | e_audiobusy(st) ? CDROM_AUDIO_PLAY : | ||
971 | CDROM_AUDIO_NO_STATUS; | ||
972 | else if (stuffp->audiostatus == CDROM_AUDIO_PLAY | ||
973 | && e_audiobusy(st) == 0) | ||
974 | stuffp->audiostatus = CDROM_AUDIO_COMPLETED; | ||
975 | |||
976 | /* media change? */ | ||
977 | if (e_changed(st)) { | ||
978 | xinfo("talk() media changed\n"); | ||
979 | stuffp->xxx = stuffp->yyy = 1; | ||
980 | } | ||
981 | |||
982 | /* now actually get the data */ | ||
983 | while (sz--) { | ||
984 | if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { | ||
985 | xinfo("talk() %02x timed out (data), %d tr%s left\n", | ||
986 | cmd[0], tries - 1, | ||
987 | tries == 2 ? "y" : "ies"); | ||
988 | st = -1; | ||
989 | break; | ||
990 | } | ||
991 | if (!discard) | ||
992 | bp++; | ||
993 | xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1)); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | #if !MCDX_QUIET | ||
998 | if (!tries && st == -1) | ||
999 | xinfo("talk() giving up\n"); | ||
1000 | #endif | ||
1001 | |||
1002 | stuffp->lock = 0; | ||
1003 | wake_up_interruptible(&stuffp->lockq); | ||
1004 | |||
1005 | xtrace(TALK, "talk() done with 0x%02x\n", st); | ||
1006 | return st; | ||
1007 | } | ||
1008 | |||
1009 | /* MODULE STUFF ***********************************************************/ | ||
1010 | |||
1011 | int __mcdx_init(void) | ||
1012 | { | ||
1013 | int i; | ||
1014 | int drives = 0; | ||
1015 | |||
1016 | mcdx_init(); | ||
1017 | for (i = 0; i < MCDX_NDRIVES; i++) { | ||
1018 | if (mcdx_stuffp[i]) { | ||
1019 | xtrace(INIT, "init_module() drive %d stuff @ %p\n", | ||
1020 | i, mcdx_stuffp[i]); | ||
1021 | drives++; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | if (!drives) | ||
1026 | return -EIO; | ||
1027 | |||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | void __exit mcdx_exit(void) | ||
1032 | { | ||
1033 | int i; | ||
1034 | |||
1035 | xinfo("cleanup_module called\n"); | ||
1036 | |||
1037 | for (i = 0; i < MCDX_NDRIVES; i++) { | ||
1038 | struct s_drive_stuff *stuffp = mcdx_stuffp[i]; | ||
1039 | if (!stuffp) | ||
1040 | continue; | ||
1041 | del_gendisk(stuffp->disk); | ||
1042 | if (unregister_cdrom(&stuffp->info)) { | ||
1043 | printk(KERN_WARNING "Can't unregister cdrom mcdx\n"); | ||
1044 | continue; | ||
1045 | } | ||
1046 | put_disk(stuffp->disk); | ||
1047 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1048 | free_irq(stuffp->irq, NULL); | ||
1049 | if (stuffp->toc) { | ||
1050 | xtrace(MALLOC, "cleanup_module() free toc @ %p\n", | ||
1051 | stuffp->toc); | ||
1052 | kfree(stuffp->toc); | ||
1053 | } | ||
1054 | xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", | ||
1055 | stuffp); | ||
1056 | mcdx_stuffp[i] = NULL; | ||
1057 | kfree(stuffp); | ||
1058 | } | ||
1059 | |||
1060 | if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) { | ||
1061 | xwarn("cleanup() unregister_blkdev() failed\n"); | ||
1062 | } | ||
1063 | blk_cleanup_queue(mcdx_queue); | ||
1064 | #if !MCDX_QUIET | ||
1065 | else | ||
1066 | xinfo("cleanup() succeeded\n"); | ||
1067 | #endif | ||
1068 | } | ||
1069 | |||
1070 | #ifdef MODULE | ||
1071 | module_init(__mcdx_init); | ||
1072 | #endif | ||
1073 | module_exit(mcdx_exit); | ||
1074 | |||
1075 | |||
1076 | /* Support functions ************************************************/ | ||
1077 | |||
1078 | int __init mcdx_init_drive(int drive) | ||
1079 | { | ||
1080 | struct s_version version; | ||
1081 | struct gendisk *disk; | ||
1082 | struct s_drive_stuff *stuffp; | ||
1083 | int size = sizeof(*stuffp); | ||
1084 | char msg[80]; | ||
1085 | |||
1086 | xtrace(INIT, "init() try drive %d\n", drive); | ||
1087 | |||
1088 | xtrace(INIT, "kmalloc space for stuffpt's\n"); | ||
1089 | xtrace(MALLOC, "init() malloc %d bytes\n", size); | ||
1090 | if (!(stuffp = kmalloc(size, GFP_KERNEL))) { | ||
1091 | xwarn("init() malloc failed\n"); | ||
1092 | return 1; | ||
1093 | } | ||
1094 | |||
1095 | disk = alloc_disk(1); | ||
1096 | if (!disk) { | ||
1097 | xwarn("init() malloc failed\n"); | ||
1098 | kfree(stuffp); | ||
1099 | return 1; | ||
1100 | } | ||
1101 | |||
1102 | xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", | ||
1103 | sizeof(*stuffp), stuffp); | ||
1104 | |||
1105 | /* set default values */ | ||
1106 | memset(stuffp, 0, sizeof(*stuffp)); | ||
1107 | |||
1108 | stuffp->present = 0; /* this should be 0 already */ | ||
1109 | stuffp->toc = NULL; /* this should be NULL already */ | ||
1110 | |||
1111 | /* setup our irq and i/o addresses */ | ||
1112 | stuffp->irq = irq(mcdx_drive_map[drive]); | ||
1113 | stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); | ||
1114 | stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; | ||
1115 | stuffp->wreg_hcon = stuffp->wreg_reset + 1; | ||
1116 | stuffp->wreg_chn = stuffp->wreg_hcon + 1; | ||
1117 | |||
1118 | init_waitqueue_head(&stuffp->busyq); | ||
1119 | init_waitqueue_head(&stuffp->lockq); | ||
1120 | init_waitqueue_head(&stuffp->sleepq); | ||
1121 | |||
1122 | /* check if i/o addresses are available */ | ||
1123 | if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) { | ||
1124 | xwarn("0x%03x,%d: Init failed. " | ||
1125 | "I/O ports (0x%03x..0x%03x) already in use.\n", | ||
1126 | stuffp->wreg_data, stuffp->irq, | ||
1127 | stuffp->wreg_data, | ||
1128 | stuffp->wreg_data + MCDX_IO_SIZE - 1); | ||
1129 | xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); | ||
1130 | kfree(stuffp); | ||
1131 | put_disk(disk); | ||
1132 | xtrace(INIT, "init() continue at next drive\n"); | ||
1133 | return 0; /* next drive */ | ||
1134 | } | ||
1135 | |||
1136 | xtrace(INIT, "init() i/o port is available at 0x%03x\n" | ||
1137 | stuffp->wreg_data); | ||
1138 | xtrace(INIT, "init() hardware reset\n"); | ||
1139 | mcdx_reset(stuffp, HARD, 1); | ||
1140 | |||
1141 | xtrace(INIT, "init() get version\n"); | ||
1142 | if (-1 == mcdx_requestversion(stuffp, &version, 4)) { | ||
1143 | /* failed, next drive */ | ||
1144 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1145 | xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n", | ||
1146 | MCDX, stuffp->wreg_data, stuffp->irq); | ||
1147 | xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); | ||
1148 | kfree(stuffp); | ||
1149 | put_disk(disk); | ||
1150 | xtrace(INIT, "init() continue at next drive\n"); | ||
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | switch (version.code) { | ||
1155 | case 'D': | ||
1156 | stuffp->readcmd = READ2X; | ||
1157 | stuffp->present = DOUBLE | DOOR | MULTI; | ||
1158 | break; | ||
1159 | case 'F': | ||
1160 | stuffp->readcmd = READ1X; | ||
1161 | stuffp->present = SINGLE | DOOR | MULTI; | ||
1162 | break; | ||
1163 | case 'M': | ||
1164 | stuffp->readcmd = READ1X; | ||
1165 | stuffp->present = SINGLE; | ||
1166 | break; | ||
1167 | default: | ||
1168 | stuffp->present = 0; | ||
1169 | break; | ||
1170 | } | ||
1171 | |||
1172 | stuffp->playcmd = READ1X; | ||
1173 | |||
1174 | if (!stuffp->present) { | ||
1175 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1176 | xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n", | ||
1177 | MCDX, stuffp->wreg_data, stuffp->irq); | ||
1178 | kfree(stuffp); | ||
1179 | put_disk(disk); | ||
1180 | return 0; /* next drive */ | ||
1181 | } | ||
1182 | |||
1183 | xtrace(INIT, "init() register blkdev\n"); | ||
1184 | if (register_blkdev(MAJOR_NR, "mcdx")) { | ||
1185 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1186 | kfree(stuffp); | ||
1187 | put_disk(disk); | ||
1188 | return 1; | ||
1189 | } | ||
1190 | |||
1191 | mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock); | ||
1192 | if (!mcdx_queue) { | ||
1193 | unregister_blkdev(MAJOR_NR, "mcdx"); | ||
1194 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1195 | kfree(stuffp); | ||
1196 | put_disk(disk); | ||
1197 | return 1; | ||
1198 | } | ||
1199 | |||
1200 | xtrace(INIT, "init() subscribe irq and i/o\n"); | ||
1201 | if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", stuffp)) { | ||
1202 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1203 | xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n", | ||
1204 | MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); | ||
1205 | stuffp->irq = 0; | ||
1206 | blk_cleanup_queue(mcdx_queue); | ||
1207 | kfree(stuffp); | ||
1208 | put_disk(disk); | ||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | xtrace(INIT, "init() get garbage\n"); | ||
1213 | { | ||
1214 | int i; | ||
1215 | mcdx_delay(stuffp, HZ / 2); | ||
1216 | for (i = 100; i; i--) | ||
1217 | (void) inb(stuffp->rreg_status); | ||
1218 | } | ||
1219 | |||
1220 | |||
1221 | #if WE_KNOW_WHY | ||
1222 | /* irq 11 -> channel register */ | ||
1223 | outb(0x50, stuffp->wreg_chn); | ||
1224 | #endif | ||
1225 | |||
1226 | xtrace(INIT, "init() set non dma but irq mode\n"); | ||
1227 | mcdx_config(stuffp, 1); | ||
1228 | |||
1229 | stuffp->info.ops = &mcdx_dops; | ||
1230 | stuffp->info.speed = 2; | ||
1231 | stuffp->info.capacity = 1; | ||
1232 | stuffp->info.handle = stuffp; | ||
1233 | sprintf(stuffp->info.name, "mcdx%d", drive); | ||
1234 | disk->major = MAJOR_NR; | ||
1235 | disk->first_minor = drive; | ||
1236 | strcpy(disk->disk_name, stuffp->info.name); | ||
1237 | disk->fops = &mcdx_bdops; | ||
1238 | disk->flags = GENHD_FL_CD; | ||
1239 | stuffp->disk = disk; | ||
1240 | |||
1241 | sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d." | ||
1242 | " (Firmware version %c %x)\n", | ||
1243 | stuffp->wreg_data, stuffp->irq, version.code, version.ver); | ||
1244 | mcdx_stuffp[drive] = stuffp; | ||
1245 | xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); | ||
1246 | if (register_cdrom(&stuffp->info) != 0) { | ||
1247 | printk("Cannot register Mitsumi CD-ROM!\n"); | ||
1248 | free_irq(stuffp->irq, NULL); | ||
1249 | release_region(stuffp->wreg_data, MCDX_IO_SIZE); | ||
1250 | kfree(stuffp); | ||
1251 | put_disk(disk); | ||
1252 | if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) | ||
1253 | xwarn("cleanup() unregister_blkdev() failed\n"); | ||
1254 | blk_cleanup_queue(mcdx_queue); | ||
1255 | return 2; | ||
1256 | } | ||
1257 | disk->private_data = stuffp; | ||
1258 | disk->queue = mcdx_queue; | ||
1259 | add_disk(disk); | ||
1260 | printk(msg); | ||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | int __init mcdx_init(void) | ||
1265 | { | ||
1266 | int drive; | ||
1267 | xwarn("Version 2.14(hs) \n"); | ||
1268 | |||
1269 | xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); | ||
1270 | |||
1271 | /* zero the pointer array */ | ||
1272 | for (drive = 0; drive < MCDX_NDRIVES; drive++) | ||
1273 | mcdx_stuffp[drive] = NULL; | ||
1274 | |||
1275 | /* do the initialisation */ | ||
1276 | for (drive = 0; drive < MCDX_NDRIVES; drive++) { | ||
1277 | switch (mcdx_init_drive(drive)) { | ||
1278 | case 2: | ||
1279 | return -EIO; | ||
1280 | case 1: | ||
1281 | break; | ||
1282 | } | ||
1283 | } | ||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | static int mcdx_transfer(struct s_drive_stuff *stuffp, | ||
1288 | char *p, int sector, int nr_sectors) | ||
1289 | /* This seems to do the actually transfer. But it does more. It | ||
1290 | keeps track of errors occurred and will (if possible) fall back | ||
1291 | to single speed on error. | ||
1292 | Return: -1 on timeout or other error | ||
1293 | else status byte (as in stuff->st) */ | ||
1294 | { | ||
1295 | int ans; | ||
1296 | |||
1297 | ans = mcdx_xfer(stuffp, p, sector, nr_sectors); | ||
1298 | return ans; | ||
1299 | #if FALLBACK | ||
1300 | if (-1 == ans) | ||
1301 | stuffp->readerrs++; | ||
1302 | else | ||
1303 | return ans; | ||
1304 | |||
1305 | if (stuffp->readerrs && stuffp->readcmd == READ1X) { | ||
1306 | xwarn("XXX Already reading 1x -- no chance\n"); | ||
1307 | return -1; | ||
1308 | } | ||
1309 | |||
1310 | xwarn("XXX Fallback to 1x\n"); | ||
1311 | |||
1312 | stuffp->readcmd = READ1X; | ||
1313 | return mcdx_transfer(stuffp, p, sector, nr_sectors); | ||
1314 | #endif | ||
1315 | |||
1316 | } | ||
1317 | |||
1318 | |||
1319 | static int mcdx_xfer(struct s_drive_stuff *stuffp, | ||
1320 | char *p, int sector, int nr_sectors) | ||
1321 | /* This does actually the transfer from the drive. | ||
1322 | Return: -1 on timeout or other error | ||
1323 | else status byte (as in stuff->st) */ | ||
1324 | { | ||
1325 | int border; | ||
1326 | int done = 0; | ||
1327 | long timeout; | ||
1328 | |||
1329 | if (stuffp->audio) { | ||
1330 | xwarn("Attempt to read from audio CD.\n"); | ||
1331 | return -1; | ||
1332 | } | ||
1333 | |||
1334 | if (!stuffp->readcmd) { | ||
1335 | xinfo("Can't transfer from missing disk.\n"); | ||
1336 | return -1; | ||
1337 | } | ||
1338 | |||
1339 | while (stuffp->lock) { | ||
1340 | interruptible_sleep_on(&stuffp->lockq); | ||
1341 | } | ||
1342 | |||
1343 | if (stuffp->valid && (sector >= stuffp->pending) | ||
1344 | && (sector < stuffp->low_border)) { | ||
1345 | |||
1346 | /* All (or at least a part of the sectors requested) seems | ||
1347 | * to be already requested, so we don't need to bother the | ||
1348 | * drive with new requests ... | ||
1349 | * Wait for the drive become idle, but first | ||
1350 | * check for possible occurred errors --- the drive | ||
1351 | * seems to report them asynchronously */ | ||
1352 | |||
1353 | |||
1354 | border = stuffp->high_border < (border = | ||
1355 | sector + nr_sectors) | ||
1356 | ? stuffp->high_border : border; | ||
1357 | |||
1358 | stuffp->lock = current->pid; | ||
1359 | |||
1360 | do { | ||
1361 | |||
1362 | while (stuffp->busy) { | ||
1363 | |||
1364 | timeout = | ||
1365 | interruptible_sleep_on_timeout | ||
1366 | (&stuffp->busyq, 5 * HZ); | ||
1367 | |||
1368 | if (!stuffp->introk) { | ||
1369 | xtrace(XFER, | ||
1370 | "error via interrupt\n"); | ||
1371 | } else if (!timeout) { | ||
1372 | xtrace(XFER, "timeout\n"); | ||
1373 | } else if (signal_pending(current)) { | ||
1374 | xtrace(XFER, "signal\n"); | ||
1375 | } else | ||
1376 | continue; | ||
1377 | |||
1378 | stuffp->lock = 0; | ||
1379 | stuffp->busy = 0; | ||
1380 | stuffp->valid = 0; | ||
1381 | |||
1382 | wake_up_interruptible(&stuffp->lockq); | ||
1383 | xtrace(XFER, "transfer() done (-1)\n"); | ||
1384 | return -1; | ||
1385 | } | ||
1386 | |||
1387 | /* check if we need to set the busy flag (as we | ||
1388 | * expect an interrupt */ | ||
1389 | stuffp->busy = (3 == (stuffp->pending & 3)); | ||
1390 | |||
1391 | /* Test if it's the first sector of a block, | ||
1392 | * there we have to skip some bytes as we read raw data */ | ||
1393 | if (stuffp->xa && (0 == (stuffp->pending & 3))) { | ||
1394 | const int HEAD = | ||
1395 | CD_FRAMESIZE_RAW - CD_XA_TAIL - | ||
1396 | CD_FRAMESIZE; | ||
1397 | insb(stuffp->rreg_data, p, HEAD); | ||
1398 | } | ||
1399 | |||
1400 | /* now actually read the data */ | ||
1401 | insb(stuffp->rreg_data, p, 512); | ||
1402 | |||
1403 | /* test if it's the last sector of a block, | ||
1404 | * if so, we have to handle XA special */ | ||
1405 | if ((3 == (stuffp->pending & 3)) && stuffp->xa) { | ||
1406 | char dummy[CD_XA_TAIL]; | ||
1407 | insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL); | ||
1408 | } | ||
1409 | |||
1410 | if (stuffp->pending == sector) { | ||
1411 | p += 512; | ||
1412 | done++; | ||
1413 | sector++; | ||
1414 | } | ||
1415 | } while (++(stuffp->pending) < border); | ||
1416 | |||
1417 | stuffp->lock = 0; | ||
1418 | wake_up_interruptible(&stuffp->lockq); | ||
1419 | |||
1420 | } else { | ||
1421 | |||
1422 | /* The requested sector(s) is/are out of the | ||
1423 | * already requested range, so we have to bother the drive | ||
1424 | * with a new request. */ | ||
1425 | |||
1426 | static unsigned char cmd[] = { | ||
1427 | 0, | ||
1428 | 0, 0, 0, | ||
1429 | 0, 0, 0 | ||
1430 | }; | ||
1431 | |||
1432 | cmd[0] = stuffp->readcmd; | ||
1433 | |||
1434 | /* The numbers held in ->pending, ..., should be valid */ | ||
1435 | stuffp->valid = 1; | ||
1436 | stuffp->pending = sector & ~3; | ||
1437 | |||
1438 | /* do some sanity checks */ | ||
1439 | if (stuffp->pending > stuffp->lastsector) { | ||
1440 | xwarn | ||
1441 | ("transfer() sector %d from nirvana requested.\n", | ||
1442 | stuffp->pending); | ||
1443 | stuffp->status = MCDX_ST_EOM; | ||
1444 | stuffp->valid = 0; | ||
1445 | xtrace(XFER, "transfer() done (-1)\n"); | ||
1446 | return -1; | ||
1447 | } | ||
1448 | |||
1449 | if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE) | ||
1450 | > stuffp->lastsector + 1) { | ||
1451 | xtrace(XFER, "cut low_border\n"); | ||
1452 | stuffp->low_border = stuffp->lastsector + 1; | ||
1453 | } | ||
1454 | if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE) | ||
1455 | > stuffp->lastsector + 1) { | ||
1456 | xtrace(XFER, "cut high_border\n"); | ||
1457 | stuffp->high_border = stuffp->lastsector + 1; | ||
1458 | } | ||
1459 | |||
1460 | { /* Convert the sector to be requested to MSF format */ | ||
1461 | struct cdrom_msf0 pending; | ||
1462 | log2msf(stuffp->pending / 4, &pending); | ||
1463 | cmd[1] = pending.minute; | ||
1464 | cmd[2] = pending.second; | ||
1465 | cmd[3] = pending.frame; | ||
1466 | } | ||
1467 | |||
1468 | cmd[6] = | ||
1469 | (unsigned | ||
1470 | char) ((stuffp->high_border - stuffp->pending) / 4); | ||
1471 | xtrace(XFER, "[%2d]\n", cmd[6]); | ||
1472 | |||
1473 | stuffp->busy = 1; | ||
1474 | /* Now really issue the request command */ | ||
1475 | outsb(stuffp->wreg_data, cmd, sizeof cmd); | ||
1476 | |||
1477 | } | ||
1478 | #ifdef AK2 | ||
1479 | if (stuffp->int_err) { | ||
1480 | stuffp->valid = 0; | ||
1481 | stuffp->int_err = 0; | ||
1482 | return -1; | ||
1483 | } | ||
1484 | #endif /* AK2 */ | ||
1485 | |||
1486 | stuffp->low_border = (stuffp->low_border += | ||
1487 | done) < | ||
1488 | stuffp->high_border ? stuffp->low_border : stuffp->high_border; | ||
1489 | |||
1490 | return done; | ||
1491 | } | ||
1492 | |||
1493 | |||
1494 | /* Access to elements of the mcdx_drive_map members */ | ||
1495 | |||
1496 | static unsigned port(int *ip) | ||
1497 | { | ||
1498 | return ip[0]; | ||
1499 | } | ||
1500 | static int irq(int *ip) | ||
1501 | { | ||
1502 | return ip[1]; | ||
1503 | } | ||
1504 | |||
1505 | /* Misc number converters */ | ||
1506 | |||
1507 | static unsigned int bcd2uint(unsigned char c) | ||
1508 | { | ||
1509 | return (c >> 4) * 10 + (c & 0x0f); | ||
1510 | } | ||
1511 | |||
1512 | static unsigned int uint2bcd(unsigned int ival) | ||
1513 | { | ||
1514 | return ((ival / 10) << 4) | (ival % 10); | ||
1515 | } | ||
1516 | |||
1517 | static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf) | ||
1518 | { | ||
1519 | l += CD_MSF_OFFSET; | ||
1520 | pmsf->minute = uint2bcd(l / 4500), l %= 4500; | ||
1521 | pmsf->second = uint2bcd(l / 75); | ||
1522 | pmsf->frame = uint2bcd(l % 75); | ||
1523 | } | ||
1524 | |||
1525 | static unsigned int msf2log(const struct cdrom_msf0 *pmsf) | ||
1526 | { | ||
1527 | return bcd2uint(pmsf->frame) | ||
1528 | + bcd2uint(pmsf->second) * 75 | ||
1529 | + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET; | ||
1530 | } | ||
1531 | |||
1532 | int mcdx_readtoc(struct s_drive_stuff *stuffp) | ||
1533 | /* Read the toc entries from the CD, | ||
1534 | * Return: -1 on failure, else 0 */ | ||
1535 | { | ||
1536 | |||
1537 | if (stuffp->toc) { | ||
1538 | xtrace(READTOC, "ioctl() toc already read\n"); | ||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | xtrace(READTOC, "ioctl() readtoc for %d tracks\n", | ||
1543 | stuffp->di.n_last - stuffp->di.n_first + 1); | ||
1544 | |||
1545 | if (-1 == mcdx_hold(stuffp, 1)) | ||
1546 | return -1; | ||
1547 | |||
1548 | xtrace(READTOC, "ioctl() tocmode\n"); | ||
1549 | if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) | ||
1550 | return -EIO; | ||
1551 | |||
1552 | /* all seems to be ok so far ... malloc */ | ||
1553 | { | ||
1554 | int size; | ||
1555 | size = | ||
1556 | sizeof(struct s_subqcode) * (stuffp->di.n_last - | ||
1557 | stuffp->di.n_first + 2); | ||
1558 | |||
1559 | xtrace(MALLOC, "ioctl() malloc %d bytes\n", size); | ||
1560 | stuffp->toc = kmalloc(size, GFP_KERNEL); | ||
1561 | if (!stuffp->toc) { | ||
1562 | xwarn("Cannot malloc %d bytes for toc\n", size); | ||
1563 | mcdx_setdrivemode(stuffp, DATA, 1); | ||
1564 | return -EIO; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | /* now read actually the index */ | ||
1569 | { | ||
1570 | int trk; | ||
1571 | int retries; | ||
1572 | |||
1573 | for (trk = 0; | ||
1574 | trk < (stuffp->di.n_last - stuffp->di.n_first + 1); | ||
1575 | trk++) | ||
1576 | stuffp->toc[trk].index = 0; | ||
1577 | |||
1578 | for (retries = 300; retries; retries--) { /* why 300? */ | ||
1579 | struct s_subqcode q; | ||
1580 | unsigned int idx; | ||
1581 | |||
1582 | if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) { | ||
1583 | mcdx_setdrivemode(stuffp, DATA, 1); | ||
1584 | return -EIO; | ||
1585 | } | ||
1586 | |||
1587 | idx = bcd2uint(q.index); | ||
1588 | |||
1589 | if ((idx > 0) | ||
1590 | && (idx <= stuffp->di.n_last) | ||
1591 | && (q.tno == 0) | ||
1592 | && (stuffp->toc[idx - stuffp->di.n_first]. | ||
1593 | index == 0)) { | ||
1594 | stuffp->toc[idx - stuffp->di.n_first] = q; | ||
1595 | xtrace(READTOC, | ||
1596 | "ioctl() toc idx %d (trk %d)\n", | ||
1597 | idx, trk); | ||
1598 | trk--; | ||
1599 | } | ||
1600 | if (trk == 0) | ||
1601 | break; | ||
1602 | } | ||
1603 | memset(&stuffp-> | ||
1604 | toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0, | ||
1605 | sizeof(stuffp->toc[0])); | ||
1606 | stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + | ||
1607 | 1].dt = stuffp->di.msf_leadout; | ||
1608 | } | ||
1609 | |||
1610 | /* unset toc mode */ | ||
1611 | xtrace(READTOC, "ioctl() undo toc mode\n"); | ||
1612 | if (-1 == mcdx_setdrivemode(stuffp, DATA, 2)) | ||
1613 | return -EIO; | ||
1614 | |||
1615 | #if MCDX_DEBUG && READTOC | ||
1616 | { | ||
1617 | int trk; | ||
1618 | for (trk = 0; | ||
1619 | trk < (stuffp->di.n_last - stuffp->di.n_first + 2); | ||
1620 | trk++) | ||
1621 | xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x" | ||
1622 | " %02x:%02x.%02x %02x:%02x.%02x\n", | ||
1623 | trk + stuffp->di.n_first, | ||
1624 | stuffp->toc[trk].control, | ||
1625 | stuffp->toc[trk].tno, | ||
1626 | stuffp->toc[trk].index, | ||
1627 | stuffp->toc[trk].tt.minute, | ||
1628 | stuffp->toc[trk].tt.second, | ||
1629 | stuffp->toc[trk].tt.frame, | ||
1630 | stuffp->toc[trk].dt.minute, | ||
1631 | stuffp->toc[trk].dt.second, | ||
1632 | stuffp->toc[trk].dt.frame); | ||
1633 | } | ||
1634 | #endif | ||
1635 | |||
1636 | return 0; | ||
1637 | } | ||
1638 | |||
1639 | static int | ||
1640 | mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf) | ||
1641 | { | ||
1642 | unsigned char cmd[7] = { | ||
1643 | 0, 0, 0, 0, 0, 0, 0 | ||
1644 | }; | ||
1645 | |||
1646 | if (!stuffp->readcmd) { | ||
1647 | xinfo("Can't play from missing disk.\n"); | ||
1648 | return -1; | ||
1649 | } | ||
1650 | |||
1651 | cmd[0] = stuffp->playcmd; | ||
1652 | |||
1653 | cmd[1] = msf->cdmsf_min0; | ||
1654 | cmd[2] = msf->cdmsf_sec0; | ||
1655 | cmd[3] = msf->cdmsf_frame0; | ||
1656 | cmd[4] = msf->cdmsf_min1; | ||
1657 | cmd[5] = msf->cdmsf_sec1; | ||
1658 | cmd[6] = msf->cdmsf_frame1; | ||
1659 | |||
1660 | xtrace(PLAYMSF, "ioctl(): play %x " | ||
1661 | "%02x:%02x:%02x -- %02x:%02x:%02x\n", | ||
1662 | cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]); | ||
1663 | |||
1664 | outsb(stuffp->wreg_data, cmd, sizeof cmd); | ||
1665 | |||
1666 | if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) { | ||
1667 | xwarn("playmsf() timeout\n"); | ||
1668 | return -1; | ||
1669 | } | ||
1670 | |||
1671 | stuffp->audiostatus = CDROM_AUDIO_PLAY; | ||
1672 | return 0; | ||
1673 | } | ||
1674 | |||
1675 | static int | ||
1676 | mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti) | ||
1677 | { | ||
1678 | struct s_subqcode *p; | ||
1679 | struct cdrom_msf msf; | ||
1680 | |||
1681 | if (-1 == mcdx_readtoc(stuffp)) | ||
1682 | return -1; | ||
1683 | |||
1684 | if (ti) | ||
1685 | p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first]; | ||
1686 | else | ||
1687 | p = &stuffp->start; | ||
1688 | |||
1689 | msf.cdmsf_min0 = p->dt.minute; | ||
1690 | msf.cdmsf_sec0 = p->dt.second; | ||
1691 | msf.cdmsf_frame0 = p->dt.frame; | ||
1692 | |||
1693 | if (ti) { | ||
1694 | p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1]; | ||
1695 | stuffp->stop = *p; | ||
1696 | } else | ||
1697 | p = &stuffp->stop; | ||
1698 | |||
1699 | msf.cdmsf_min1 = p->dt.minute; | ||
1700 | msf.cdmsf_sec1 = p->dt.second; | ||
1701 | msf.cdmsf_frame1 = p->dt.frame; | ||
1702 | |||
1703 | return mcdx_playmsf(stuffp, &msf); | ||
1704 | } | ||
1705 | |||
1706 | |||
1707 | /* Drive functions ************************************************/ | ||
1708 | |||
1709 | static int mcdx_tray_move(struct cdrom_device_info *cdi, int position) | ||
1710 | { | ||
1711 | struct s_drive_stuff *stuffp = cdi->handle; | ||
1712 | |||
1713 | if (!stuffp->present) | ||
1714 | return -ENXIO; | ||
1715 | if (!(stuffp->present & DOOR)) | ||
1716 | return -ENOSYS; | ||
1717 | |||
1718 | if (position) /* 1: eject */ | ||
1719 | return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3); | ||
1720 | else /* 0: close */ | ||
1721 | return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3); | ||
1722 | return 1; | ||
1723 | } | ||
1724 | |||
1725 | static int mcdx_stop(struct s_drive_stuff *stuffp, int tries) | ||
1726 | { | ||
1727 | return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); | ||
1728 | } | ||
1729 | |||
1730 | static int mcdx_hold(struct s_drive_stuff *stuffp, int tries) | ||
1731 | { | ||
1732 | return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); | ||
1733 | } | ||
1734 | |||
1735 | static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp, | ||
1736 | struct s_subqcode *sub, int tries) | ||
1737 | { | ||
1738 | char buf[11]; | ||
1739 | int ans; | ||
1740 | |||
1741 | if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf), | ||
1742 | 2 * HZ, tries))) | ||
1743 | return -1; | ||
1744 | sub->control = buf[1]; | ||
1745 | sub->tno = buf[2]; | ||
1746 | sub->index = buf[3]; | ||
1747 | sub->tt.minute = buf[4]; | ||
1748 | sub->tt.second = buf[5]; | ||
1749 | sub->tt.frame = buf[6]; | ||
1750 | sub->dt.minute = buf[8]; | ||
1751 | sub->dt.second = buf[9]; | ||
1752 | sub->dt.frame = buf[10]; | ||
1753 | |||
1754 | return ans; | ||
1755 | } | ||
1756 | |||
1757 | static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, | ||
1758 | struct s_multi *multi, int tries) | ||
1759 | { | ||
1760 | char buf[5]; | ||
1761 | int ans; | ||
1762 | |||
1763 | if (stuffp->present & MULTI) { | ||
1764 | ans = | ||
1765 | mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, | ||
1766 | tries); | ||
1767 | multi->multi = buf[1]; | ||
1768 | multi->msf_last.minute = buf[2]; | ||
1769 | multi->msf_last.second = buf[3]; | ||
1770 | multi->msf_last.frame = buf[4]; | ||
1771 | return ans; | ||
1772 | } else { | ||
1773 | multi->multi = 0; | ||
1774 | return 0; | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, | ||
1779 | int tries) | ||
1780 | { | ||
1781 | char buf[9]; | ||
1782 | int ans; | ||
1783 | ans = | ||
1784 | mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries); | ||
1785 | if (ans == -1) { | ||
1786 | info->n_first = 0; | ||
1787 | info->n_last = 0; | ||
1788 | } else { | ||
1789 | info->n_first = bcd2uint(buf[1]); | ||
1790 | info->n_last = bcd2uint(buf[2]); | ||
1791 | info->msf_leadout.minute = buf[3]; | ||
1792 | info->msf_leadout.second = buf[4]; | ||
1793 | info->msf_leadout.frame = buf[5]; | ||
1794 | info->msf_first.minute = buf[6]; | ||
1795 | info->msf_first.second = buf[7]; | ||
1796 | info->msf_first.frame = buf[8]; | ||
1797 | } | ||
1798 | return ans; | ||
1799 | } | ||
1800 | |||
1801 | static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, | ||
1802 | int tries) | ||
1803 | { | ||
1804 | char cmd[2]; | ||
1805 | int ans; | ||
1806 | |||
1807 | xtrace(HW, "setdrivemode() %d\n", mode); | ||
1808 | |||
1809 | if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries))) | ||
1810 | return -1; | ||
1811 | |||
1812 | switch (mode) { | ||
1813 | case TOC: | ||
1814 | cmd[1] |= 0x04; | ||
1815 | break; | ||
1816 | case DATA: | ||
1817 | cmd[1] &= ~0x04; | ||
1818 | break; | ||
1819 | case RAW: | ||
1820 | cmd[1] |= 0x40; | ||
1821 | break; | ||
1822 | case COOKED: | ||
1823 | cmd[1] &= ~0x40; | ||
1824 | break; | ||
1825 | default: | ||
1826 | break; | ||
1827 | } | ||
1828 | cmd[0] = 0x50; | ||
1829 | return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); | ||
1830 | } | ||
1831 | |||
1832 | static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, | ||
1833 | int tries) | ||
1834 | { | ||
1835 | unsigned char cmd[2] = { 0xa0 }; | ||
1836 | xtrace(HW, "setdatamode() %d\n", mode); | ||
1837 | switch (mode) { | ||
1838 | case MODE0: | ||
1839 | cmd[1] = 0x00; | ||
1840 | break; | ||
1841 | case MODE1: | ||
1842 | cmd[1] = 0x01; | ||
1843 | break; | ||
1844 | case MODE2: | ||
1845 | cmd[1] = 0x02; | ||
1846 | break; | ||
1847 | default: | ||
1848 | return -EINVAL; | ||
1849 | } | ||
1850 | return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); | ||
1851 | } | ||
1852 | |||
1853 | static int mcdx_config(struct s_drive_stuff *stuffp, int tries) | ||
1854 | { | ||
1855 | char cmd[4]; | ||
1856 | |||
1857 | xtrace(HW, "config()\n"); | ||
1858 | |||
1859 | cmd[0] = 0x90; | ||
1860 | |||
1861 | cmd[1] = 0x10; /* irq enable */ | ||
1862 | cmd[2] = 0x05; /* pre, err irq enable */ | ||
1863 | |||
1864 | if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries)) | ||
1865 | return -1; | ||
1866 | |||
1867 | cmd[1] = 0x02; /* dma select */ | ||
1868 | cmd[2] = 0x00; /* no dma */ | ||
1869 | |||
1870 | return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries); | ||
1871 | } | ||
1872 | |||
1873 | static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, | ||
1874 | int tries) | ||
1875 | { | ||
1876 | char buf[3]; | ||
1877 | int ans; | ||
1878 | |||
1879 | if (-1 == (ans = mcdx_talk(stuffp, "\xdc", | ||
1880 | 1, buf, sizeof(buf), 2 * HZ, tries))) | ||
1881 | return ans; | ||
1882 | |||
1883 | ver->code = buf[1]; | ||
1884 | ver->ver = buf[2]; | ||
1885 | |||
1886 | return ans; | ||
1887 | } | ||
1888 | |||
1889 | static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries) | ||
1890 | { | ||
1891 | if (mode == HARD) { | ||
1892 | outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */ | ||
1893 | outb(0, stuffp->wreg_reset); /* hw reset */ | ||
1894 | return 0; | ||
1895 | } else | ||
1896 | return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries); | ||
1897 | } | ||
1898 | |||
1899 | static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock) | ||
1900 | { | ||
1901 | struct s_drive_stuff *stuffp = cdi->handle; | ||
1902 | char cmd[2] = { 0xfe }; | ||
1903 | |||
1904 | if (!(stuffp->present & DOOR)) | ||
1905 | return -ENOSYS; | ||
1906 | if (stuffp->present & DOOR) { | ||
1907 | cmd[1] = lock ? 0x01 : 0x00; | ||
1908 | return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3); | ||
1909 | } else | ||
1910 | return 0; | ||
1911 | } | ||
1912 | |||
1913 | static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries) | ||
1914 | { | ||
1915 | return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); | ||
1916 | } | ||
1917 | |||
1918 | static int | ||
1919 | mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf) | ||
1920 | { | ||
1921 | unsigned long timeout = to + jiffies; | ||
1922 | char c; | ||
1923 | |||
1924 | if (!buf) | ||
1925 | buf = &c; | ||
1926 | |||
1927 | while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) { | ||
1928 | if (time_after(jiffies, timeout)) | ||
1929 | return -1; | ||
1930 | mcdx_delay(stuffp, delay); | ||
1931 | } | ||
1932 | |||
1933 | *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff; | ||
1934 | |||
1935 | return 0; | ||
1936 | } | ||
1937 | |||
1938 | static int mcdx_setattentuator(struct s_drive_stuff *stuffp, | ||
1939 | struct cdrom_volctrl *vol, int tries) | ||
1940 | { | ||
1941 | char cmd[5]; | ||
1942 | cmd[0] = 0xae; | ||
1943 | cmd[1] = vol->channel0; | ||
1944 | cmd[2] = 0; | ||
1945 | cmd[3] = vol->channel1; | ||
1946 | cmd[4] = 0; | ||
1947 | |||
1948 | return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries); | ||
1949 | } | ||
1950 | |||
1951 | MODULE_LICENSE("GPL"); | ||
1952 | MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/mcdx.h b/drivers/cdrom/mcdx.h new file mode 100644 index 000000000000..83c364a74dc4 --- /dev/null +++ b/drivers/cdrom/mcdx.h | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * Definitions for the Mitsumi CDROM interface | ||
3 | * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de> | ||
4 | * VERSION: @VERSION@ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program 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 | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; see the file COPYING. If not, write to | ||
18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | * Thanks to | ||
21 | * The Linux Community at all and ... | ||
22 | * Martin Harris (he wrote the first Mitsumi Driver) | ||
23 | * Eberhard Moenkeberg (he gave me much support and the initial kick) | ||
24 | * Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they | ||
25 | * improved the original driver) | ||
26 | * Jon Tombs, Bjorn Ekwall (module support) | ||
27 | * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) | ||
28 | * Gerd Knorr (he lent me his PhotoCD) | ||
29 | * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) | ||
30 | * Andreas Kies (testing the mysterious hang up's) | ||
31 | * ... somebody forgotten? | ||
32 | * Marcin Dalecki | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | /* | ||
37 | * The following lines are for user configuration | ||
38 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
39 | * | ||
40 | * {0|1} -- 1 if you want the driver detect your drive, may crash and | ||
41 | * needs a long time to seek. The higher the address the longer the | ||
42 | * seek. | ||
43 | * | ||
44 | * WARNING: AUTOPROBE doesn't work. | ||
45 | */ | ||
46 | #define MCDX_AUTOPROBE 0 | ||
47 | |||
48 | /* | ||
49 | * Drive specific settings according to the jumpers on the controller | ||
50 | * board(s). | ||
51 | * o MCDX_NDRIVES : number of used entries of the following table | ||
52 | * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller | ||
53 | * | ||
54 | * NOTE: I didn't get a drive at irq 9(2) working. Not even alone. | ||
55 | */ | ||
56 | #if MCDX_AUTOPROBE == 0 | ||
57 | #define MCDX_NDRIVES 1 | ||
58 | #define MCDX_DRIVEMAP { \ | ||
59 | {0x300, 11}, \ | ||
60 | {0x304, 05}, \ | ||
61 | {0x000, 00}, \ | ||
62 | {0x000, 00}, \ | ||
63 | {0x000, 00}, \ | ||
64 | } | ||
65 | #else | ||
66 | #error Autoprobing is not implemented yet. | ||
67 | #endif | ||
68 | |||
69 | #ifndef MCDX_QUIET | ||
70 | #define MCDX_QUIET 1 | ||
71 | #endif | ||
72 | |||
73 | #ifndef MCDX_DEBUG | ||
74 | #define MCDX_DEBUG 0 | ||
75 | #endif | ||
76 | |||
77 | /* *** make the following line uncommented, if you're sure, | ||
78 | * *** all configuration is done */ | ||
79 | /* #define I_WAS_HERE */ | ||
80 | |||
81 | /* The name of the device */ | ||
82 | #define MCDX "mcdx" | ||
83 | |||
84 | /* Flags for DEBUGGING */ | ||
85 | #define INIT 0 | ||
86 | #define MALLOC 0 | ||
87 | #define IOCTL 0 | ||
88 | #define PLAYTRK 0 | ||
89 | #define SUBCHNL 0 | ||
90 | #define TOCHDR 0 | ||
91 | #define MS 0 | ||
92 | #define PLAYMSF 0 | ||
93 | #define READTOC 0 | ||
94 | #define OPENCLOSE 0 | ||
95 | #define HW 0 | ||
96 | #define TALK 0 | ||
97 | #define IRQ 0 | ||
98 | #define XFER 0 | ||
99 | #define REQUEST 0 | ||
100 | #define SLEEP 0 | ||
101 | |||
102 | /* The following addresses are taken from the Mitsumi Reference | ||
103 | * and describe the possible i/o range for the controller. | ||
104 | */ | ||
105 | #define MCDX_IO_BEGIN ((char*) 0x300) /* first base of i/o addr */ | ||
106 | #define MCDX_IO_END ((char*) 0x3fc) /* last base of i/o addr */ | ||
107 | |||
108 | /* Per controller 4 bytes i/o are needed. */ | ||
109 | #define MCDX_IO_SIZE 4 | ||
110 | |||
111 | /* | ||
112 | * Bits | ||
113 | */ | ||
114 | |||
115 | /* The status byte, returned from every command, set if | ||
116 | * the description is true */ | ||
117 | #define MCDX_RBIT_OPEN 0x80 /* door is open */ | ||
118 | #define MCDX_RBIT_DISKSET 0x40 /* disk set (recognised) */ | ||
119 | #define MCDX_RBIT_CHANGED 0x20 /* disk was changed */ | ||
120 | #define MCDX_RBIT_CHECK 0x10 /* disk rotates, servo is on */ | ||
121 | #define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */ | ||
122 | #define MCDX_RBIT_RDERR 0x04 /* read error, refer SENSE KEY */ | ||
123 | #define MCDX_RBIT_AUDIOBS 0x02 /* currently playing audio */ | ||
124 | #define MCDX_RBIT_CMDERR 0x01 /* command, param or format error */ | ||
125 | |||
126 | /* The I/O Register holding the h/w status of the drive, | ||
127 | * can be read at i/o base + 1 */ | ||
128 | #define MCDX_RBIT_DOOR 0x10 /* door is open */ | ||
129 | #define MCDX_RBIT_STEN 0x04 /* if 0, i/o base contains drive status */ | ||
130 | #define MCDX_RBIT_DTEN 0x02 /* if 0, i/o base contains data */ | ||
131 | |||
132 | /* | ||
133 | * The commands. | ||
134 | */ | ||
135 | |||
136 | #define OPCODE 1 /* offset of opcode */ | ||
137 | #define MCDX_CMD_REQUEST_TOC 1, 0x10 | ||
138 | #define MCDX_CMD_REQUEST_STATUS 1, 0x40 | ||
139 | #define MCDX_CMD_RESET 1, 0x60 | ||
140 | #define MCDX_CMD_REQUEST_DRIVE_MODE 1, 0xc2 | ||
141 | #define MCDX_CMD_SET_INTERLEAVE 2, 0xc8, 0 | ||
142 | #define MCDX_CMD_DATAMODE_SET 2, 0xa0, 0 | ||
143 | #define MCDX_DATAMODE1 0x01 | ||
144 | #define MCDX_DATAMODE2 0x02 | ||
145 | #define MCDX_CMD_LOCK_DOOR 2, 0xfe, 0 | ||
146 | |||
147 | #define READ_AHEAD 4 /* 8 Sectors (4K) */ | ||
148 | |||
149 | /* Useful macros */ | ||
150 | #define e_door(x) ((x) & MCDX_RBIT_OPEN) | ||
151 | #define e_check(x) (~(x) & MCDX_RBIT_CHECK) | ||
152 | #define e_notset(x) (~(x) & MCDX_RBIT_DISKSET) | ||
153 | #define e_changed(x) ((x) & MCDX_RBIT_CHANGED) | ||
154 | #define e_audio(x) ((x) & MCDX_RBIT_AUDIOTR) | ||
155 | #define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS) | ||
156 | #define e_cmderr(x) ((x) & MCDX_RBIT_CMDERR) | ||
157 | #define e_readerr(x) ((x) & MCDX_RBIT_RDERR) | ||
158 | |||
159 | /** no drive specific */ | ||
160 | #define MCDX_CDBLK 2048 /* 2048 cooked data each blk */ | ||
161 | |||
162 | #define MCDX_DATA_TIMEOUT (HZ/10) /* 0.1 second */ | ||
163 | |||
164 | /* | ||
165 | * Access to the msf array | ||
166 | */ | ||
167 | #define MSF_MIN 0 /* minute */ | ||
168 | #define MSF_SEC 1 /* second */ | ||
169 | #define MSF_FRM 2 /* frame */ | ||
170 | |||
171 | /* | ||
172 | * Errors | ||
173 | */ | ||
174 | #define MCDX_E 1 /* unspec error */ | ||
175 | #define MCDX_ST_EOM 0x0100 /* end of media */ | ||
176 | #define MCDX_ST_DRV 0x00ff /* mask to query the drive status */ | ||
177 | |||
178 | #ifndef I_WAS_HERE | ||
179 | #ifndef MODULE | ||
180 | #warning You have not edited mcdx.h | ||
181 | #warning Perhaps irq and i/o settings are wrong. | ||
182 | #endif | ||
183 | #endif | ||
184 | |||
185 | /* ex:set ts=4 sw=4: */ | ||
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c new file mode 100644 index 000000000000..7e69c54568bf --- /dev/null +++ b/drivers/cdrom/optcd.c | |||
@@ -0,0 +1,2106 @@ | |||
1 | /* linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver | ||
2 | $Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $ | ||
3 | |||
4 | Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) | ||
5 | |||
6 | |||
7 | Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks | ||
8 | by Eberhard Moenkeberg (emoenke@gwdg.de). | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2, or (at your option) | ||
13 | any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | /* Revision history | ||
26 | |||
27 | |||
28 | 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet. | ||
29 | Detection of disk change doesn't work. | ||
30 | 21-5-95 v0.1 First ALPHA version. CD can be mounted. The | ||
31 | device major nr is borrowed from the Aztech | ||
32 | driver. Speed is around 240 kb/s, as measured | ||
33 | with "time dd if=/dev/cdrom of=/dev/null \ | ||
34 | bs=2048 count=4096". | ||
35 | 24-6-95 v0.2 Reworked the #defines for the command codes | ||
36 | and the like, as well as the structure of | ||
37 | the hardware communication protocol, to | ||
38 | reflect the "official" documentation, kindly | ||
39 | supplied by C.K. Tan, Optics Storage Pte. Ltd. | ||
40 | Also tidied up the state machine somewhat. | ||
41 | 28-6-95 v0.3 Removed the ISP-16 interface code, as this | ||
42 | should go into its own driver. The driver now | ||
43 | has its own major nr. | ||
44 | Disk change detection now seems to work, too. | ||
45 | This version became part of the standard | ||
46 | kernel as of version 1.3.7 | ||
47 | 24-9-95 v0.4 Re-inserted ISP-16 interface code which I | ||
48 | copied from sjcd.c, with a few changes. | ||
49 | Updated README.optcd. Submitted for | ||
50 | inclusion in 1.3.21 | ||
51 | 29-9-95 v0.4a Fixed bug that prevented compilation as module | ||
52 | 25-10-95 v0.5 Started multisession code. Implementation | ||
53 | copied from Werner Zimmermann, who copied it | ||
54 | from Heiko Schlittermann's mcdx. | ||
55 | 17-1-96 v0.6 Multisession works; some cleanup too. | ||
56 | 18-4-96 v0.7 Increased some timing constants; | ||
57 | thanks to Luke McFarlane. Also tidied up some | ||
58 | printk behaviour. ISP16 initialization | ||
59 | is now handled by a separate driver. | ||
60 | |||
61 | 09-11-99 Make kernel-parameter implementation work with 2.3.x | ||
62 | Removed init_module & cleanup_module in favor of | ||
63 | module_init & module_exit. | ||
64 | Torben Mathiasen <tmm@image.dk> | ||
65 | */ | ||
66 | |||
67 | /* Includes */ | ||
68 | |||
69 | |||
70 | #include <linux/module.h> | ||
71 | #include <linux/mm.h> | ||
72 | #include <linux/ioport.h> | ||
73 | #include <linux/init.h> | ||
74 | |||
75 | #include <asm/io.h> | ||
76 | #include <linux/blkdev.h> | ||
77 | |||
78 | #include <linux/cdrom.h> | ||
79 | #include "optcd.h" | ||
80 | |||
81 | #include <asm/uaccess.h> | ||
82 | |||
83 | #define MAJOR_NR OPTICS_CDROM_MAJOR | ||
84 | #define QUEUE (opt_queue) | ||
85 | #define CURRENT elv_next_request(opt_queue) | ||
86 | |||
87 | |||
88 | /* Debug support */ | ||
89 | |||
90 | |||
91 | /* Don't forget to add new debug flags here. */ | ||
92 | #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \ | ||
93 | DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS | ||
94 | #define DEBUG(x) debug x | ||
95 | static void debug(int debug_this, const char* fmt, ...) | ||
96 | { | ||
97 | char s[1024]; | ||
98 | va_list args; | ||
99 | |||
100 | if (!debug_this) | ||
101 | return; | ||
102 | |||
103 | va_start(args, fmt); | ||
104 | vsprintf(s, fmt, args); | ||
105 | printk(KERN_DEBUG "optcd: %s\n", s); | ||
106 | va_end(args); | ||
107 | } | ||
108 | #else | ||
109 | #define DEBUG(x) | ||
110 | #endif | ||
111 | |||
112 | |||
113 | /* Drive hardware/firmware characteristics | ||
114 | Identifiers in accordance with Optics Storage documentation */ | ||
115 | |||
116 | |||
117 | #define optcd_port optcd /* Needed for the modutils. */ | ||
118 | static short optcd_port = OPTCD_PORTBASE; /* I/O base of drive. */ | ||
119 | module_param(optcd_port, short, 0); | ||
120 | /* Drive registers, read */ | ||
121 | #define DATA_PORT optcd_port /* Read data/status */ | ||
122 | #define STATUS_PORT optcd_port+1 /* Indicate data/status availability */ | ||
123 | |||
124 | /* Drive registers, write */ | ||
125 | #define COMIN_PORT optcd_port /* For passing command/parameter */ | ||
126 | #define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */ | ||
127 | #define HCON_PORT optcd_port+2 /* Host Xfer Configuration */ | ||
128 | |||
129 | |||
130 | /* Command completion/status read from DATA register */ | ||
131 | #define ST_DRVERR 0x80 | ||
132 | #define ST_DOOR_OPEN 0x40 | ||
133 | #define ST_MIXEDMODE_DISK 0x20 | ||
134 | #define ST_MODE_BITS 0x1c | ||
135 | #define ST_M_STOP 0x00 | ||
136 | #define ST_M_READ 0x04 | ||
137 | #define ST_M_AUDIO 0x04 | ||
138 | #define ST_M_PAUSE 0x08 | ||
139 | #define ST_M_INITIAL 0x0c | ||
140 | #define ST_M_ERROR 0x10 | ||
141 | #define ST_M_OTHERS 0x14 | ||
142 | #define ST_MODE2TRACK 0x02 | ||
143 | #define ST_DSK_CHG 0x01 | ||
144 | #define ST_L_LOCK 0x01 | ||
145 | #define ST_CMD_OK 0x00 | ||
146 | #define ST_OP_OK 0x01 | ||
147 | #define ST_PA_OK 0x02 | ||
148 | #define ST_OP_ERROR 0x05 | ||
149 | #define ST_PA_ERROR 0x06 | ||
150 | |||
151 | |||
152 | /* Error codes (appear as command completion code from DATA register) */ | ||
153 | /* Player related errors */ | ||
154 | #define ERR_ILLCMD 0x11 /* Illegal command to player module */ | ||
155 | #define ERR_ILLPARM 0x12 /* Illegal parameter to player module */ | ||
156 | #define ERR_SLEDGE 0x13 | ||
157 | #define ERR_FOCUS 0x14 | ||
158 | #define ERR_MOTOR 0x15 | ||
159 | #define ERR_RADIAL 0x16 | ||
160 | #define ERR_PLL 0x17 /* PLL lock error */ | ||
161 | #define ERR_SUB_TIM 0x18 /* Subcode timeout error */ | ||
162 | #define ERR_SUB_NF 0x19 /* Subcode not found error */ | ||
163 | #define ERR_TRAY 0x1a | ||
164 | #define ERR_TOC 0x1b /* Table of Contents read error */ | ||
165 | #define ERR_JUMP 0x1c | ||
166 | /* Data errors */ | ||
167 | #define ERR_MODE 0x21 | ||
168 | #define ERR_FORM 0x22 | ||
169 | #define ERR_HEADADDR 0x23 /* Header Address not found */ | ||
170 | #define ERR_CRC 0x24 | ||
171 | #define ERR_ECC 0x25 /* Uncorrectable ECC error */ | ||
172 | #define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */ | ||
173 | #define ERR_ILLBSYNC 0x27 /* Illegal block sync error */ | ||
174 | #define ERR_VDST 0x28 /* VDST not found */ | ||
175 | /* Timeout errors */ | ||
176 | #define ERR_READ_TIM 0x31 /* Read timeout error */ | ||
177 | #define ERR_DEC_STP 0x32 /* Decoder stopped */ | ||
178 | #define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */ | ||
179 | /* Function abort codes */ | ||
180 | #define ERR_KEY 0x41 /* Key -Detected abort */ | ||
181 | #define ERR_READ_FINISH 0x42 /* Read Finish */ | ||
182 | /* Second Byte diagnostic codes */ | ||
183 | #define ERR_NOBSYNC 0x01 /* No block sync */ | ||
184 | #define ERR_SHORTB 0x02 /* Short block */ | ||
185 | #define ERR_LONGB 0x03 /* Long block */ | ||
186 | #define ERR_SHORTDSP 0x04 /* Short DSP word */ | ||
187 | #define ERR_LONGDSP 0x05 /* Long DSP word */ | ||
188 | |||
189 | |||
190 | /* Status availability flags read from STATUS register */ | ||
191 | #define FL_EJECT 0x20 | ||
192 | #define FL_WAIT 0x10 /* active low */ | ||
193 | #define FL_EOP 0x08 /* active low */ | ||
194 | #define FL_STEN 0x04 /* Status available when low */ | ||
195 | #define FL_DTEN 0x02 /* Data available when low */ | ||
196 | #define FL_DRQ 0x01 /* active low */ | ||
197 | #define FL_RESET 0xde /* These bits are high after a reset */ | ||
198 | #define FL_STDT (FL_STEN|FL_DTEN) | ||
199 | |||
200 | |||
201 | /* Transfer mode, written to HCON register */ | ||
202 | #define HCON_DTS 0x08 | ||
203 | #define HCON_SDRQB 0x04 | ||
204 | #define HCON_LOHI 0x02 | ||
205 | #define HCON_DMA16 0x01 | ||
206 | |||
207 | |||
208 | /* Drive command set, written to COMIN register */ | ||
209 | /* Quick response commands */ | ||
210 | #define COMDRVST 0x20 /* Drive Status Read */ | ||
211 | #define COMERRST 0x21 /* Error Status Read */ | ||
212 | #define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */ | ||
213 | #define COMINITSINGLE 0x28 /* Initialize Single Speed */ | ||
214 | #define COMINITDOUBLE 0x29 /* Initialize Double Speed */ | ||
215 | #define COMUNLOCK 0x30 /* Unlock */ | ||
216 | #define COMLOCK 0x31 /* Lock */ | ||
217 | #define COMLOCKST 0x32 /* Lock/Unlock Status */ | ||
218 | #define COMVERSION 0x40 /* Get Firmware Revision */ | ||
219 | #define COMVOIDREADMODE 0x50 /* Void Data Read Mode */ | ||
220 | /* Read commands */ | ||
221 | #define COMFETCH 0x60 /* Prefetch Data */ | ||
222 | #define COMREAD 0x61 /* Read */ | ||
223 | #define COMREADRAW 0x62 /* Read Raw Data */ | ||
224 | #define COMREADALL 0x63 /* Read All 2646 Bytes */ | ||
225 | /* Player control commands */ | ||
226 | #define COMLEADIN 0x70 /* Seek To Lead-in */ | ||
227 | #define COMSEEK 0x71 /* Seek */ | ||
228 | #define COMPAUSEON 0x80 /* Pause On */ | ||
229 | #define COMPAUSEOFF 0x81 /* Pause Off */ | ||
230 | #define COMSTOP 0x82 /* Stop */ | ||
231 | #define COMOPEN 0x90 /* Open Tray Door */ | ||
232 | #define COMCLOSE 0x91 /* Close Tray Door */ | ||
233 | #define COMPLAY 0xa0 /* Audio Play */ | ||
234 | #define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */ | ||
235 | #define COMSUBQ 0xb0 /* Read Sub-q Code */ | ||
236 | #define COMLOCATION 0xb1 /* Read Head Position */ | ||
237 | /* Audio control commands */ | ||
238 | #define COMCHCTRL 0xc0 /* Audio Channel Control */ | ||
239 | /* Miscellaneous (test) commands */ | ||
240 | #define COMDRVTEST 0xd0 /* Write Test Bytes */ | ||
241 | #define COMTEST 0xd1 /* Diagnostic Test */ | ||
242 | |||
243 | /* Low level drive interface. Only here we do actual I/O | ||
244 | Waiting for status / data available */ | ||
245 | |||
246 | |||
247 | /* Busy wait until FLAG goes low. Return 0 on timeout. */ | ||
248 | inline static int flag_low(int flag, unsigned long timeout) | ||
249 | { | ||
250 | int flag_high; | ||
251 | unsigned long count = 0; | ||
252 | |||
253 | while ((flag_high = (inb(STATUS_PORT) & flag))) | ||
254 | if (++count >= timeout) | ||
255 | break; | ||
256 | |||
257 | DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s", | ||
258 | flag, count, flag_high ? " timeout" : "")); | ||
259 | return !flag_high; | ||
260 | } | ||
261 | |||
262 | |||
263 | /* Timed waiting for status or data */ | ||
264 | static int sleep_timeout; /* max # of ticks to sleep */ | ||
265 | static DECLARE_WAIT_QUEUE_HEAD(waitq); | ||
266 | static void sleep_timer(unsigned long data); | ||
267 | static struct timer_list delay_timer = TIMER_INITIALIZER(sleep_timer, 0, 0); | ||
268 | static DEFINE_SPINLOCK(optcd_lock); | ||
269 | static struct request_queue *opt_queue; | ||
270 | |||
271 | /* Timer routine: wake up when desired flag goes low, | ||
272 | or when timeout expires. */ | ||
273 | static void sleep_timer(unsigned long data) | ||
274 | { | ||
275 | int flags = inb(STATUS_PORT) & FL_STDT; | ||
276 | |||
277 | if (flags == FL_STDT && --sleep_timeout > 0) { | ||
278 | mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */ | ||
279 | } else | ||
280 | wake_up(&waitq); | ||
281 | } | ||
282 | |||
283 | |||
284 | /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */ | ||
285 | static int sleep_flag_low(int flag, unsigned long timeout) | ||
286 | { | ||
287 | int flag_high; | ||
288 | |||
289 | DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low")); | ||
290 | |||
291 | sleep_timeout = timeout; | ||
292 | flag_high = inb(STATUS_PORT) & flag; | ||
293 | if (flag_high && sleep_timeout > 0) { | ||
294 | mod_timer(&delay_timer, jiffies + HZ/100); | ||
295 | sleep_on(&waitq); | ||
296 | flag_high = inb(STATUS_PORT) & flag; | ||
297 | } | ||
298 | |||
299 | DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s", | ||
300 | flag, timeout, flag_high ? " timeout" : "")); | ||
301 | return !flag_high; | ||
302 | } | ||
303 | |||
304 | /* Low level drive interface. Only here we do actual I/O | ||
305 | Sending commands and parameters */ | ||
306 | |||
307 | |||
308 | /* Errors in the command protocol */ | ||
309 | #define ERR_IF_CMD_TIMEOUT 0x100 | ||
310 | #define ERR_IF_ERR_TIMEOUT 0x101 | ||
311 | #define ERR_IF_RESP_TIMEOUT 0x102 | ||
312 | #define ERR_IF_DATA_TIMEOUT 0x103 | ||
313 | #define ERR_IF_NOSTAT 0x104 | ||
314 | |||
315 | |||
316 | /* Send command code. Return <0 indicates error */ | ||
317 | static int send_cmd(int cmd) | ||
318 | { | ||
319 | unsigned char ack; | ||
320 | |||
321 | DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd)); | ||
322 | |||
323 | outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */ | ||
324 | outb(cmd, COMIN_PORT); /* Send command code */ | ||
325 | if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ | ||
326 | return -ERR_IF_CMD_TIMEOUT; | ||
327 | ack = inb(DATA_PORT); /* read command acknowledge */ | ||
328 | outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ | ||
329 | return ack==ST_OP_OK ? 0 : -ack; | ||
330 | } | ||
331 | |||
332 | |||
333 | /* Send command parameters. Return <0 indicates error */ | ||
334 | static int send_params(struct cdrom_msf *params) | ||
335 | { | ||
336 | unsigned char ack; | ||
337 | |||
338 | DEBUG((DEBUG_DRIVE_IF, "sending parameters" | ||
339 | " %02x:%02x:%02x" | ||
340 | " %02x:%02x:%02x", | ||
341 | params->cdmsf_min0, | ||
342 | params->cdmsf_sec0, | ||
343 | params->cdmsf_frame0, | ||
344 | params->cdmsf_min1, | ||
345 | params->cdmsf_sec1, | ||
346 | params->cdmsf_frame1)); | ||
347 | |||
348 | outb(params->cdmsf_min0, COMIN_PORT); | ||
349 | outb(params->cdmsf_sec0, COMIN_PORT); | ||
350 | outb(params->cdmsf_frame0, COMIN_PORT); | ||
351 | outb(params->cdmsf_min1, COMIN_PORT); | ||
352 | outb(params->cdmsf_sec1, COMIN_PORT); | ||
353 | outb(params->cdmsf_frame1, COMIN_PORT); | ||
354 | if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ | ||
355 | return -ERR_IF_CMD_TIMEOUT; | ||
356 | ack = inb(DATA_PORT); /* read command acknowledge */ | ||
357 | return ack==ST_PA_OK ? 0 : -ack; | ||
358 | } | ||
359 | |||
360 | |||
361 | /* Send parameters for SEEK command. Return <0 indicates error */ | ||
362 | static int send_seek_params(struct cdrom_msf *params) | ||
363 | { | ||
364 | unsigned char ack; | ||
365 | |||
366 | DEBUG((DEBUG_DRIVE_IF, "sending seek parameters" | ||
367 | " %02x:%02x:%02x", | ||
368 | params->cdmsf_min0, | ||
369 | params->cdmsf_sec0, | ||
370 | params->cdmsf_frame0)); | ||
371 | |||
372 | outb(params->cdmsf_min0, COMIN_PORT); | ||
373 | outb(params->cdmsf_sec0, COMIN_PORT); | ||
374 | outb(params->cdmsf_frame0, COMIN_PORT); | ||
375 | if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ | ||
376 | return -ERR_IF_CMD_TIMEOUT; | ||
377 | ack = inb(DATA_PORT); /* read command acknowledge */ | ||
378 | return ack==ST_PA_OK ? 0 : -ack; | ||
379 | } | ||
380 | |||
381 | |||
382 | /* Wait for command execution status. Choice between busy waiting | ||
383 | and sleeping. Return value <0 indicates timeout. */ | ||
384 | inline static int get_exec_status(int busy_waiting) | ||
385 | { | ||
386 | unsigned char exec_status; | ||
387 | |||
388 | if (busy_waiting | ||
389 | ? !flag_low(FL_STEN, BUSY_TIMEOUT) | ||
390 | : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT)) | ||
391 | return -ERR_IF_CMD_TIMEOUT; | ||
392 | |||
393 | exec_status = inb(DATA_PORT); | ||
394 | DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status)); | ||
395 | return exec_status; | ||
396 | } | ||
397 | |||
398 | |||
399 | /* Wait busy for extra byte of data that a command returns. | ||
400 | Return value <0 indicates timeout. */ | ||
401 | inline static int get_data(int short_timeout) | ||
402 | { | ||
403 | unsigned char data; | ||
404 | |||
405 | if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT)) | ||
406 | return -ERR_IF_DATA_TIMEOUT; | ||
407 | |||
408 | data = inb(DATA_PORT); | ||
409 | DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data)); | ||
410 | return data; | ||
411 | } | ||
412 | |||
413 | |||
414 | /* Returns 0 if failed */ | ||
415 | static int reset_drive(void) | ||
416 | { | ||
417 | unsigned long count = 0; | ||
418 | int flags; | ||
419 | |||
420 | DEBUG((DEBUG_DRIVE_IF, "reset drive")); | ||
421 | |||
422 | outb(0, RESET_PORT); | ||
423 | while (++count < RESET_WAIT) | ||
424 | inb(DATA_PORT); | ||
425 | |||
426 | count = 0; | ||
427 | while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET) | ||
428 | if (++count >= BUSY_TIMEOUT) | ||
429 | break; | ||
430 | |||
431 | DEBUG((DEBUG_DRIVE_IF, "reset %s", | ||
432 | flags == FL_RESET ? "succeeded" : "failed")); | ||
433 | |||
434 | if (flags != FL_RESET) | ||
435 | return 0; /* Reset failed */ | ||
436 | outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ | ||
437 | return 1; /* Reset succeeded */ | ||
438 | } | ||
439 | |||
440 | |||
441 | /* Facilities for asynchronous operation */ | ||
442 | |||
443 | /* Read status/data availability flags FL_STEN and FL_DTEN */ | ||
444 | inline static int stdt_flags(void) | ||
445 | { | ||
446 | return inb(STATUS_PORT) & FL_STDT; | ||
447 | } | ||
448 | |||
449 | |||
450 | /* Fetch status that has previously been waited for. <0 means not available */ | ||
451 | inline static int fetch_status(void) | ||
452 | { | ||
453 | unsigned char status; | ||
454 | |||
455 | if (inb(STATUS_PORT) & FL_STEN) | ||
456 | return -ERR_IF_NOSTAT; | ||
457 | |||
458 | status = inb(DATA_PORT); | ||
459 | DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status)); | ||
460 | return status; | ||
461 | } | ||
462 | |||
463 | |||
464 | /* Fetch data that has previously been waited for. */ | ||
465 | inline static void fetch_data(char *buf, int n) | ||
466 | { | ||
467 | insb(DATA_PORT, buf, n); | ||
468 | DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n)); | ||
469 | } | ||
470 | |||
471 | |||
472 | /* Flush status and data fifos */ | ||
473 | inline static void flush_data(void) | ||
474 | { | ||
475 | while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT) | ||
476 | inb(DATA_PORT); | ||
477 | DEBUG((DEBUG_DRIVE_IF, "flushed fifos")); | ||
478 | } | ||
479 | |||
480 | /* Command protocol */ | ||
481 | |||
482 | |||
483 | /* Send a simple command and wait for response. Command codes < COMFETCH | ||
484 | are quick response commands */ | ||
485 | inline static int exec_cmd(int cmd) | ||
486 | { | ||
487 | int ack = send_cmd(cmd); | ||
488 | if (ack < 0) | ||
489 | return ack; | ||
490 | return get_exec_status(cmd < COMFETCH); | ||
491 | } | ||
492 | |||
493 | |||
494 | /* Send a command with parameters. Don't wait for the response, | ||
495 | * which consists of data blocks read from the CD. */ | ||
496 | inline static int exec_read_cmd(int cmd, struct cdrom_msf *params) | ||
497 | { | ||
498 | int ack = send_cmd(cmd); | ||
499 | if (ack < 0) | ||
500 | return ack; | ||
501 | return send_params(params); | ||
502 | } | ||
503 | |||
504 | |||
505 | /* Send a seek command with parameters and wait for response */ | ||
506 | inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params) | ||
507 | { | ||
508 | int ack = send_cmd(cmd); | ||
509 | if (ack < 0) | ||
510 | return ack; | ||
511 | ack = send_seek_params(params); | ||
512 | if (ack < 0) | ||
513 | return ack; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | |||
518 | /* Send a command with parameters and wait for response */ | ||
519 | inline static int exec_long_cmd(int cmd, struct cdrom_msf *params) | ||
520 | { | ||
521 | int ack = exec_read_cmd(cmd, params); | ||
522 | if (ack < 0) | ||
523 | return ack; | ||
524 | return get_exec_status(0); | ||
525 | } | ||
526 | |||
527 | /* Address conversion routines */ | ||
528 | |||
529 | |||
530 | /* Binary to BCD (2 digits) */ | ||
531 | inline static void single_bin2bcd(u_char *p) | ||
532 | { | ||
533 | DEBUG((DEBUG_CONV, "bin2bcd %02d", *p)); | ||
534 | *p = (*p % 10) | ((*p / 10) << 4); | ||
535 | } | ||
536 | |||
537 | |||
538 | /* Convert entire msf struct */ | ||
539 | static void bin2bcd(struct cdrom_msf *msf) | ||
540 | { | ||
541 | single_bin2bcd(&msf->cdmsf_min0); | ||
542 | single_bin2bcd(&msf->cdmsf_sec0); | ||
543 | single_bin2bcd(&msf->cdmsf_frame0); | ||
544 | single_bin2bcd(&msf->cdmsf_min1); | ||
545 | single_bin2bcd(&msf->cdmsf_sec1); | ||
546 | single_bin2bcd(&msf->cdmsf_frame1); | ||
547 | } | ||
548 | |||
549 | |||
550 | /* Linear block address to minute, second, frame form */ | ||
551 | #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */ | ||
552 | |||
553 | static void lba2msf(int lba, struct cdrom_msf *msf) | ||
554 | { | ||
555 | DEBUG((DEBUG_CONV, "lba2msf %d", lba)); | ||
556 | lba += CD_MSF_OFFSET; | ||
557 | msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM; | ||
558 | msf->cdmsf_sec0 = lba / CD_FRAMES; | ||
559 | msf->cdmsf_frame0 = lba % CD_FRAMES; | ||
560 | msf->cdmsf_min1 = 0; | ||
561 | msf->cdmsf_sec1 = 0; | ||
562 | msf->cdmsf_frame1 = 0; | ||
563 | bin2bcd(msf); | ||
564 | } | ||
565 | |||
566 | |||
567 | /* Two BCD digits to binary */ | ||
568 | inline static u_char bcd2bin(u_char bcd) | ||
569 | { | ||
570 | DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd)); | ||
571 | return (bcd >> 4) * 10 + (bcd & 0x0f); | ||
572 | } | ||
573 | |||
574 | |||
575 | static void msf2lba(union cdrom_addr *addr) | ||
576 | { | ||
577 | addr->lba = addr->msf.minute * CD_FPM | ||
578 | + addr->msf.second * CD_FRAMES | ||
579 | + addr->msf.frame - CD_MSF_OFFSET; | ||
580 | } | ||
581 | |||
582 | |||
583 | /* Minute, second, frame address BCD to binary or to linear address, | ||
584 | depending on MODE */ | ||
585 | static void msf_bcd2bin(union cdrom_addr *addr) | ||
586 | { | ||
587 | addr->msf.minute = bcd2bin(addr->msf.minute); | ||
588 | addr->msf.second = bcd2bin(addr->msf.second); | ||
589 | addr->msf.frame = bcd2bin(addr->msf.frame); | ||
590 | } | ||
591 | |||
592 | /* High level drive commands */ | ||
593 | |||
594 | |||
595 | static int audio_status = CDROM_AUDIO_NO_STATUS; | ||
596 | static char toc_uptodate = 0; | ||
597 | static char disk_changed = 1; | ||
598 | |||
599 | /* Get drive status, flagging completion of audio play and disk changes. */ | ||
600 | static int drive_status(void) | ||
601 | { | ||
602 | int status; | ||
603 | |||
604 | status = exec_cmd(COMIOCTLISTAT); | ||
605 | DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status)); | ||
606 | if (status < 0) | ||
607 | return status; | ||
608 | if (status == 0xff) /* No status available */ | ||
609 | return -ERR_IF_NOSTAT; | ||
610 | |||
611 | if (((status & ST_MODE_BITS) != ST_M_AUDIO) && | ||
612 | (audio_status == CDROM_AUDIO_PLAY)) { | ||
613 | audio_status = CDROM_AUDIO_COMPLETED; | ||
614 | } | ||
615 | |||
616 | if (status & ST_DSK_CHG) { | ||
617 | toc_uptodate = 0; | ||
618 | disk_changed = 1; | ||
619 | audio_status = CDROM_AUDIO_NO_STATUS; | ||
620 | } | ||
621 | |||
622 | return status; | ||
623 | } | ||
624 | |||
625 | |||
626 | /* Read the current Q-channel info. Also used for reading the | ||
627 | table of contents. qp->cdsc_format must be set on entry to | ||
628 | indicate the desired address format */ | ||
629 | static int get_q_channel(struct cdrom_subchnl *qp) | ||
630 | { | ||
631 | int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10; | ||
632 | |||
633 | status = drive_status(); | ||
634 | if (status < 0) | ||
635 | return status; | ||
636 | qp->cdsc_audiostatus = audio_status; | ||
637 | |||
638 | status = exec_cmd(COMSUBQ); | ||
639 | if (status < 0) | ||
640 | return status; | ||
641 | |||
642 | d1 = get_data(0); | ||
643 | if (d1 < 0) | ||
644 | return d1; | ||
645 | qp->cdsc_adr = d1; | ||
646 | qp->cdsc_ctrl = d1 >> 4; | ||
647 | |||
648 | d2 = get_data(0); | ||
649 | if (d2 < 0) | ||
650 | return d2; | ||
651 | qp->cdsc_trk = bcd2bin(d2); | ||
652 | |||
653 | d3 = get_data(0); | ||
654 | if (d3 < 0) | ||
655 | return d3; | ||
656 | qp->cdsc_ind = bcd2bin(d3); | ||
657 | |||
658 | d4 = get_data(0); | ||
659 | if (d4 < 0) | ||
660 | return d4; | ||
661 | qp->cdsc_reladdr.msf.minute = d4; | ||
662 | |||
663 | d5 = get_data(0); | ||
664 | if (d5 < 0) | ||
665 | return d5; | ||
666 | qp->cdsc_reladdr.msf.second = d5; | ||
667 | |||
668 | d6 = get_data(0); | ||
669 | if (d6 < 0) | ||
670 | return d6; | ||
671 | qp->cdsc_reladdr.msf.frame = d6; | ||
672 | |||
673 | d7 = get_data(0); | ||
674 | if (d7 < 0) | ||
675 | return d7; | ||
676 | /* byte not used */ | ||
677 | |||
678 | d8 = get_data(0); | ||
679 | if (d8 < 0) | ||
680 | return d8; | ||
681 | qp->cdsc_absaddr.msf.minute = d8; | ||
682 | |||
683 | d9 = get_data(0); | ||
684 | if (d9 < 0) | ||
685 | return d9; | ||
686 | qp->cdsc_absaddr.msf.second = d9; | ||
687 | |||
688 | d10 = get_data(0); | ||
689 | if (d10 < 0) | ||
690 | return d10; | ||
691 | qp->cdsc_absaddr.msf.frame = d10; | ||
692 | |||
693 | DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", | ||
694 | d1, d2, d3, d4, d5, d6, d7, d8, d9, d10)); | ||
695 | |||
696 | msf_bcd2bin(&qp->cdsc_absaddr); | ||
697 | msf_bcd2bin(&qp->cdsc_reladdr); | ||
698 | if (qp->cdsc_format == CDROM_LBA) { | ||
699 | msf2lba(&qp->cdsc_absaddr); | ||
700 | msf2lba(&qp->cdsc_reladdr); | ||
701 | } | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | /* Table of contents handling */ | ||
707 | |||
708 | |||
709 | /* Errors in table of contents */ | ||
710 | #define ERR_TOC_MISSINGINFO 0x120 | ||
711 | #define ERR_TOC_MISSINGENTRY 0x121 | ||
712 | |||
713 | |||
714 | struct cdrom_disk_info { | ||
715 | unsigned char first; | ||
716 | unsigned char last; | ||
717 | struct cdrom_msf0 disk_length; | ||
718 | struct cdrom_msf0 first_track; | ||
719 | /* Multisession info: */ | ||
720 | unsigned char next; | ||
721 | struct cdrom_msf0 next_session; | ||
722 | struct cdrom_msf0 last_session; | ||
723 | unsigned char multi; | ||
724 | unsigned char xa; | ||
725 | unsigned char audio; | ||
726 | }; | ||
727 | static struct cdrom_disk_info disk_info; | ||
728 | |||
729 | #define MAX_TRACKS 111 | ||
730 | static struct cdrom_subchnl toc[MAX_TRACKS]; | ||
731 | |||
732 | #define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */ | ||
733 | #define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */ | ||
734 | #define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */ | ||
735 | #define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */ | ||
736 | |||
737 | #define I_FIRSTTRACK 0x01 | ||
738 | #define I_LASTTRACK 0x02 | ||
739 | #define I_DISKLENGTH 0x04 | ||
740 | #define I_NEXTSESSION 0x08 | ||
741 | #define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH) | ||
742 | |||
743 | |||
744 | #if DEBUG_TOC | ||
745 | static void toc_debug_info(int i) | ||
746 | { | ||
747 | printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d" | ||
748 | " %2d:%02d.%02d %2d:%02d.%02d\n", | ||
749 | i, toc[i].cdsc_ctrl, toc[i].cdsc_adr, | ||
750 | toc[i].cdsc_trk, toc[i].cdsc_ind, | ||
751 | toc[i].cdsc_reladdr.msf.minute, | ||
752 | toc[i].cdsc_reladdr.msf.second, | ||
753 | toc[i].cdsc_reladdr.msf.frame, | ||
754 | toc[i].cdsc_absaddr.msf.minute, | ||
755 | toc[i].cdsc_absaddr.msf.second, | ||
756 | toc[i].cdsc_absaddr.msf.frame); | ||
757 | } | ||
758 | #endif | ||
759 | |||
760 | |||
761 | static int read_toc(void) | ||
762 | { | ||
763 | int status, limit, count; | ||
764 | unsigned char got_info = 0; | ||
765 | struct cdrom_subchnl q_info; | ||
766 | #if DEBUG_TOC | ||
767 | int i; | ||
768 | #endif | ||
769 | |||
770 | DEBUG((DEBUG_TOC, "starting read_toc")); | ||
771 | |||
772 | count = 0; | ||
773 | for (limit = 60; limit > 0; limit--) { | ||
774 | int index; | ||
775 | |||
776 | q_info.cdsc_format = CDROM_MSF; | ||
777 | status = get_q_channel(&q_info); | ||
778 | if (status < 0) | ||
779 | return status; | ||
780 | |||
781 | index = q_info.cdsc_ind; | ||
782 | if (index > 0 && index < MAX_TRACKS | ||
783 | && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) { | ||
784 | toc[index] = q_info; | ||
785 | DEBUG((DEBUG_TOC, "got %d", index)); | ||
786 | if (index < 100) | ||
787 | count++; | ||
788 | |||
789 | switch (q_info.cdsc_ind) { | ||
790 | case QINFO_FIRSTTRACK: | ||
791 | got_info |= I_FIRSTTRACK; | ||
792 | break; | ||
793 | case QINFO_LASTTRACK: | ||
794 | got_info |= I_LASTTRACK; | ||
795 | break; | ||
796 | case QINFO_DISKLENGTH: | ||
797 | got_info |= I_DISKLENGTH; | ||
798 | break; | ||
799 | case QINFO_NEXTSESSION: | ||
800 | got_info |= I_NEXTSESSION; | ||
801 | break; | ||
802 | } | ||
803 | } | ||
804 | |||
805 | if ((got_info & I_ALL) == I_ALL | ||
806 | && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count | ||
807 | >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | /* Construct disk_info from TOC */ | ||
812 | if (disk_info.first == 0) { | ||
813 | disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; | ||
814 | disk_info.first_track.minute = | ||
815 | toc[disk_info.first].cdsc_absaddr.msf.minute; | ||
816 | disk_info.first_track.second = | ||
817 | toc[disk_info.first].cdsc_absaddr.msf.second; | ||
818 | disk_info.first_track.frame = | ||
819 | toc[disk_info.first].cdsc_absaddr.msf.frame; | ||
820 | } | ||
821 | disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute; | ||
822 | disk_info.disk_length.minute = | ||
823 | toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute; | ||
824 | disk_info.disk_length.second = | ||
825 | toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2; | ||
826 | disk_info.disk_length.frame = | ||
827 | toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame; | ||
828 | disk_info.next_session.minute = | ||
829 | toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute; | ||
830 | disk_info.next_session.second = | ||
831 | toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second; | ||
832 | disk_info.next_session.frame = | ||
833 | toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame; | ||
834 | disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; | ||
835 | disk_info.last_session.minute = | ||
836 | toc[disk_info.next].cdsc_absaddr.msf.minute; | ||
837 | disk_info.last_session.second = | ||
838 | toc[disk_info.next].cdsc_absaddr.msf.second; | ||
839 | disk_info.last_session.frame = | ||
840 | toc[disk_info.next].cdsc_absaddr.msf.frame; | ||
841 | toc[disk_info.last + 1].cdsc_absaddr.msf.minute = | ||
842 | disk_info.disk_length.minute; | ||
843 | toc[disk_info.last + 1].cdsc_absaddr.msf.second = | ||
844 | disk_info.disk_length.second; | ||
845 | toc[disk_info.last + 1].cdsc_absaddr.msf.frame = | ||
846 | disk_info.disk_length.frame; | ||
847 | #if DEBUG_TOC | ||
848 | for (i = 1; i <= disk_info.last + 1; i++) | ||
849 | toc_debug_info(i); | ||
850 | toc_debug_info(QINFO_FIRSTTRACK); | ||
851 | toc_debug_info(QINFO_LASTTRACK); | ||
852 | toc_debug_info(QINFO_DISKLENGTH); | ||
853 | toc_debug_info(QINFO_NEXTSESSION); | ||
854 | #endif | ||
855 | |||
856 | DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d", | ||
857 | got_info, count)); | ||
858 | if ((got_info & I_ALL) != I_ALL | ||
859 | || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count | ||
860 | < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) | ||
861 | return -ERR_TOC_MISSINGINFO; | ||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | |||
866 | #ifdef MULTISESSION | ||
867 | static int get_multi_disk_info(void) | ||
868 | { | ||
869 | int sessions, status; | ||
870 | struct cdrom_msf multi_index; | ||
871 | |||
872 | |||
873 | for (sessions = 2; sessions < 10 /* %%for now */; sessions++) { | ||
874 | int count; | ||
875 | |||
876 | for (count = 100; count < MAX_TRACKS; count++) | ||
877 | toc[count].cdsc_ind = 0; | ||
878 | |||
879 | multi_index.cdmsf_min0 = disk_info.next_session.minute; | ||
880 | multi_index.cdmsf_sec0 = disk_info.next_session.second; | ||
881 | multi_index.cdmsf_frame0 = disk_info.next_session.frame; | ||
882 | if (multi_index.cdmsf_sec0 >= 20) | ||
883 | multi_index.cdmsf_sec0 -= 20; | ||
884 | else { | ||
885 | multi_index.cdmsf_sec0 += 40; | ||
886 | multi_index.cdmsf_min0--; | ||
887 | } | ||
888 | DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions, | ||
889 | multi_index.cdmsf_min0, | ||
890 | multi_index.cdmsf_sec0, | ||
891 | multi_index.cdmsf_frame0)); | ||
892 | bin2bcd(&multi_index); | ||
893 | multi_index.cdmsf_min1 = 0; | ||
894 | multi_index.cdmsf_sec1 = 0; | ||
895 | multi_index.cdmsf_frame1 = 1; | ||
896 | |||
897 | status = exec_read_cmd(COMREAD, &multi_index); | ||
898 | if (status < 0) { | ||
899 | DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x", | ||
900 | -status)); | ||
901 | break; | ||
902 | } | ||
903 | status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ? | ||
904 | 0 : -ERR_TOC_MISSINGINFO; | ||
905 | flush_data(); | ||
906 | if (status < 0) { | ||
907 | DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status)); | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | status = read_toc(); | ||
912 | if (status < 0) { | ||
913 | DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | disk_info.multi = 1; | ||
918 | } | ||
919 | |||
920 | exec_cmd(COMSTOP); | ||
921 | |||
922 | if (status < 0) | ||
923 | return -EIO; | ||
924 | return 0; | ||
925 | } | ||
926 | #endif /* MULTISESSION */ | ||
927 | |||
928 | |||
929 | static int update_toc(void) | ||
930 | { | ||
931 | int status, count; | ||
932 | |||
933 | if (toc_uptodate) | ||
934 | return 0; | ||
935 | |||
936 | DEBUG((DEBUG_TOC, "starting update_toc")); | ||
937 | |||
938 | disk_info.first = 0; | ||
939 | for (count = 0; count < MAX_TRACKS; count++) | ||
940 | toc[count].cdsc_ind = 0; | ||
941 | |||
942 | status = exec_cmd(COMLEADIN); | ||
943 | if (status < 0) | ||
944 | return -EIO; | ||
945 | |||
946 | status = read_toc(); | ||
947 | if (status < 0) { | ||
948 | DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); | ||
949 | return -EIO; | ||
950 | } | ||
951 | |||
952 | /* Audio disk detection. Look at first track. */ | ||
953 | disk_info.audio = | ||
954 | (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1; | ||
955 | |||
956 | /* XA detection */ | ||
957 | disk_info.xa = drive_status() & ST_MODE2TRACK; | ||
958 | |||
959 | /* Multisession detection: if we want this, define MULTISESSION */ | ||
960 | disk_info.multi = 0; | ||
961 | #ifdef MULTISESSION | ||
962 | if (disk_info.xa) | ||
963 | get_multi_disk_info(); /* Here disk_info.multi is set */ | ||
964 | #endif /* MULTISESSION */ | ||
965 | if (disk_info.multi) | ||
966 | printk(KERN_WARNING "optcd: Multisession support experimental, " | ||
967 | "see Documentation/cdrom/optcd\n"); | ||
968 | |||
969 | DEBUG((DEBUG_TOC, "exiting update_toc")); | ||
970 | |||
971 | toc_uptodate = 1; | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | /* Request handling */ | ||
976 | |||
977 | static int current_valid(void) | ||
978 | { | ||
979 | return CURRENT && | ||
980 | CURRENT->cmd == READ && | ||
981 | CURRENT->sector != -1; | ||
982 | } | ||
983 | |||
984 | /* Buffers for block size conversion. */ | ||
985 | #define NOBUF -1 | ||
986 | |||
987 | static char buf[CD_FRAMESIZE * N_BUFS]; | ||
988 | static volatile int buf_bn[N_BUFS], next_bn; | ||
989 | static volatile int buf_in = 0, buf_out = NOBUF; | ||
990 | |||
991 | inline static void opt_invalidate_buffers(void) | ||
992 | { | ||
993 | int i; | ||
994 | |||
995 | DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers")); | ||
996 | |||
997 | for (i = 0; i < N_BUFS; i++) | ||
998 | buf_bn[i] = NOBUF; | ||
999 | buf_out = NOBUF; | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | /* Take care of the different block sizes between cdrom and Linux. | ||
1004 | When Linux gets variable block sizes this will probably go away. */ | ||
1005 | static void transfer(void) | ||
1006 | { | ||
1007 | #if DEBUG_BUFFERS | DEBUG_REQUEST | ||
1008 | printk(KERN_DEBUG "optcd: executing transfer\n"); | ||
1009 | #endif | ||
1010 | |||
1011 | if (!current_valid()) | ||
1012 | return; | ||
1013 | while (CURRENT -> nr_sectors) { | ||
1014 | int bn = CURRENT -> sector / 4; | ||
1015 | int i, offs, nr_sectors; | ||
1016 | for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i); | ||
1017 | |||
1018 | DEBUG((DEBUG_REQUEST, "found %d", i)); | ||
1019 | |||
1020 | if (i >= N_BUFS) { | ||
1021 | buf_out = NOBUF; | ||
1022 | break; | ||
1023 | } | ||
1024 | |||
1025 | offs = (i * 4 + (CURRENT -> sector & 3)) * 512; | ||
1026 | nr_sectors = 4 - (CURRENT -> sector & 3); | ||
1027 | |||
1028 | if (buf_out != i) { | ||
1029 | buf_out = i; | ||
1030 | if (buf_bn[i] != bn) { | ||
1031 | buf_out = NOBUF; | ||
1032 | continue; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | if (nr_sectors > CURRENT -> nr_sectors) | ||
1037 | nr_sectors = CURRENT -> nr_sectors; | ||
1038 | memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512); | ||
1039 | CURRENT -> nr_sectors -= nr_sectors; | ||
1040 | CURRENT -> sector += nr_sectors; | ||
1041 | CURRENT -> buffer += nr_sectors * 512; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | /* State machine for reading disk blocks */ | ||
1047 | |||
1048 | enum state_e { | ||
1049 | S_IDLE, /* 0 */ | ||
1050 | S_START, /* 1 */ | ||
1051 | S_READ, /* 2 */ | ||
1052 | S_DATA, /* 3 */ | ||
1053 | S_STOP, /* 4 */ | ||
1054 | S_STOPPING /* 5 */ | ||
1055 | }; | ||
1056 | |||
1057 | static volatile enum state_e state = S_IDLE; | ||
1058 | #if DEBUG_STATE | ||
1059 | static volatile enum state_e state_old = S_STOP; | ||
1060 | static volatile int flags_old = 0; | ||
1061 | static volatile long state_n = 0; | ||
1062 | #endif | ||
1063 | |||
1064 | |||
1065 | /* Used as mutex to keep do_optcd_request (and other processes calling | ||
1066 | ioctl) out while some process is inside a VFS call. | ||
1067 | Reverse is accomplished by checking if state = S_IDLE upon entry | ||
1068 | of opt_ioctl and opt_media_change. */ | ||
1069 | static int in_vfs = 0; | ||
1070 | |||
1071 | |||
1072 | static volatile int transfer_is_active = 0; | ||
1073 | static volatile int error = 0; /* %% do something with this?? */ | ||
1074 | static int tries; /* ibid?? */ | ||
1075 | static int timeout = 0; | ||
1076 | |||
1077 | static void poll(unsigned long data); | ||
1078 | static struct timer_list req_timer = {.function = poll}; | ||
1079 | |||
1080 | |||
1081 | static void poll(unsigned long data) | ||
1082 | { | ||
1083 | static volatile int read_count = 1; | ||
1084 | int flags; | ||
1085 | int loop_again = 1; | ||
1086 | int status = 0; | ||
1087 | int skip = 0; | ||
1088 | |||
1089 | if (error) { | ||
1090 | printk(KERN_ERR "optcd: I/O error 0x%02x\n", error); | ||
1091 | opt_invalidate_buffers(); | ||
1092 | if (!tries--) { | ||
1093 | printk(KERN_ERR "optcd: read block %d failed;" | ||
1094 | " Giving up\n", next_bn); | ||
1095 | if (transfer_is_active) | ||
1096 | loop_again = 0; | ||
1097 | if (current_valid()) | ||
1098 | end_request(CURRENT, 0); | ||
1099 | tries = 5; | ||
1100 | } | ||
1101 | error = 0; | ||
1102 | state = S_STOP; | ||
1103 | } | ||
1104 | |||
1105 | while (loop_again) | ||
1106 | { | ||
1107 | loop_again = 0; /* each case must flip this back to 1 if we want | ||
1108 | to come back up here */ | ||
1109 | |||
1110 | #if DEBUG_STATE | ||
1111 | if (state == state_old) | ||
1112 | state_n++; | ||
1113 | else { | ||
1114 | state_old = state; | ||
1115 | if (++state_n > 1) | ||
1116 | printk(KERN_DEBUG "optcd: %ld times " | ||
1117 | "in previous state\n", state_n); | ||
1118 | printk(KERN_DEBUG "optcd: state %d\n", state); | ||
1119 | state_n = 0; | ||
1120 | } | ||
1121 | #endif | ||
1122 | |||
1123 | switch (state) { | ||
1124 | case S_IDLE: | ||
1125 | return; | ||
1126 | case S_START: | ||
1127 | if (in_vfs) | ||
1128 | break; | ||
1129 | if (send_cmd(COMDRVST)) { | ||
1130 | state = S_IDLE; | ||
1131 | while (current_valid()) | ||
1132 | end_request(CURRENT, 0); | ||
1133 | return; | ||
1134 | } | ||
1135 | state = S_READ; | ||
1136 | timeout = READ_TIMEOUT; | ||
1137 | break; | ||
1138 | case S_READ: { | ||
1139 | struct cdrom_msf msf; | ||
1140 | if (!skip) { | ||
1141 | status = fetch_status(); | ||
1142 | if (status < 0) | ||
1143 | break; | ||
1144 | if (status & ST_DSK_CHG) { | ||
1145 | toc_uptodate = 0; | ||
1146 | opt_invalidate_buffers(); | ||
1147 | } | ||
1148 | } | ||
1149 | skip = 0; | ||
1150 | if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { | ||
1151 | toc_uptodate = 0; | ||
1152 | opt_invalidate_buffers(); | ||
1153 | printk(KERN_WARNING "optcd: %s\n", | ||
1154 | (status & ST_DOOR_OPEN) | ||
1155 | ? "door open" | ||
1156 | : "disk removed"); | ||
1157 | state = S_IDLE; | ||
1158 | while (current_valid()) | ||
1159 | end_request(CURRENT, 0); | ||
1160 | return; | ||
1161 | } | ||
1162 | if (!current_valid()) { | ||
1163 | state = S_STOP; | ||
1164 | loop_again = 1; | ||
1165 | break; | ||
1166 | } | ||
1167 | next_bn = CURRENT -> sector / 4; | ||
1168 | lba2msf(next_bn, &msf); | ||
1169 | read_count = N_BUFS; | ||
1170 | msf.cdmsf_frame1 = read_count; /* Not BCD! */ | ||
1171 | |||
1172 | DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x", | ||
1173 | msf.cdmsf_min0, | ||
1174 | msf.cdmsf_sec0, | ||
1175 | msf.cdmsf_frame0, | ||
1176 | msf.cdmsf_min1, | ||
1177 | msf.cdmsf_sec1, | ||
1178 | msf.cdmsf_frame1)); | ||
1179 | DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d" | ||
1180 | " buf_out:%d buf_bn:%d", | ||
1181 | next_bn, | ||
1182 | buf_in, | ||
1183 | buf_out, | ||
1184 | buf_bn[buf_in])); | ||
1185 | |||
1186 | exec_read_cmd(COMREAD, &msf); | ||
1187 | state = S_DATA; | ||
1188 | timeout = READ_TIMEOUT; | ||
1189 | break; | ||
1190 | } | ||
1191 | case S_DATA: | ||
1192 | flags = stdt_flags() & (FL_STEN|FL_DTEN); | ||
1193 | |||
1194 | #if DEBUG_STATE | ||
1195 | if (flags != flags_old) { | ||
1196 | flags_old = flags; | ||
1197 | printk(KERN_DEBUG "optcd: flags:%x\n", flags); | ||
1198 | } | ||
1199 | if (flags == FL_STEN) | ||
1200 | printk(KERN_DEBUG "timeout cnt: %d\n", timeout); | ||
1201 | #endif | ||
1202 | |||
1203 | switch (flags) { | ||
1204 | case FL_DTEN: /* only STEN low */ | ||
1205 | if (!tries--) { | ||
1206 | printk(KERN_ERR | ||
1207 | "optcd: read block %d failed; " | ||
1208 | "Giving up\n", next_bn); | ||
1209 | if (transfer_is_active) { | ||
1210 | tries = 0; | ||
1211 | break; | ||
1212 | } | ||
1213 | if (current_valid()) | ||
1214 | end_request(CURRENT, 0); | ||
1215 | tries = 5; | ||
1216 | } | ||
1217 | state = S_START; | ||
1218 | timeout = READ_TIMEOUT; | ||
1219 | loop_again = 1; | ||
1220 | case (FL_STEN|FL_DTEN): /* both high */ | ||
1221 | break; | ||
1222 | default: /* DTEN low */ | ||
1223 | tries = 5; | ||
1224 | if (!current_valid() && buf_in == buf_out) { | ||
1225 | state = S_STOP; | ||
1226 | loop_again = 1; | ||
1227 | break; | ||
1228 | } | ||
1229 | if (read_count<=0) | ||
1230 | printk(KERN_WARNING | ||
1231 | "optcd: warning - try to read" | ||
1232 | " 0 frames\n"); | ||
1233 | while (read_count) { | ||
1234 | buf_bn[buf_in] = NOBUF; | ||
1235 | if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) { | ||
1236 | /* should be no waiting here!?? */ | ||
1237 | printk(KERN_ERR | ||
1238 | "read_count:%d " | ||
1239 | "CURRENT->nr_sectors:%ld " | ||
1240 | "buf_in:%d\n", | ||
1241 | read_count, | ||
1242 | CURRENT->nr_sectors, | ||
1243 | buf_in); | ||
1244 | printk(KERN_ERR | ||
1245 | "transfer active: %x\n", | ||
1246 | transfer_is_active); | ||
1247 | read_count = 0; | ||
1248 | state = S_STOP; | ||
1249 | loop_again = 1; | ||
1250 | end_request(CURRENT, 0); | ||
1251 | break; | ||
1252 | } | ||
1253 | fetch_data(buf+ | ||
1254 | CD_FRAMESIZE*buf_in, | ||
1255 | CD_FRAMESIZE); | ||
1256 | read_count--; | ||
1257 | |||
1258 | DEBUG((DEBUG_REQUEST, | ||
1259 | "S_DATA; ---I've read data- " | ||
1260 | "read_count: %d", | ||
1261 | read_count)); | ||
1262 | DEBUG((DEBUG_REQUEST, | ||
1263 | "next_bn:%d buf_in:%d " | ||
1264 | "buf_out:%d buf_bn:%d", | ||
1265 | next_bn, | ||
1266 | buf_in, | ||
1267 | buf_out, | ||
1268 | buf_bn[buf_in])); | ||
1269 | |||
1270 | buf_bn[buf_in] = next_bn++; | ||
1271 | if (buf_out == NOBUF) | ||
1272 | buf_out = buf_in; | ||
1273 | buf_in = buf_in + 1 == | ||
1274 | N_BUFS ? 0 : buf_in + 1; | ||
1275 | } | ||
1276 | if (!transfer_is_active) { | ||
1277 | while (current_valid()) { | ||
1278 | transfer(); | ||
1279 | if (CURRENT -> nr_sectors == 0) | ||
1280 | end_request(CURRENT, 1); | ||
1281 | else | ||
1282 | break; | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | if (current_valid() | ||
1287 | && (CURRENT -> sector / 4 < next_bn || | ||
1288 | CURRENT -> sector / 4 > | ||
1289 | next_bn + N_BUFS)) { | ||
1290 | state = S_STOP; | ||
1291 | loop_again = 1; | ||
1292 | break; | ||
1293 | } | ||
1294 | timeout = READ_TIMEOUT; | ||
1295 | if (read_count == 0) { | ||
1296 | state = S_STOP; | ||
1297 | loop_again = 1; | ||
1298 | break; | ||
1299 | } | ||
1300 | } | ||
1301 | break; | ||
1302 | case S_STOP: | ||
1303 | if (read_count != 0) | ||
1304 | printk(KERN_ERR | ||
1305 | "optcd: discard data=%x frames\n", | ||
1306 | read_count); | ||
1307 | flush_data(); | ||
1308 | if (send_cmd(COMDRVST)) { | ||
1309 | state = S_IDLE; | ||
1310 | while (current_valid()) | ||
1311 | end_request(CURRENT, 0); | ||
1312 | return; | ||
1313 | } | ||
1314 | state = S_STOPPING; | ||
1315 | timeout = STOP_TIMEOUT; | ||
1316 | break; | ||
1317 | case S_STOPPING: | ||
1318 | status = fetch_status(); | ||
1319 | if (status < 0 && timeout) | ||
1320 | break; | ||
1321 | if ((status >= 0) && (status & ST_DSK_CHG)) { | ||
1322 | toc_uptodate = 0; | ||
1323 | opt_invalidate_buffers(); | ||
1324 | } | ||
1325 | if (current_valid()) { | ||
1326 | if (status >= 0) { | ||
1327 | state = S_READ; | ||
1328 | loop_again = 1; | ||
1329 | skip = 1; | ||
1330 | break; | ||
1331 | } else { | ||
1332 | state = S_START; | ||
1333 | timeout = 1; | ||
1334 | } | ||
1335 | } else { | ||
1336 | state = S_IDLE; | ||
1337 | return; | ||
1338 | } | ||
1339 | break; | ||
1340 | default: | ||
1341 | printk(KERN_ERR "optcd: invalid state %d\n", state); | ||
1342 | return; | ||
1343 | } /* case */ | ||
1344 | } /* while */ | ||
1345 | |||
1346 | if (!timeout--) { | ||
1347 | printk(KERN_ERR "optcd: timeout in state %d\n", state); | ||
1348 | state = S_STOP; | ||
1349 | if (exec_cmd(COMSTOP) < 0) { | ||
1350 | state = S_IDLE; | ||
1351 | while (current_valid()) | ||
1352 | end_request(CURRENT, 0); | ||
1353 | return; | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | mod_timer(&req_timer, jiffies + HZ/100); | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | static void do_optcd_request(request_queue_t * q) | ||
1362 | { | ||
1363 | DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)", | ||
1364 | CURRENT -> sector, CURRENT -> nr_sectors)); | ||
1365 | |||
1366 | if (disk_info.audio) { | ||
1367 | printk(KERN_WARNING "optcd: tried to mount an Audio CD\n"); | ||
1368 | end_request(CURRENT, 0); | ||
1369 | return; | ||
1370 | } | ||
1371 | |||
1372 | transfer_is_active = 1; | ||
1373 | while (current_valid()) { | ||
1374 | transfer(); /* First try to transfer block from buffers */ | ||
1375 | if (CURRENT -> nr_sectors == 0) { | ||
1376 | end_request(CURRENT, 1); | ||
1377 | } else { /* Want to read a block not in buffer */ | ||
1378 | buf_out = NOBUF; | ||
1379 | if (state == S_IDLE) { | ||
1380 | /* %% Should this block the request queue?? */ | ||
1381 | if (update_toc() < 0) { | ||
1382 | while (current_valid()) | ||
1383 | end_request(CURRENT, 0); | ||
1384 | break; | ||
1385 | } | ||
1386 | /* Start state machine */ | ||
1387 | state = S_START; | ||
1388 | timeout = READ_TIMEOUT; | ||
1389 | tries = 5; | ||
1390 | /* %% why not start right away?? */ | ||
1391 | mod_timer(&req_timer, jiffies + HZ/100); | ||
1392 | } | ||
1393 | break; | ||
1394 | } | ||
1395 | } | ||
1396 | transfer_is_active = 0; | ||
1397 | |||
1398 | DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d", | ||
1399 | next_bn, buf_in, buf_out, buf_bn[buf_in])); | ||
1400 | DEBUG((DEBUG_REQUEST, "do_optcd_request ends")); | ||
1401 | } | ||
1402 | |||
1403 | /* IOCTLs */ | ||
1404 | |||
1405 | |||
1406 | static char auto_eject = 0; | ||
1407 | |||
1408 | static int cdrompause(void) | ||
1409 | { | ||
1410 | int status; | ||
1411 | |||
1412 | if (audio_status != CDROM_AUDIO_PLAY) | ||
1413 | return -EINVAL; | ||
1414 | |||
1415 | status = exec_cmd(COMPAUSEON); | ||
1416 | if (status < 0) { | ||
1417 | DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status)); | ||
1418 | return -EIO; | ||
1419 | } | ||
1420 | audio_status = CDROM_AUDIO_PAUSED; | ||
1421 | return 0; | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | static int cdromresume(void) | ||
1426 | { | ||
1427 | int status; | ||
1428 | |||
1429 | if (audio_status != CDROM_AUDIO_PAUSED) | ||
1430 | return -EINVAL; | ||
1431 | |||
1432 | status = exec_cmd(COMPAUSEOFF); | ||
1433 | if (status < 0) { | ||
1434 | DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status)); | ||
1435 | audio_status = CDROM_AUDIO_ERROR; | ||
1436 | return -EIO; | ||
1437 | } | ||
1438 | audio_status = CDROM_AUDIO_PLAY; | ||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1442 | |||
1443 | static int cdromplaymsf(void __user *arg) | ||
1444 | { | ||
1445 | int status; | ||
1446 | struct cdrom_msf msf; | ||
1447 | |||
1448 | if (copy_from_user(&msf, arg, sizeof msf)) | ||
1449 | return -EFAULT; | ||
1450 | |||
1451 | bin2bcd(&msf); | ||
1452 | status = exec_long_cmd(COMPLAY, &msf); | ||
1453 | if (status < 0) { | ||
1454 | DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); | ||
1455 | audio_status = CDROM_AUDIO_ERROR; | ||
1456 | return -EIO; | ||
1457 | } | ||
1458 | |||
1459 | audio_status = CDROM_AUDIO_PLAY; | ||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | |||
1464 | static int cdromplaytrkind(void __user *arg) | ||
1465 | { | ||
1466 | int status; | ||
1467 | struct cdrom_ti ti; | ||
1468 | struct cdrom_msf msf; | ||
1469 | |||
1470 | if (copy_from_user(&ti, arg, sizeof ti)) | ||
1471 | return -EFAULT; | ||
1472 | |||
1473 | if (ti.cdti_trk0 < disk_info.first | ||
1474 | || ti.cdti_trk0 > disk_info.last | ||
1475 | || ti.cdti_trk1 < ti.cdti_trk0) | ||
1476 | return -EINVAL; | ||
1477 | if (ti.cdti_trk1 > disk_info.last) | ||
1478 | ti.cdti_trk1 = disk_info.last; | ||
1479 | |||
1480 | msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute; | ||
1481 | msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second; | ||
1482 | msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame; | ||
1483 | msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute; | ||
1484 | msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second; | ||
1485 | msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame; | ||
1486 | |||
1487 | DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d", | ||
1488 | msf.cdmsf_min0, | ||
1489 | msf.cdmsf_sec0, | ||
1490 | msf.cdmsf_frame0, | ||
1491 | msf.cdmsf_min1, | ||
1492 | msf.cdmsf_sec1, | ||
1493 | msf.cdmsf_frame1)); | ||
1494 | |||
1495 | bin2bcd(&msf); | ||
1496 | status = exec_long_cmd(COMPLAY, &msf); | ||
1497 | if (status < 0) { | ||
1498 | DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); | ||
1499 | audio_status = CDROM_AUDIO_ERROR; | ||
1500 | return -EIO; | ||
1501 | } | ||
1502 | |||
1503 | audio_status = CDROM_AUDIO_PLAY; | ||
1504 | return 0; | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | static int cdromreadtochdr(void __user *arg) | ||
1509 | { | ||
1510 | struct cdrom_tochdr tochdr; | ||
1511 | |||
1512 | tochdr.cdth_trk0 = disk_info.first; | ||
1513 | tochdr.cdth_trk1 = disk_info.last; | ||
1514 | |||
1515 | return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0; | ||
1516 | } | ||
1517 | |||
1518 | |||
1519 | static int cdromreadtocentry(void __user *arg) | ||
1520 | { | ||
1521 | struct cdrom_tocentry entry; | ||
1522 | struct cdrom_subchnl *tocptr; | ||
1523 | |||
1524 | if (copy_from_user(&entry, arg, sizeof entry)) | ||
1525 | return -EFAULT; | ||
1526 | |||
1527 | if (entry.cdte_track == CDROM_LEADOUT) | ||
1528 | tocptr = &toc[disk_info.last + 1]; | ||
1529 | else if (entry.cdte_track > disk_info.last | ||
1530 | || entry.cdte_track < disk_info.first) | ||
1531 | return -EINVAL; | ||
1532 | else | ||
1533 | tocptr = &toc[entry.cdte_track]; | ||
1534 | |||
1535 | entry.cdte_adr = tocptr->cdsc_adr; | ||
1536 | entry.cdte_ctrl = tocptr->cdsc_ctrl; | ||
1537 | entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute; | ||
1538 | entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second; | ||
1539 | entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame; | ||
1540 | /* %% What should go into entry.cdte_datamode? */ | ||
1541 | |||
1542 | if (entry.cdte_format == CDROM_LBA) | ||
1543 | msf2lba(&entry.cdte_addr); | ||
1544 | else if (entry.cdte_format != CDROM_MSF) | ||
1545 | return -EINVAL; | ||
1546 | |||
1547 | return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0; | ||
1548 | } | ||
1549 | |||
1550 | |||
1551 | static int cdromvolctrl(void __user *arg) | ||
1552 | { | ||
1553 | int status; | ||
1554 | struct cdrom_volctrl volctrl; | ||
1555 | struct cdrom_msf msf; | ||
1556 | |||
1557 | if (copy_from_user(&volctrl, arg, sizeof volctrl)) | ||
1558 | return -EFAULT; | ||
1559 | |||
1560 | msf.cdmsf_min0 = 0x10; | ||
1561 | msf.cdmsf_sec0 = 0x32; | ||
1562 | msf.cdmsf_frame0 = volctrl.channel0; | ||
1563 | msf.cdmsf_min1 = volctrl.channel1; | ||
1564 | msf.cdmsf_sec1 = volctrl.channel2; | ||
1565 | msf.cdmsf_frame1 = volctrl.channel3; | ||
1566 | |||
1567 | status = exec_long_cmd(COMCHCTRL, &msf); | ||
1568 | if (status < 0) { | ||
1569 | DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status)); | ||
1570 | return -EIO; | ||
1571 | } | ||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1575 | |||
1576 | static int cdromsubchnl(void __user *arg) | ||
1577 | { | ||
1578 | int status; | ||
1579 | struct cdrom_subchnl subchnl; | ||
1580 | |||
1581 | if (copy_from_user(&subchnl, arg, sizeof subchnl)) | ||
1582 | return -EFAULT; | ||
1583 | |||
1584 | if (subchnl.cdsc_format != CDROM_LBA | ||
1585 | && subchnl.cdsc_format != CDROM_MSF) | ||
1586 | return -EINVAL; | ||
1587 | |||
1588 | status = get_q_channel(&subchnl); | ||
1589 | if (status < 0) { | ||
1590 | DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status)); | ||
1591 | return -EIO; | ||
1592 | } | ||
1593 | |||
1594 | if (copy_to_user(arg, &subchnl, sizeof subchnl)) | ||
1595 | return -EFAULT; | ||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | |||
1600 | static struct gendisk *optcd_disk; | ||
1601 | |||
1602 | |||
1603 | static int cdromread(void __user *arg, int blocksize, int cmd) | ||
1604 | { | ||
1605 | int status; | ||
1606 | struct cdrom_msf msf; | ||
1607 | |||
1608 | if (copy_from_user(&msf, arg, sizeof msf)) | ||
1609 | return -EFAULT; | ||
1610 | |||
1611 | bin2bcd(&msf); | ||
1612 | msf.cdmsf_min1 = 0; | ||
1613 | msf.cdmsf_sec1 = 0; | ||
1614 | msf.cdmsf_frame1 = 1; /* read only one frame */ | ||
1615 | status = exec_read_cmd(cmd, &msf); | ||
1616 | |||
1617 | DEBUG((DEBUG_VFS, "read cmd status 0x%x", status)); | ||
1618 | |||
1619 | if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT)) | ||
1620 | return -EIO; | ||
1621 | |||
1622 | fetch_data(optcd_disk->private_data, blocksize); | ||
1623 | |||
1624 | if (copy_to_user(arg, optcd_disk->private_data, blocksize)) | ||
1625 | return -EFAULT; | ||
1626 | |||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | static int cdromseek(void __user *arg) | ||
1632 | { | ||
1633 | int status; | ||
1634 | struct cdrom_msf msf; | ||
1635 | |||
1636 | if (copy_from_user(&msf, arg, sizeof msf)) | ||
1637 | return -EFAULT; | ||
1638 | |||
1639 | bin2bcd(&msf); | ||
1640 | status = exec_seek_cmd(COMSEEK, &msf); | ||
1641 | |||
1642 | DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status)); | ||
1643 | |||
1644 | if (status < 0) | ||
1645 | return -EIO; | ||
1646 | return 0; | ||
1647 | } | ||
1648 | |||
1649 | |||
1650 | #ifdef MULTISESSION | ||
1651 | static int cdrommultisession(void __user *arg) | ||
1652 | { | ||
1653 | struct cdrom_multisession ms; | ||
1654 | |||
1655 | if (copy_from_user(&ms, arg, sizeof ms)) | ||
1656 | return -EFAULT; | ||
1657 | |||
1658 | ms.addr.msf.minute = disk_info.last_session.minute; | ||
1659 | ms.addr.msf.second = disk_info.last_session.second; | ||
1660 | ms.addr.msf.frame = disk_info.last_session.frame; | ||
1661 | |||
1662 | if (ms.addr_format != CDROM_LBA | ||
1663 | && ms.addr_format != CDROM_MSF) | ||
1664 | return -EINVAL; | ||
1665 | if (ms.addr_format == CDROM_LBA) | ||
1666 | msf2lba(&ms.addr); | ||
1667 | |||
1668 | ms.xa_flag = disk_info.xa; | ||
1669 | |||
1670 | if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession))) | ||
1671 | return -EFAULT; | ||
1672 | |||
1673 | #if DEBUG_MULTIS | ||
1674 | if (ms.addr_format == CDROM_MSF) | ||
1675 | printk(KERN_DEBUG | ||
1676 | "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n", | ||
1677 | ms.xa_flag, | ||
1678 | ms.addr.msf.minute, | ||
1679 | ms.addr.msf.second, | ||
1680 | ms.addr.msf.frame); | ||
1681 | else | ||
1682 | printk(KERN_DEBUG | ||
1683 | "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n", | ||
1684 | ms.xa_flag, | ||
1685 | ms.addr.lba, | ||
1686 | disk_info.last_session.minute, | ||
1687 | disk_info.last_session.second, | ||
1688 | disk_info.last_session.frame); | ||
1689 | #endif /* DEBUG_MULTIS */ | ||
1690 | |||
1691 | return 0; | ||
1692 | } | ||
1693 | #endif /* MULTISESSION */ | ||
1694 | |||
1695 | |||
1696 | static int cdromreset(void) | ||
1697 | { | ||
1698 | if (state != S_IDLE) { | ||
1699 | error = 1; | ||
1700 | tries = 0; | ||
1701 | } | ||
1702 | |||
1703 | toc_uptodate = 0; | ||
1704 | disk_changed = 1; | ||
1705 | opt_invalidate_buffers(); | ||
1706 | audio_status = CDROM_AUDIO_NO_STATUS; | ||
1707 | |||
1708 | if (!reset_drive()) | ||
1709 | return -EIO; | ||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1713 | /* VFS calls */ | ||
1714 | |||
1715 | |||
1716 | static int opt_ioctl(struct inode *ip, struct file *fp, | ||
1717 | unsigned int cmd, unsigned long arg) | ||
1718 | { | ||
1719 | int status, err, retval = 0; | ||
1720 | void __user *argp = (void __user *)arg; | ||
1721 | |||
1722 | DEBUG((DEBUG_VFS, "starting opt_ioctl")); | ||
1723 | |||
1724 | if (!ip) | ||
1725 | return -EINVAL; | ||
1726 | |||
1727 | if (cmd == CDROMRESET) | ||
1728 | return cdromreset(); | ||
1729 | |||
1730 | /* is do_optcd_request or another ioctl busy? */ | ||
1731 | if (state != S_IDLE || in_vfs) | ||
1732 | return -EBUSY; | ||
1733 | |||
1734 | in_vfs = 1; | ||
1735 | |||
1736 | status = drive_status(); | ||
1737 | if (status < 0) { | ||
1738 | DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); | ||
1739 | in_vfs = 0; | ||
1740 | return -EIO; | ||
1741 | } | ||
1742 | |||
1743 | if (status & ST_DOOR_OPEN) | ||
1744 | switch (cmd) { /* Actions that can be taken with door open */ | ||
1745 | case CDROMCLOSETRAY: | ||
1746 | /* We do this before trying to read the toc. */ | ||
1747 | err = exec_cmd(COMCLOSE); | ||
1748 | if (err < 0) { | ||
1749 | DEBUG((DEBUG_VFS, | ||
1750 | "exec_cmd COMCLOSE: %02x", -err)); | ||
1751 | in_vfs = 0; | ||
1752 | return -EIO; | ||
1753 | } | ||
1754 | break; | ||
1755 | default: in_vfs = 0; | ||
1756 | return -EBUSY; | ||
1757 | } | ||
1758 | |||
1759 | err = update_toc(); | ||
1760 | if (err < 0) { | ||
1761 | DEBUG((DEBUG_VFS, "update_toc: %02x", -err)); | ||
1762 | in_vfs = 0; | ||
1763 | return -EIO; | ||
1764 | } | ||
1765 | |||
1766 | DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd)); | ||
1767 | |||
1768 | switch (cmd) { | ||
1769 | case CDROMPAUSE: retval = cdrompause(); break; | ||
1770 | case CDROMRESUME: retval = cdromresume(); break; | ||
1771 | case CDROMPLAYMSF: retval = cdromplaymsf(argp); break; | ||
1772 | case CDROMPLAYTRKIND: retval = cdromplaytrkind(argp); break; | ||
1773 | case CDROMREADTOCHDR: retval = cdromreadtochdr(argp); break; | ||
1774 | case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break; | ||
1775 | |||
1776 | case CDROMSTOP: err = exec_cmd(COMSTOP); | ||
1777 | if (err < 0) { | ||
1778 | DEBUG((DEBUG_VFS, | ||
1779 | "exec_cmd COMSTOP: %02x", | ||
1780 | -err)); | ||
1781 | retval = -EIO; | ||
1782 | } else | ||
1783 | audio_status = CDROM_AUDIO_NO_STATUS; | ||
1784 | break; | ||
1785 | case CDROMSTART: break; /* This is a no-op */ | ||
1786 | case CDROMEJECT: err = exec_cmd(COMUNLOCK); | ||
1787 | if (err < 0) { | ||
1788 | DEBUG((DEBUG_VFS, | ||
1789 | "exec_cmd COMUNLOCK: %02x", | ||
1790 | -err)); | ||
1791 | retval = -EIO; | ||
1792 | break; | ||
1793 | } | ||
1794 | err = exec_cmd(COMOPEN); | ||
1795 | if (err < 0) { | ||
1796 | DEBUG((DEBUG_VFS, | ||
1797 | "exec_cmd COMOPEN: %02x", | ||
1798 | -err)); | ||
1799 | retval = -EIO; | ||
1800 | } | ||
1801 | break; | ||
1802 | |||
1803 | case CDROMVOLCTRL: retval = cdromvolctrl(argp); break; | ||
1804 | case CDROMSUBCHNL: retval = cdromsubchnl(argp); break; | ||
1805 | |||
1806 | /* The drive detects the mode and automatically delivers the | ||
1807 | correct 2048 bytes, so we don't need these IOCTLs */ | ||
1808 | case CDROMREADMODE2: retval = -EINVAL; break; | ||
1809 | case CDROMREADMODE1: retval = -EINVAL; break; | ||
1810 | |||
1811 | /* Drive doesn't support reading audio */ | ||
1812 | case CDROMREADAUDIO: retval = -EINVAL; break; | ||
1813 | |||
1814 | case CDROMEJECT_SW: auto_eject = (char) arg; | ||
1815 | break; | ||
1816 | |||
1817 | #ifdef MULTISESSION | ||
1818 | case CDROMMULTISESSION: retval = cdrommultisession(argp); break; | ||
1819 | #endif | ||
1820 | |||
1821 | case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */ | ||
1822 | case CDROMVOLREAD: retval = -EINVAL; break; /* not implemented */ | ||
1823 | |||
1824 | case CDROMREADRAW: | ||
1825 | /* this drive delivers 2340 bytes in raw mode */ | ||
1826 | retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW); | ||
1827 | break; | ||
1828 | case CDROMREADCOOKED: | ||
1829 | retval = cdromread(argp, CD_FRAMESIZE, COMREAD); | ||
1830 | break; | ||
1831 | case CDROMREADALL: | ||
1832 | retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL); | ||
1833 | break; | ||
1834 | |||
1835 | case CDROMSEEK: retval = cdromseek(argp); break; | ||
1836 | case CDROMPLAYBLK: retval = -EINVAL; break; /* not implemented */ | ||
1837 | case CDROMCLOSETRAY: break; /* The action was taken earlier */ | ||
1838 | default: retval = -EINVAL; | ||
1839 | } | ||
1840 | in_vfs = 0; | ||
1841 | return retval; | ||
1842 | } | ||
1843 | |||
1844 | |||
1845 | static int open_count = 0; | ||
1846 | |||
1847 | /* Open device special file; check that a disk is in. */ | ||
1848 | static int opt_open(struct inode *ip, struct file *fp) | ||
1849 | { | ||
1850 | DEBUG((DEBUG_VFS, "starting opt_open")); | ||
1851 | |||
1852 | if (!open_count && state == S_IDLE) { | ||
1853 | int status; | ||
1854 | char *buf; | ||
1855 | |||
1856 | buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL); | ||
1857 | if (!buf) { | ||
1858 | printk(KERN_INFO "optcd: cannot allocate read buffer\n"); | ||
1859 | return -ENOMEM; | ||
1860 | } | ||
1861 | optcd_disk->private_data = buf; /* save read buffer */ | ||
1862 | |||
1863 | toc_uptodate = 0; | ||
1864 | opt_invalidate_buffers(); | ||
1865 | |||
1866 | status = exec_cmd(COMCLOSE); /* close door */ | ||
1867 | if (status < 0) { | ||
1868 | DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status)); | ||
1869 | } | ||
1870 | |||
1871 | status = drive_status(); | ||
1872 | if (status < 0) { | ||
1873 | DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); | ||
1874 | goto err_out; | ||
1875 | } | ||
1876 | DEBUG((DEBUG_VFS, "status: %02x", status)); | ||
1877 | if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { | ||
1878 | printk(KERN_INFO "optcd: no disk or door open\n"); | ||
1879 | goto err_out; | ||
1880 | } | ||
1881 | status = exec_cmd(COMLOCK); /* Lock door */ | ||
1882 | if (status < 0) { | ||
1883 | DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status)); | ||
1884 | } | ||
1885 | status = update_toc(); /* Read table of contents */ | ||
1886 | if (status < 0) { | ||
1887 | DEBUG((DEBUG_VFS, "update_toc: %02x", -status)); | ||
1888 | status = exec_cmd(COMUNLOCK); /* Unlock door */ | ||
1889 | if (status < 0) { | ||
1890 | DEBUG((DEBUG_VFS, | ||
1891 | "exec_cmd COMUNLOCK: %02x", -status)); | ||
1892 | } | ||
1893 | goto err_out; | ||
1894 | } | ||
1895 | open_count++; | ||
1896 | } | ||
1897 | |||
1898 | DEBUG((DEBUG_VFS, "exiting opt_open")); | ||
1899 | |||
1900 | return 0; | ||
1901 | |||
1902 | err_out: | ||
1903 | return -EIO; | ||
1904 | } | ||
1905 | |||
1906 | |||
1907 | /* Release device special file; flush all blocks from the buffer cache */ | ||
1908 | static int opt_release(struct inode *ip, struct file *fp) | ||
1909 | { | ||
1910 | int status; | ||
1911 | |||
1912 | DEBUG((DEBUG_VFS, "executing opt_release")); | ||
1913 | DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n", | ||
1914 | ip, ip->i_bdev->bd_disk->disk_name, fp)); | ||
1915 | |||
1916 | if (!--open_count) { | ||
1917 | toc_uptodate = 0; | ||
1918 | opt_invalidate_buffers(); | ||
1919 | status = exec_cmd(COMUNLOCK); /* Unlock door */ | ||
1920 | if (status < 0) { | ||
1921 | DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status)); | ||
1922 | } | ||
1923 | if (auto_eject) { | ||
1924 | status = exec_cmd(COMOPEN); | ||
1925 | DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status)); | ||
1926 | } | ||
1927 | kfree(optcd_disk->private_data); | ||
1928 | del_timer(&delay_timer); | ||
1929 | del_timer(&req_timer); | ||
1930 | } | ||
1931 | return 0; | ||
1932 | } | ||
1933 | |||
1934 | |||
1935 | /* Check if disk has been changed */ | ||
1936 | static int opt_media_change(struct gendisk *disk) | ||
1937 | { | ||
1938 | DEBUG((DEBUG_VFS, "executing opt_media_change")); | ||
1939 | DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n", | ||
1940 | disk->disk_name, disk_changed)); | ||
1941 | |||
1942 | if (disk_changed) { | ||
1943 | disk_changed = 0; | ||
1944 | return 1; | ||
1945 | } | ||
1946 | return 0; | ||
1947 | } | ||
1948 | |||
1949 | /* Driver initialisation */ | ||
1950 | |||
1951 | |||
1952 | /* Returns 1 if a drive is detected with a version string | ||
1953 | starting with "DOLPHIN". Otherwise 0. */ | ||
1954 | static int __init version_ok(void) | ||
1955 | { | ||
1956 | char devname[100]; | ||
1957 | int count, i, ch, status; | ||
1958 | |||
1959 | status = exec_cmd(COMVERSION); | ||
1960 | if (status < 0) { | ||
1961 | DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status)); | ||
1962 | return 0; | ||
1963 | } | ||
1964 | if ((count = get_data(1)) < 0) { | ||
1965 | DEBUG((DEBUG_VFS, "get_data(1): %02x", -count)); | ||
1966 | return 0; | ||
1967 | } | ||
1968 | for (i = 0, ch = -1; count > 0; count--) { | ||
1969 | if ((ch = get_data(1)) < 0) { | ||
1970 | DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch)); | ||
1971 | break; | ||
1972 | } | ||
1973 | if (i < 99) | ||
1974 | devname[i++] = ch; | ||
1975 | } | ||
1976 | devname[i] = '\0'; | ||
1977 | if (ch < 0) | ||
1978 | return 0; | ||
1979 | |||
1980 | printk(KERN_INFO "optcd: Device %s detected\n", devname); | ||
1981 | return ((devname[0] == 'D') | ||
1982 | && (devname[1] == 'O') | ||
1983 | && (devname[2] == 'L') | ||
1984 | && (devname[3] == 'P') | ||
1985 | && (devname[4] == 'H') | ||
1986 | && (devname[5] == 'I') | ||
1987 | && (devname[6] == 'N')); | ||
1988 | } | ||
1989 | |||
1990 | |||
1991 | static struct block_device_operations opt_fops = { | ||
1992 | .owner = THIS_MODULE, | ||
1993 | .open = opt_open, | ||
1994 | .release = opt_release, | ||
1995 | .ioctl = opt_ioctl, | ||
1996 | .media_changed = opt_media_change, | ||
1997 | }; | ||
1998 | |||
1999 | #ifndef MODULE | ||
2000 | /* Get kernel parameter when used as a kernel driver */ | ||
2001 | static int optcd_setup(char *str) | ||
2002 | { | ||
2003 | int ints[4]; | ||
2004 | (void)get_options(str, ARRAY_SIZE(ints), ints); | ||
2005 | |||
2006 | if (ints[0] > 0) | ||
2007 | optcd_port = ints[1]; | ||
2008 | |||
2009 | return 1; | ||
2010 | } | ||
2011 | |||
2012 | __setup("optcd=", optcd_setup); | ||
2013 | |||
2014 | #endif /* MODULE */ | ||
2015 | |||
2016 | /* Test for presence of drive and initialize it. Called at boot time | ||
2017 | or during module initialisation. */ | ||
2018 | static int __init optcd_init(void) | ||
2019 | { | ||
2020 | int status; | ||
2021 | |||
2022 | if (optcd_port <= 0) { | ||
2023 | printk(KERN_INFO | ||
2024 | "optcd: no Optics Storage CDROM Initialization\n"); | ||
2025 | return -EIO; | ||
2026 | } | ||
2027 | optcd_disk = alloc_disk(1); | ||
2028 | if (!optcd_disk) { | ||
2029 | printk(KERN_ERR "optcd: can't allocate disk\n"); | ||
2030 | return -ENOMEM; | ||
2031 | } | ||
2032 | optcd_disk->major = MAJOR_NR; | ||
2033 | optcd_disk->first_minor = 0; | ||
2034 | optcd_disk->fops = &opt_fops; | ||
2035 | sprintf(optcd_disk->disk_name, "optcd"); | ||
2036 | sprintf(optcd_disk->devfs_name, "optcd"); | ||
2037 | |||
2038 | if (!request_region(optcd_port, 4, "optcd")) { | ||
2039 | printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n", | ||
2040 | optcd_port); | ||
2041 | put_disk(optcd_disk); | ||
2042 | return -EIO; | ||
2043 | } | ||
2044 | |||
2045 | if (!reset_drive()) { | ||
2046 | printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port); | ||
2047 | release_region(optcd_port, 4); | ||
2048 | put_disk(optcd_disk); | ||
2049 | return -EIO; | ||
2050 | } | ||
2051 | if (!version_ok()) { | ||
2052 | printk(KERN_ERR "optcd: unknown drive detected; aborting\n"); | ||
2053 | release_region(optcd_port, 4); | ||
2054 | put_disk(optcd_disk); | ||
2055 | return -EIO; | ||
2056 | } | ||
2057 | status = exec_cmd(COMINITDOUBLE); | ||
2058 | if (status < 0) { | ||
2059 | printk(KERN_ERR "optcd: cannot init double speed mode\n"); | ||
2060 | release_region(optcd_port, 4); | ||
2061 | DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status)); | ||
2062 | put_disk(optcd_disk); | ||
2063 | return -EIO; | ||
2064 | } | ||
2065 | if (register_blkdev(MAJOR_NR, "optcd")) { | ||
2066 | release_region(optcd_port, 4); | ||
2067 | put_disk(optcd_disk); | ||
2068 | return -EIO; | ||
2069 | } | ||
2070 | |||
2071 | |||
2072 | opt_queue = blk_init_queue(do_optcd_request, &optcd_lock); | ||
2073 | if (!opt_queue) { | ||
2074 | unregister_blkdev(MAJOR_NR, "optcd"); | ||
2075 | release_region(optcd_port, 4); | ||
2076 | put_disk(optcd_disk); | ||
2077 | return -ENOMEM; | ||
2078 | } | ||
2079 | |||
2080 | blk_queue_hardsect_size(opt_queue, 2048); | ||
2081 | optcd_disk->queue = opt_queue; | ||
2082 | add_disk(optcd_disk); | ||
2083 | |||
2084 | printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); | ||
2085 | return 0; | ||
2086 | } | ||
2087 | |||
2088 | |||
2089 | static void __exit optcd_exit(void) | ||
2090 | { | ||
2091 | del_gendisk(optcd_disk); | ||
2092 | put_disk(optcd_disk); | ||
2093 | if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) { | ||
2094 | printk(KERN_ERR "optcd: what's that: can't unregister\n"); | ||
2095 | return; | ||
2096 | } | ||
2097 | blk_cleanup_queue(opt_queue); | ||
2098 | release_region(optcd_port, 4); | ||
2099 | printk(KERN_INFO "optcd: module released.\n"); | ||
2100 | } | ||
2101 | |||
2102 | module_init(optcd_init); | ||
2103 | module_exit(optcd_exit); | ||
2104 | |||
2105 | MODULE_LICENSE("GPL"); | ||
2106 | MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/optcd.h b/drivers/cdrom/optcd.h new file mode 100644 index 000000000000..1911bb92ee28 --- /dev/null +++ b/drivers/cdrom/optcd.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* linux/include/linux/optcd.h - Optics Storage 8000 AT CDROM driver | ||
2 | $Id: optcd.h,v 1.2 1996/01/15 18:43:44 root Exp root $ | ||
3 | |||
4 | Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) | ||
5 | |||
6 | |||
7 | Configuration file for linux/drivers/cdrom/optcd.c | ||
8 | */ | ||
9 | |||
10 | #ifndef _LINUX_OPTCD_H | ||
11 | #define _LINUX_OPTCD_H | ||
12 | |||
13 | |||
14 | /* I/O base of drive. Drive uses base to base+2. | ||
15 | This setting can be overridden with the kernel or insmod command | ||
16 | line option 'optcd=<portbase>'. Use address of 0 to disable driver. */ | ||
17 | #define OPTCD_PORTBASE 0x340 | ||
18 | |||
19 | |||
20 | /* enable / disable parts of driver by define / undef */ | ||
21 | #define MULTISESSION /* multisession support (ALPHA) */ | ||
22 | |||
23 | |||
24 | /* Change 0 to 1 to debug various parts of the driver */ | ||
25 | #define DEBUG_DRIVE_IF 0 /* Low level drive interface */ | ||
26 | #define DEBUG_CONV 0 /* Address conversions */ | ||
27 | #define DEBUG_BUFFERS 0 /* Buffering and block size conversion */ | ||
28 | #define DEBUG_REQUEST 0 /* Request mechanism */ | ||
29 | #define DEBUG_STATE 0 /* State machine */ | ||
30 | #define DEBUG_TOC 0 /* Q-channel and Table of Contents */ | ||
31 | #define DEBUG_MULTIS 0 /* Multisession code */ | ||
32 | #define DEBUG_VFS 0 /* VFS interface */ | ||
33 | |||
34 | |||
35 | /* Don't touch these unless you know what you're doing. */ | ||
36 | |||
37 | /* Various timeout loop repetition counts. */ | ||
38 | #define BUSY_TIMEOUT 10000000 /* for busy wait */ | ||
39 | #define FAST_TIMEOUT 100000 /* ibid. for probing */ | ||
40 | #define SLEEP_TIMEOUT 6000 /* for timer wait */ | ||
41 | #define MULTI_SEEK_TIMEOUT 1000 /* for timer wait */ | ||
42 | #define READ_TIMEOUT 6000 /* for poll wait */ | ||
43 | #define STOP_TIMEOUT 2000 /* for poll wait */ | ||
44 | #define RESET_WAIT 5000 /* busy wait at drive reset */ | ||
45 | |||
46 | /* # of buffers for block size conversion. 6 is optimal for my setup (P75), | ||
47 | giving 280 kb/s, with 0.4% CPU usage. Experiment to find your optimal | ||
48 | setting */ | ||
49 | #define N_BUFS 6 | ||
50 | |||
51 | |||
52 | #endif /* _LINUX_OPTCD_H */ | ||
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c new file mode 100644 index 000000000000..fc2c433f6a29 --- /dev/null +++ b/drivers/cdrom/sbpcd.c | |||
@@ -0,0 +1,5978 @@ | |||
1 | /* | ||
2 | * sbpcd.c CD-ROM device driver for the whole family of traditional, | ||
3 | * non-ATAPI IDE-style Matsushita/Panasonic CR-5xx drives. | ||
4 | * Works with SoundBlaster compatible cards and with "no-sound" | ||
5 | * interface cards like Lasermate, Panasonic CI-101P, Teac, ... | ||
6 | * Also for the Longshine LCS-7260 drive. | ||
7 | * Also for the IBM "External ISA CD-Rom" drive. | ||
8 | * Also for the CreativeLabs CD200 drive. | ||
9 | * Also for the TEAC CD-55A drive. | ||
10 | * Also for the ECS-AT "Vertos 100" drive. | ||
11 | * Not for Sanyo drives (but for the H94A, sjcd is there...). | ||
12 | * Not for any other Funai drives than the CD200 types (sometimes | ||
13 | * labelled E2550UA or MK4015 or 2800F). | ||
14 | */ | ||
15 | |||
16 | #define VERSION "v4.63 Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000" | ||
17 | |||
18 | /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg <emoenke@gwdg.de> | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2, or (at your option) | ||
23 | * any later version. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * (for example /usr/src/linux/COPYING); if not, write to the Free | ||
27 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | * | ||
29 | * If you change this software, you should mail a .diff file with some | ||
30 | * description lines to emoenke@gwdg.de. I want to know about it. | ||
31 | * | ||
32 | * If you are the editor of a Linux CD, you should enable sbpcd.c within | ||
33 | * your boot floppy kernel and send me one of your CDs for free. | ||
34 | * | ||
35 | * If you would like to port the driver to an other operating system (f.e. | ||
36 | * FreeBSD or NetBSD) or use it as an information source, you shall not be | ||
37 | * restricted by the GPL under the following conditions: | ||
38 | * a) the source code of your work is freely available | ||
39 | * b) my part of the work gets mentioned at all places where your | ||
40 | * authorship gets mentioned | ||
41 | * c) I receive a copy of your code together with a full installation | ||
42 | * package of your operating system for free. | ||
43 | * | ||
44 | * | ||
45 | * VERSION HISTORY | ||
46 | * | ||
47 | * 0.1 initial release, April/May 93, after mcd.c (Martin Harriss) | ||
48 | * | ||
49 | * 0.2 thek "repeat:"-loop in do_sbpcd_request did not check for | ||
50 | * end-of-request_queue (resulting in kernel panic). | ||
51 | * Flow control seems stable, but throughput is not better. | ||
52 | * | ||
53 | * 0.3 interrupt locking totally eliminated (maybe "inb" and "outb" | ||
54 | * are still locking) - 0.2 made keyboard-type-ahead losses. | ||
55 | * check_sbpcd_media_change added (to use by isofs/inode.c) | ||
56 | * - but it detects almost nothing. | ||
57 | * | ||
58 | * 0.4 use MAJOR 25 definitely. | ||
59 | * Almost total re-design to support double-speed drives and | ||
60 | * "naked" (no sound) interface cards ("LaserMate" interface type). | ||
61 | * Flow control should be exact now. | ||
62 | * Don't occupy the SbPro IRQ line (not needed either); will | ||
63 | * live together with Hannu Savolainen's sndkit now. | ||
64 | * Speeded up data transfer to 150 kB/sec, with help from Kai | ||
65 | * Makisara, the "provider" of the "mt" tape utility. | ||
66 | * Give "SpinUp" command if necessary. | ||
67 | * First steps to support up to 4 drives (but currently only one). | ||
68 | * Implemented audio capabilities - workman should work, xcdplayer | ||
69 | * gives some problems. | ||
70 | * This version is still consuming too much CPU time, and | ||
71 | * sleeping still has to be worked on. | ||
72 | * During "long" implied seeks, it seems possible that a | ||
73 | * ReadStatus command gets ignored. That gives the message | ||
74 | * "ResponseStatus timed out" (happens about 6 times here during | ||
75 | * a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is | ||
76 | * handled without data error, but it should get done better. | ||
77 | * | ||
78 | * 0.5 Free CPU during waits (again with help from Kai Makisara). | ||
79 | * Made it work together with the LILO/kernel setup standard. | ||
80 | * Included auto-probing code, as suggested by YGGDRASIL. | ||
81 | * Formal redesign to add DDI debugging. | ||
82 | * There are still flaws in IOCTL (workman with double speed drive). | ||
83 | * | ||
84 | * 1.0 Added support for all drive IDs (0...3, no longer only 0) | ||
85 | * and up to 4 drives on one controller. | ||
86 | * Added "#define MANY_SESSION" for "old" multi session CDs. | ||
87 | * | ||
88 | * 1.1 Do SpinUp for new drives, too. | ||
89 | * Revised for clean compile under "old" kernels (0.99pl9). | ||
90 | * | ||
91 | * 1.2 Found the "workman with double-speed drive" bug: use the driver's | ||
92 | * audio_state, not what the drive is reporting with ReadSubQ. | ||
93 | * | ||
94 | * 1.3 Minor cleanups. | ||
95 | * Refinements regarding Workman. | ||
96 | * | ||
97 | * 1.4 Read XA disks (PhotoCDs) with "old" drives, too (but only the first | ||
98 | * session - no chance to fully access a "multi-session" CD). | ||
99 | * This currently still is too slow (50 kB/sec) - but possibly | ||
100 | * the old drives won't do it faster. | ||
101 | * Implemented "door (un)lock" for new drives (still does not work | ||
102 | * as wanted - no lock possible after an unlock). | ||
103 | * Added some debugging printout for the UPC/EAN code - but my drives | ||
104 | * return only zeroes. Is there no UPC/EAN code written? | ||
105 | * | ||
106 | * 1.5 Laborate with UPC/EAN code (not better yet). | ||
107 | * Adapt to kernel 1.1.8 change (have to explicitly include | ||
108 | * <linux/string.h> now). | ||
109 | * | ||
110 | * 1.6 Trying to read audio frames as data. Impossible with the current | ||
111 | * drive firmware levels, as it seems. Awaiting any hint. ;-) | ||
112 | * Changed "door unlock": repeat it until success. | ||
113 | * Changed CDROMSTOP routine (stop somewhat "softer" so that Workman | ||
114 | * won't get confused). | ||
115 | * Added a third interface type: Sequoia S-1000, as used with the SPEA | ||
116 | * Media FX sound card. This interface (usable for Sony and Mitsumi | ||
117 | * drives, too) needs a special configuration setup and behaves like a | ||
118 | * LaserMate type after that. Still experimental - I do not have such | ||
119 | * an interface. | ||
120 | * Use the "variable BLOCK_SIZE" feature (2048). But it does only work | ||
121 | * if you give the mount option "block=2048". | ||
122 | * The media_check routine is currently disabled; now that it gets | ||
123 | * called as it should I fear it must get synchronized for not to | ||
124 | * disturb the normal driver's activity. | ||
125 | * | ||
126 | * 2.0 Version number bumped - two reasons: | ||
127 | * - reading audio tracks as data works now with CR-562 and CR-563. We | ||
128 | * currently do it by an IOCTL (yet has to get standardized), one frame | ||
129 | * at a time; that is pretty slow. But it works. | ||
130 | * - we are maintaining now up to 4 interfaces (each up to 4 drives): | ||
131 | * did it the easy way - a different MAJOR (25, 26, ...) and a different | ||
132 | * copy of the driver (sbpcd.c, sbpcd2.c, sbpcd3.c, sbpcd4.c - only | ||
133 | * distinguished by the value of SBPCD_ISSUE and the driver's name), | ||
134 | * and a common sbpcd.h file. | ||
135 | * Bettered the "ReadCapacity error" problem with old CR-52x drives (the | ||
136 | * drives sometimes need a manual "eject/insert" before work): just | ||
137 | * reset the drive and do again. Needs lots of resets here and sometimes | ||
138 | * that does not cure, so this can't be the solution. | ||
139 | * | ||
140 | * 2.1 Found bug with multisession CDs (accessing frame 16). | ||
141 | * "read audio" works now with address type CDROM_MSF, too. | ||
142 | * Bigger audio frame buffer: allows reading max. 4 frames at time; this | ||
143 | * gives a significant speedup, but reading more than one frame at once | ||
144 | * gives missing chunks at each single frame boundary. | ||
145 | * | ||
146 | * 2.2 Kernel interface cleanups: timers, init, setup, media check. | ||
147 | * | ||
148 | * 2.3 Let "door lock" and "eject" live together. | ||
149 | * Implemented "close tray" (done automatically during open). | ||
150 | * | ||
151 | * 2.4 Use different names for device registering. | ||
152 | * | ||
153 | * 2.5 Added "#if EJECT" code (default: enabled) to automatically eject | ||
154 | * the tray during last call to "sbpcd_release". | ||
155 | * Added "#if JUKEBOX" code (default: disabled) to automatically eject | ||
156 | * the tray during call to "sbpcd_open" if no disk is in. | ||
157 | * Turn on the CD volume of "compatible" sound cards, too; just define | ||
158 | * SOUND_BASE (in sbpcd.h) accordingly (default: disabled). | ||
159 | * | ||
160 | * 2.6 Nothing new. | ||
161 | * | ||
162 | * 2.7 Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly: | ||
163 | * 0 disables, 1 enables auto-ejecting. Useful to keep the tray in | ||
164 | * during shutdown. | ||
165 | * | ||
166 | * 2.8 Added first support (still BETA, I need feedback or a drive) for | ||
167 | * the Longshine LCS-7260 drives. They appear as double-speed drives | ||
168 | * using the "old" command scheme, extended by tray control and door | ||
169 | * lock functions. | ||
170 | * Found (and fixed preliminary) a flaw with some multisession CDs: we | ||
171 | * have to re-direct not only the accesses to frame 16 (the isofs | ||
172 | * routines drive it up to max. 100), but also those to the continuation | ||
173 | * (repetition) frames (as far as they exist - currently set fix as | ||
174 | * 16..20). | ||
175 | * Changed default of the "JUKEBOX" define. If you use this default, | ||
176 | * your tray will eject if you try to mount without a disk in. Next | ||
177 | * mount command will insert the tray - so, just fill in a disk. ;-) | ||
178 | * | ||
179 | * 2.9 Fulfilled the Longshine LCS-7260 support; with great help and | ||
180 | * experiments by Serge Robyns. | ||
181 | * First attempts to support the TEAC CD-55A drives; but still not | ||
182 | * usable yet. | ||
183 | * Implemented the CDROMMULTISESSION ioctl; this is an attempt to handle | ||
184 | * multi session CDs more "transparent" (redirection handling has to be | ||
185 | * done within the isofs routines, and only for the special purpose of | ||
186 | * obtaining the "right" volume descriptor; accesses to the raw device | ||
187 | * should not get redirected). | ||
188 | * | ||
189 | * 3.0 Just a "normal" increment, with some provisions to do it better. ;-) | ||
190 | * Introduced "#define READ_AUDIO" to specify the maximum number of | ||
191 | * audio frames to grab with one request. This defines a buffer size | ||
192 | * within kernel space; a value of 0 will reserve no such space and | ||
193 | * disable the CDROMREADAUDIO ioctl. A value of 75 enables the reading | ||
194 | * of a whole second with one command, but will use a buffer of more | ||
195 | * than 172 kB. | ||
196 | * Started CD200 support. Drive detection should work, but nothing | ||
197 | * more. | ||
198 | * | ||
199 | * 3.1 Working to support the CD200 and the Teac CD-55A drives. | ||
200 | * AT-BUS style device numbering no longer used: use SCSI style now. | ||
201 | * So, the first "found" device has MINOR 0, regardless of the | ||
202 | * jumpered drive ID. This implies modifications to the /dev/sbpcd* | ||
203 | * entries for some people, but will help the DAU (german TLA, english: | ||
204 | * "newbie", maybe ;-) to install his "first" system from a CD. | ||
205 | * | ||
206 | * 3.2 Still testing with CD200 and CD-55A drives. | ||
207 | * | ||
208 | * 3.3 Working with CD200 support. | ||
209 | * | ||
210 | * 3.4 Auto-probing stops if an address of 0 is seen (to be entered with | ||
211 | * the kernel command line). | ||
212 | * Made the driver "loadable". If used as a module, "audio copy" is | ||
213 | * disabled, and the internal read ahead data buffer has a reduced size | ||
214 | * of 4 kB; so, throughput may be reduced a little bit with slow CPUs. | ||
215 | * | ||
216 | * 3.5 Provisions to handle weird photoCDs which have an interrupted | ||
217 | * "formatting" immediately after the last frames of some files: simply | ||
218 | * never "read ahead" with MultiSession CDs. By this, CPU usage may be | ||
219 | * increased with those CDs, and there may be a loss in speed. | ||
220 | * Re-structured the messaging system. | ||
221 | * The "loadable" version no longer has a limited READ_AUDIO buffer | ||
222 | * size. | ||
223 | * Removed "MANY_SESSION" handling for "old" multi session CDs. | ||
224 | * Added "private" IOCTLs CDROMRESET and CDROMVOLREAD. | ||
225 | * Started again to support the TEAC CD-55A drives, now that I found | ||
226 | * the money for "my own" drive. ;-) | ||
227 | * The TEAC CD-55A support is fairly working now. | ||
228 | * I have measured that the drive "delivers" at 600 kB/sec (even with | ||
229 | * bigger requests than the drive's 64 kB buffer can satisfy), but | ||
230 | * the "real" rate does not exceed 520 kB/sec at the moment. | ||
231 | * Caused by the various changes to build in TEAC support, the timed | ||
232 | * loops are de-optimized at the moment (less throughput with CR-52x | ||
233 | * drives, and the TEAC will give speed only with SBP_BUFFER_FRAMES 64). | ||
234 | * | ||
235 | * 3.6 Fixed TEAC data read problems with SbPro interfaces. | ||
236 | * Initial size of the READ_AUDIO buffer is 0. Can get set to any size | ||
237 | * during runtime. | ||
238 | * | ||
239 | * 3.7 Introduced MAX_DRIVES for some poor interface cards (seen with TEAC | ||
240 | * drives) which allow only one drive (ID 0); this avoids repetitive | ||
241 | * detection under IDs 1..3. | ||
242 | * Elongated cmd_out_T response waiting; necessary for photo CDs with | ||
243 | * a lot of sessions. | ||
244 | * Bettered the sbpcd_open() behavior with TEAC drives. | ||
245 | * | ||
246 | * 3.8 Elongated max_latency for CR-56x drives. | ||
247 | * | ||
248 | * 3.9 Finally fixed the long-known SoundScape/SPEA/Sequoia S-1000 interface | ||
249 | * configuration bug. | ||
250 | * Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy | ||
251 | * the config_spea() routine into their drivers. ;-) | ||
252 | * | ||
253 | * 4.0 No "big step" - normal version increment. | ||
254 | * Adapted the benefits from 1.3.33. | ||
255 | * Fiddled with CDROMREADAUDIO flaws. | ||
256 | * Avoid ReadCapacity command with CD200 drives (the MKE 1.01 version | ||
257 | * seems not to support it). | ||
258 | * Fulfilled "read audio" for CD200 drives, with help of Pete Heist | ||
259 | * (heistp@rpi.edu). | ||
260 | * | ||
261 | * 4.1 Use loglevel KERN_INFO with printk(). | ||
262 | * Added support for "Vertos 100" drive ("ECS-AT") - it is very similar | ||
263 | * to the Longshine LCS-7260. Give feedback if you can - I never saw | ||
264 | * such a drive, and I have no specs. | ||
265 | * | ||
266 | * 4.2 Support for Teac 16-bit interface cards. Can't get auto-detected, | ||
267 | * so you have to jumper your card to 0x2C0. Still not 100% - come | ||
268 | * in contact if you can give qualified feedback. | ||
269 | * Use loglevel KERN_NOTICE with printk(). If you get annoyed by a | ||
270 | * flood of unwanted messages and the accompanied delay, try to read | ||
271 | * my documentation. Especially the Linux CDROM drivers have to do an | ||
272 | * important job for the newcomers, so the "distributed" version has | ||
273 | * to fit some special needs. Since generations, the flood of messages | ||
274 | * is user-configurable (even at runtime), but to get aware of this, one | ||
275 | * needs a special mental quality: the ability to read. | ||
276 | * | ||
277 | * 4.3 CD200F does not like to receive a command while the drive is | ||
278 | * reading the ToC; still trying to solve it. | ||
279 | * Removed some redundant verify_area calls (yes, Heiko Eissfeldt | ||
280 | * is visiting all the Linux CDROM drivers ;-). | ||
281 | * | ||
282 | * 4.4 Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down" | ||
283 | * experiments: "KLOGD_PAUSE". | ||
284 | * Inhibited "play audio" attempts with data CDs. Provisions for a | ||
285 | * "data-safe" handling of "mixed" (data plus audio) Cds. | ||
286 | * | ||
287 | * 4.5 Meanwhile Gonzalo Tornaria <tornaria@cmat.edu.uy> (GTL) built a | ||
288 | * special end_request routine: we seem to have to take care for not | ||
289 | * to have two processes working at the request list. My understanding | ||
290 | * was and is that ll_rw_blk should not call do_sbpcd_request as long | ||
291 | * as there is still one call active (the first call will care for all | ||
292 | * outstanding I/Os, and if a second call happens, that is a bug in | ||
293 | * ll_rw_blk.c). | ||
294 | * "Check media change" without touching any drive. | ||
295 | * | ||
296 | * 4.6 Use a semaphore to synchronize multi-activity; elaborated by Rob | ||
297 | * Riggs <rriggs@tesser.com>. At the moment, we simply block "read" | ||
298 | * against "ioctl" and vice versa. This could be refined further, but | ||
299 | * I guess with almost no performance increase. | ||
300 | * Experiments to speed up the CD-55A; again with help of Rob Riggs | ||
301 | * (to be true, he gave both, idea & code. ;-) | ||
302 | * | ||
303 | * 4.61 Ported to Uniform CD-ROM driver by | ||
304 | * Heiko Eissfeldt <heiko@colossus.escape.de> with additional | ||
305 | * changes by Erik Andersen <andersee@debian.org> | ||
306 | * | ||
307 | * 4.62 Fix a bug where playing audio left the drive in an unusable state. | ||
308 | * Heiko Eissfeldt <heiko@colossus.escape.de> | ||
309 | * | ||
310 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
311 | * Removed init_module & cleanup_module in favor of | ||
312 | * module_init & module_exit. | ||
313 | * Torben Mathiasen <tmm@image.dk> | ||
314 | * | ||
315 | * 4.63 Bug fixes for audio annoyances, new legacy CDROM maintainer. | ||
316 | * Annoying things fixed: | ||
317 | * TOC reread on automated disk changes | ||
318 | * TOC reread on manual cd changes | ||
319 | * Play IOCTL tries to play CD before it's actually ready... sometimes. | ||
320 | * CD_AUDIO_COMPLETED state so workman (and other playes) can repeat play. | ||
321 | * Andrew J. Kroll <ag784@freenet.buffalo.edu> Wed Jul 26 04:24:10 EDT 2000 | ||
322 | * | ||
323 | * 4.64 Fix module parameters - were being completely ignored. | ||
324 | * Can also specify max_drives=N as a setup int to get rid of | ||
325 | * "ghost" drives on crap hardware (aren't they all?) Paul Gortmaker | ||
326 | * | ||
327 | * TODO | ||
328 | * implement "read all subchannel data" (96 bytes per frame) | ||
329 | * remove alot of the virtual status bits and deal with hardware status | ||
330 | * move the change of cd for audio to a better place | ||
331 | * add debug levels to insmod parameters (trivial) | ||
332 | * | ||
333 | * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine | ||
334 | * elaborated speed-up experiments (and the fabulous results!), for | ||
335 | * the "push" towards load-free wait loops, and for the extensive mail | ||
336 | * thread which brought additional hints and bug fixes. | ||
337 | * | ||
338 | */ | ||
339 | |||
340 | /* | ||
341 | * Trying to merge requests breaks this driver horribly (as in it goes | ||
342 | * boom and apparently has done so since 2.3.41). As it is a legacy | ||
343 | * driver for a horribly slow double speed CD on a hideous interface | ||
344 | * designed for polled operation, I won't lose any sleep in simply | ||
345 | * disallowing merging. Paul G. 02/2001 | ||
346 | * | ||
347 | * Thu May 30 14:14:47 CEST 2002: | ||
348 | * | ||
349 | * I have presumably found the reson for the above - there was a bogous | ||
350 | * end_request substitute, which was manipulating the request queues | ||
351 | * incorrectly. If someone has access to the actual hardware, and it's | ||
352 | * still operations - well please free to test it. | ||
353 | * | ||
354 | * Marcin Dalecki | ||
355 | */ | ||
356 | |||
357 | /* | ||
358 | * Add bio/kdev_t changes for 2.5.x required to make it work again. | ||
359 | * Still room for improvement in the request handling here if anyone | ||
360 | * actually cares. Bring your own chainsaw. Paul G. 02/2002 | ||
361 | */ | ||
362 | |||
363 | |||
364 | #include <linux/module.h> | ||
365 | |||
366 | #include <linux/errno.h> | ||
367 | #include <linux/sched.h> | ||
368 | #include <linux/mm.h> | ||
369 | #include <linux/timer.h> | ||
370 | #include <linux/fs.h> | ||
371 | #include <linux/kernel.h> | ||
372 | #include <linux/cdrom.h> | ||
373 | #include <linux/ioport.h> | ||
374 | #include <linux/devfs_fs_kernel.h> | ||
375 | #include <linux/major.h> | ||
376 | #include <linux/string.h> | ||
377 | #include <linux/vmalloc.h> | ||
378 | #include <linux/init.h> | ||
379 | #include <linux/interrupt.h> | ||
380 | |||
381 | #include <asm/system.h> | ||
382 | #include <asm/io.h> | ||
383 | #include <asm/uaccess.h> | ||
384 | #include <stdarg.h> | ||
385 | #include <linux/config.h> | ||
386 | #include "sbpcd.h" | ||
387 | |||
388 | #define MAJOR_NR MATSUSHITA_CDROM_MAJOR | ||
389 | #include <linux/blkdev.h> | ||
390 | |||
391 | /*==========================================================================*/ | ||
392 | #if SBPCD_DIS_IRQ | ||
393 | # define SBPCD_CLI cli() | ||
394 | # define SBPCD_STI sti() | ||
395 | #else | ||
396 | # define SBPCD_CLI | ||
397 | # define SBPCD_STI | ||
398 | #endif | ||
399 | |||
400 | /*==========================================================================*/ | ||
401 | /* | ||
402 | * auto-probing address list | ||
403 | * inspired by Adam J. Richter from Yggdrasil | ||
404 | * | ||
405 | * still not good enough - can cause a hang. | ||
406 | * example: a NE 2000 ethernet card at 300 will cause a hang probing 310. | ||
407 | * if that happens, reboot and use the LILO (kernel) command line. | ||
408 | * The possibly conflicting ethernet card addresses get NOT probed | ||
409 | * by default - to minimize the hang possibilities. | ||
410 | * | ||
411 | * The SB Pro addresses get "mirrored" at 0x6xx and some more locations - to | ||
412 | * avoid a type error, the 0x2xx-addresses must get checked before 0x6xx. | ||
413 | * | ||
414 | * send mail to emoenke@gwdg.de if your interface card is not FULLY | ||
415 | * represented here. | ||
416 | */ | ||
417 | static int sbpcd[] = | ||
418 | { | ||
419 | CDROM_PORT, SBPRO, /* probe with user's setup first */ | ||
420 | #if DISTRIBUTION | ||
421 | 0x230, 1, /* Soundblaster Pro and 16 (default) */ | ||
422 | #if 0 | ||
423 | 0x300, 0, /* CI-101P (default), WDH-7001C (default), | ||
424 | Galaxy (default), Reveal (one default) */ | ||
425 | 0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */ | ||
426 | 0x2C0, 3, /* Teac 16-bit cards */ | ||
427 | 0x260, 1, /* OmniCD */ | ||
428 | 0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default), | ||
429 | Longshine LCS-6853 (default) */ | ||
430 | 0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */ | ||
431 | 0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */ | ||
432 | 0x360, 0, /* Lasermate, CI-101P */ | ||
433 | 0x270, 1, /* Soundblaster 16 */ | ||
434 | 0x670, 0, /* "sound card #9" */ | ||
435 | 0x690, 0, /* "sound card #9" */ | ||
436 | 0x338, 2, /* SPEA Media FX, Ensonic SoundScape (default) */ | ||
437 | 0x328, 2, /* SPEA Media FX */ | ||
438 | 0x348, 2, /* SPEA Media FX */ | ||
439 | 0x634, 0, /* some newer sound cards */ | ||
440 | 0x638, 0, /* some newer sound cards */ | ||
441 | 0x230, 1, /* some newer sound cards */ | ||
442 | /* due to incomplete address decoding of the SbPro card, these must be last */ | ||
443 | 0x630, 0, /* "sound card #9" (default) */ | ||
444 | 0x650, 0, /* "sound card #9" */ | ||
445 | #ifdef MODULE | ||
446 | /* | ||
447 | * some "hazardous" locations (no harm with the loadable version) | ||
448 | * (will stop the bus if a NE2000 ethernet card resides at offset -0x10) | ||
449 | */ | ||
450 | 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */ | ||
451 | 0x350, 0, /* Lasermate, CI-101P */ | ||
452 | 0x358, 2, /* SPEA Media FX */ | ||
453 | 0x370, 0, /* Lasermate, CI-101P */ | ||
454 | 0x290, 1, /* Soundblaster 16 */ | ||
455 | 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ | ||
456 | #endif /* MODULE */ | ||
457 | #endif | ||
458 | #endif /* DISTRIBUTION */ | ||
459 | }; | ||
460 | |||
461 | /* | ||
462 | * Protects access to global structures etc. | ||
463 | */ | ||
464 | static __cacheline_aligned DEFINE_SPINLOCK(sbpcd_lock); | ||
465 | static struct request_queue *sbpcd_queue; | ||
466 | |||
467 | MODULE_PARM(sbpcd, "2i"); | ||
468 | MODULE_PARM(max_drives, "i"); | ||
469 | |||
470 | #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) | ||
471 | |||
472 | /*==========================================================================*/ | ||
473 | |||
474 | #define INLINE inline | ||
475 | |||
476 | /*==========================================================================*/ | ||
477 | /* | ||
478 | * the forward references: | ||
479 | */ | ||
480 | static void sbp_sleep(u_int); | ||
481 | static void mark_timeout_delay(u_long); | ||
482 | static void mark_timeout_data(u_long); | ||
483 | #if 0 | ||
484 | static void mark_timeout_audio(u_long); | ||
485 | #endif | ||
486 | static void sbp_read_cmd(struct request *req); | ||
487 | static int sbp_data(struct request *req); | ||
488 | static int cmd_out(void); | ||
489 | static int DiskInfo(void); | ||
490 | |||
491 | /*==========================================================================*/ | ||
492 | |||
493 | /* | ||
494 | * pattern for printk selection: | ||
495 | * | ||
496 | * (1<<DBG_INF) necessary information | ||
497 | * (1<<DBG_BSZ) BLOCK_SIZE trace | ||
498 | * (1<<DBG_REA) "read" status trace | ||
499 | * (1<<DBG_CHK) "media check" trace | ||
500 | * (1<<DBG_TIM) datarate timer test | ||
501 | * (1<<DBG_INI) initialization trace | ||
502 | * (1<<DBG_TOC) tell TocEntry values | ||
503 | * (1<<DBG_IOC) ioctl trace | ||
504 | * (1<<DBG_STA) "ResponseStatus" trace | ||
505 | * (1<<DBG_ERR) "cc_ReadError" trace | ||
506 | * (1<<DBG_CMD) "cmd_out" trace | ||
507 | * (1<<DBG_WRN) give explanation before auto-probing | ||
508 | * (1<<DBG_MUL) multi session code test | ||
509 | * (1<<DBG_IDX) "drive_id != 0" test code | ||
510 | * (1<<DBG_IOX) some special information | ||
511 | * (1<<DBG_DID) drive ID test | ||
512 | * (1<<DBG_RES) drive reset info | ||
513 | * (1<<DBG_SPI) SpinUp test info | ||
514 | * (1<<DBG_IOS) ioctl trace: "subchannel" | ||
515 | * (1<<DBG_IO2) ioctl trace: general | ||
516 | * (1<<DBG_UPC) show UPC info | ||
517 | * (1<<DBG_XA1) XA mode debugging | ||
518 | * (1<<DBG_LCK) door (un)lock info | ||
519 | * (1<<DBG_SQ1) dump SubQ frame | ||
520 | * (1<<DBG_AUD) "read audio" debugging | ||
521 | * (1<<DBG_SEQ) Sequoia interface configuration trace | ||
522 | * (1<<DBG_LCS) Longshine LCS-7260 debugging trace | ||
523 | * (1<<DBG_CD2) MKE/Funai CD200 debugging trace | ||
524 | * (1<<DBG_TEA) TEAC CD-55A debugging trace | ||
525 | * (1<<DBG_ECS) ECS-AT (Vertos-100) debugging trace | ||
526 | * (1<<DBG_000) unnecessary information | ||
527 | */ | ||
528 | #if DISTRIBUTION | ||
529 | static int sbpcd_debug = (1<<DBG_INF); | ||
530 | #else | ||
531 | static int sbpcd_debug = 0 & ((1<<DBG_INF) | | ||
532 | (1<<DBG_TOC) | | ||
533 | (1<<DBG_MUL) | | ||
534 | (1<<DBG_UPC)); | ||
535 | #endif /* DISTRIBUTION */ | ||
536 | |||
537 | static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */ | ||
538 | static int sbpro_type = SBPRO; | ||
539 | static unsigned char f_16bit; | ||
540 | static unsigned char do_16bit; | ||
541 | static int CDo_command, CDo_reset; | ||
542 | static int CDo_sel_i_d, CDo_enable; | ||
543 | static int CDi_info, CDi_status, CDi_data; | ||
544 | static struct cdrom_msf msf; | ||
545 | static struct cdrom_ti ti; | ||
546 | static struct cdrom_tochdr tochdr; | ||
547 | static struct cdrom_tocentry tocentry; | ||
548 | static struct cdrom_subchnl SC; | ||
549 | static struct cdrom_volctrl volctrl; | ||
550 | static struct cdrom_read_audio read_audio; | ||
551 | |||
552 | static unsigned char msgnum; | ||
553 | static char msgbuf[80]; | ||
554 | |||
555 | static int max_drives = MAX_DRIVES; | ||
556 | #ifndef MODULE | ||
557 | static unsigned char setup_done; | ||
558 | static const char *str_sb_l = "soundblaster"; | ||
559 | static const char *str_sp_l = "spea"; | ||
560 | static const char *str_ss_l = "soundscape"; | ||
561 | static const char *str_t16_l = "teac16bit"; | ||
562 | static const char *str_ss = "SoundScape"; | ||
563 | #endif | ||
564 | static const char *str_sb = "SoundBlaster"; | ||
565 | static const char *str_lm = "LaserMate"; | ||
566 | static const char *str_sp = "SPEA"; | ||
567 | static const char *str_t16 = "Teac16bit"; | ||
568 | static const char *type; | ||
569 | static const char *major_name="sbpcd"; | ||
570 | |||
571 | /*==========================================================================*/ | ||
572 | |||
573 | #ifdef FUTURE | ||
574 | static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq); | ||
575 | #endif /* FUTURE */ | ||
576 | |||
577 | static int teac=SBP_TEAC_SPEED; | ||
578 | static int buffers=SBP_BUFFER_FRAMES; | ||
579 | |||
580 | static u_char family0[]="MATSHITA"; /* MKE CR-521, CR-522, CR-523 */ | ||
581 | static u_char family1[]="CR-56"; /* MKE CR-562, CR-563 */ | ||
582 | static u_char family2[]="CD200"; /* MKE CD200, Funai CD200F */ | ||
583 | static u_char familyL[]="LCS-7260"; /* Longshine LCS-7260 */ | ||
584 | static u_char familyT[]="CD-55"; /* TEAC CD-55A */ | ||
585 | static u_char familyV[]="ECS-AT"; /* ECS Vertos 100 */ | ||
586 | |||
587 | static u_int recursion; /* internal testing only */ | ||
588 | static u_int fatal_err; /* internal testing only */ | ||
589 | static u_int response_count; | ||
590 | static u_int flags_cmd_out; | ||
591 | static u_char cmd_type; | ||
592 | static u_char drvcmd[10]; | ||
593 | static u_char infobuf[20]; | ||
594 | static u_char xa_head_buf[CD_XA_HEAD]; | ||
595 | static u_char xa_tail_buf[CD_XA_TAIL]; | ||
596 | |||
597 | #if OLD_BUSY | ||
598 | static volatile u_char busy_data; | ||
599 | static volatile u_char busy_audio; /* true semaphores would be safer */ | ||
600 | #endif /* OLD_BUSY */ | ||
601 | static DECLARE_MUTEX(ioctl_read_sem); | ||
602 | static u_long timeout; | ||
603 | static volatile u_char timed_out_delay; | ||
604 | static volatile u_char timed_out_data; | ||
605 | #if 0 | ||
606 | static volatile u_char timed_out_audio; | ||
607 | #endif | ||
608 | static u_int datarate= 1000000; | ||
609 | static u_int maxtim16=16000000; | ||
610 | static u_int maxtim04= 4000000; | ||
611 | static u_int maxtim02= 2000000; | ||
612 | static u_int maxtim_8= 30000; | ||
613 | #if LONG_TIMING | ||
614 | static u_int maxtim_data= 9000; | ||
615 | #else | ||
616 | static u_int maxtim_data= 3000; | ||
617 | #endif /* LONG_TIMING */ | ||
618 | #if DISTRIBUTION | ||
619 | static int n_retries=6; | ||
620 | #else | ||
621 | static int n_retries=6; | ||
622 | #endif | ||
623 | /*==========================================================================*/ | ||
624 | |||
625 | static int ndrives; | ||
626 | static u_char drv_pattern[NR_SBPCD]={speed_auto,speed_auto,speed_auto,speed_auto}; | ||
627 | |||
628 | /*==========================================================================*/ | ||
629 | /* | ||
630 | * drive space begins here (needed separate for each unit) | ||
631 | */ | ||
632 | static struct sbpcd_drive { | ||
633 | char drv_id; /* "jumpered" drive ID or -1 */ | ||
634 | char drv_sel; /* drive select lines bits */ | ||
635 | |||
636 | char drive_model[9]; | ||
637 | u_char firmware_version[4]; | ||
638 | char f_eject; /* auto-eject flag: 0 or 1 */ | ||
639 | u_char *sbp_buf; /* Pointer to internal data buffer, | ||
640 | space allocated during sbpcd_init() */ | ||
641 | u_int sbp_bufsiz; /* size of sbp_buf (# of frames) */ | ||
642 | int sbp_first_frame; /* First frame in buffer */ | ||
643 | int sbp_last_frame; /* Last frame in buffer */ | ||
644 | int sbp_read_frames; /* Number of frames being read to buffer */ | ||
645 | int sbp_current; /* Frame being currently read */ | ||
646 | |||
647 | u_char mode; /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */ | ||
648 | u_char *aud_buf; /* Pointer to audio data buffer, | ||
649 | space allocated during sbpcd_init() */ | ||
650 | u_int sbp_audsiz; /* size of aud_buf (# of raw frames) */ | ||
651 | u_int drv_type; | ||
652 | u_char drv_options; | ||
653 | int status_bits; | ||
654 | u_char diskstate_flags; | ||
655 | u_char sense_byte; | ||
656 | |||
657 | u_char CD_changed; | ||
658 | char open_count; | ||
659 | u_char error_byte; | ||
660 | |||
661 | u_char f_multisession; | ||
662 | u_int lba_multi; | ||
663 | int first_session; | ||
664 | int last_session; | ||
665 | int track_of_last_session; | ||
666 | |||
667 | u_char audio_state; | ||
668 | u_int pos_audio_start; | ||
669 | u_int pos_audio_end; | ||
670 | char vol_chan0; | ||
671 | u_char vol_ctrl0; | ||
672 | char vol_chan1; | ||
673 | u_char vol_ctrl1; | ||
674 | #if 000 /* no supported drive has it */ | ||
675 | char vol_chan2; | ||
676 | u_char vol_ctrl2; | ||
677 | char vol_chan3; | ||
678 | u_char vol_ctrl3; | ||
679 | #endif /*000 */ | ||
680 | u_char volume_control; /* TEAC on/off bits */ | ||
681 | |||
682 | u_char SubQ_ctl_adr; | ||
683 | u_char SubQ_trk; | ||
684 | u_char SubQ_pnt_idx; | ||
685 | u_int SubQ_run_tot; | ||
686 | u_int SubQ_run_trk; | ||
687 | u_char SubQ_whatisthis; | ||
688 | |||
689 | u_char UPC_ctl_adr; | ||
690 | u_char UPC_buf[7]; | ||
691 | |||
692 | int frame_size; | ||
693 | int CDsize_frm; | ||
694 | |||
695 | u_char xa_byte; /* 0x20: XA capabilities */ | ||
696 | u_char n_first_track; /* binary */ | ||
697 | u_char n_last_track; /* binary (not bcd), 0x01...0x63 */ | ||
698 | u_int size_msf; /* time of whole CD, position of LeadOut track */ | ||
699 | u_int size_blk; | ||
700 | |||
701 | u_char TocEnt_nixbyte; /* em */ | ||
702 | u_char TocEnt_ctl_adr; | ||
703 | u_char TocEnt_number; | ||
704 | u_char TocEnt_format; /* em */ | ||
705 | u_int TocEnt_address; | ||
706 | #ifdef SAFE_MIXED | ||
707 | char has_data; | ||
708 | #endif /* SAFE_MIXED */ | ||
709 | u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */ | ||
710 | |||
711 | struct { | ||
712 | u_char nixbyte; /* em */ | ||
713 | u_char ctl_adr; /* 0x4x: data, 0x0x: audio */ | ||
714 | u_char number; | ||
715 | u_char format; /* em */ /* 0x00: lba, 0x01: msf */ | ||
716 | u_int address; | ||
717 | } TocBuffer[MAX_TRACKS+1]; /* last entry faked */ | ||
718 | |||
719 | int in_SpinUp; /* CR-52x test flag */ | ||
720 | int n_bytes; /* TEAC awaited response count */ | ||
721 | u_char error_state, b3, b4; /* TEAC command error state */ | ||
722 | u_char f_drv_error; /* TEAC command error flag */ | ||
723 | u_char speed_byte; | ||
724 | int frmsiz; | ||
725 | u_char f_XA; /* 1: XA */ | ||
726 | u_char type_byte; /* 0, 1, 3 */ | ||
727 | u_char mode_xb_6; | ||
728 | u_char mode_yb_7; | ||
729 | u_char mode_xb_8; | ||
730 | u_char delay; | ||
731 | struct cdrom_device_info *sbpcd_infop; | ||
732 | struct gendisk *disk; | ||
733 | } D_S[NR_SBPCD]; | ||
734 | |||
735 | static struct sbpcd_drive *current_drive = D_S; | ||
736 | |||
737 | /* | ||
738 | * drive space ends here (needed separate for each unit) | ||
739 | */ | ||
740 | /*==========================================================================*/ | ||
741 | #if 0 | ||
742 | unsigned long cli_sti; /* for saving the processor flags */ | ||
743 | #endif | ||
744 | /*==========================================================================*/ | ||
745 | static struct timer_list delay_timer = | ||
746 | TIMER_INITIALIZER(mark_timeout_delay, 0, 0); | ||
747 | static struct timer_list data_timer = | ||
748 | TIMER_INITIALIZER(mark_timeout_data, 0, 0); | ||
749 | #if 0 | ||
750 | static struct timer_list audio_timer = | ||
751 | TIMER_INITIALIZER(mark_timeout_audio, 0, 0); | ||
752 | #endif | ||
753 | /*==========================================================================*/ | ||
754 | /* | ||
755 | * DDI interface | ||
756 | */ | ||
757 | static void msg(int level, const char *fmt, ...) | ||
758 | { | ||
759 | #if DISTRIBUTION | ||
760 | #define MSG_LEVEL KERN_NOTICE | ||
761 | #else | ||
762 | #define MSG_LEVEL KERN_INFO | ||
763 | #endif /* DISTRIBUTION */ | ||
764 | |||
765 | char buf[256]; | ||
766 | va_list args; | ||
767 | |||
768 | if (!(sbpcd_debug&(1<<level))) return; | ||
769 | |||
770 | msgnum++; | ||
771 | if (msgnum>99) msgnum=0; | ||
772 | sprintf(buf, MSG_LEVEL "%s-%d [%02d]: ", major_name, current_drive - D_S, msgnum); | ||
773 | va_start(args, fmt); | ||
774 | vsprintf(&buf[18], fmt, args); | ||
775 | va_end(args); | ||
776 | printk(buf); | ||
777 | #if KLOGD_PAUSE | ||
778 | sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ | ||
779 | #endif /* KLOGD_PAUSE */ | ||
780 | return; | ||
781 | } | ||
782 | /*==========================================================================*/ | ||
783 | /* | ||
784 | * DDI interface: runtime trace bit pattern maintenance | ||
785 | */ | ||
786 | static int sbpcd_dbg_ioctl(unsigned long arg, int level) | ||
787 | { | ||
788 | switch(arg) | ||
789 | { | ||
790 | case 0: /* OFF */ | ||
791 | sbpcd_debug = DBG_INF; | ||
792 | break; | ||
793 | |||
794 | default: | ||
795 | if (arg>=128) sbpcd_debug &= ~(1<<(arg-128)); | ||
796 | else sbpcd_debug |= (1<<arg); | ||
797 | } | ||
798 | return (arg); | ||
799 | } | ||
800 | /*==========================================================================*/ | ||
801 | static void mark_timeout_delay(u_long i) | ||
802 | { | ||
803 | timed_out_delay=1; | ||
804 | #if 0 | ||
805 | msg(DBG_TIM,"delay timer expired.\n"); | ||
806 | #endif | ||
807 | } | ||
808 | /*==========================================================================*/ | ||
809 | static void mark_timeout_data(u_long i) | ||
810 | { | ||
811 | timed_out_data=1; | ||
812 | #if 0 | ||
813 | msg(DBG_TIM,"data timer expired.\n"); | ||
814 | #endif | ||
815 | } | ||
816 | /*==========================================================================*/ | ||
817 | #if 0 | ||
818 | static void mark_timeout_audio(u_long i) | ||
819 | { | ||
820 | timed_out_audio=1; | ||
821 | #if 0 | ||
822 | msg(DBG_TIM,"audio timer expired.\n"); | ||
823 | #endif | ||
824 | } | ||
825 | #endif | ||
826 | /*==========================================================================*/ | ||
827 | /* | ||
828 | * Wait a little while (used for polling the drive). | ||
829 | */ | ||
830 | static void sbp_sleep(u_int time) | ||
831 | { | ||
832 | sti(); | ||
833 | current->state = TASK_INTERRUPTIBLE; | ||
834 | schedule_timeout(time); | ||
835 | sti(); | ||
836 | } | ||
837 | /*==========================================================================*/ | ||
838 | #define RETURN_UP(rc) {up(&ioctl_read_sem); return(rc);} | ||
839 | /*==========================================================================*/ | ||
840 | /* | ||
841 | * convert logical_block_address to m-s-f_number (3 bytes only) | ||
842 | */ | ||
843 | static INLINE void lba2msf(int lba, u_char *msf) | ||
844 | { | ||
845 | lba += CD_MSF_OFFSET; | ||
846 | msf[0] = lba / (CD_SECS*CD_FRAMES); | ||
847 | lba %= CD_SECS*CD_FRAMES; | ||
848 | msf[1] = lba / CD_FRAMES; | ||
849 | msf[2] = lba % CD_FRAMES; | ||
850 | } | ||
851 | /*==========================================================================*/ | ||
852 | /*==========================================================================*/ | ||
853 | /* | ||
854 | * convert msf-bin to msf-bcd | ||
855 | */ | ||
856 | static INLINE void bin2bcdx(u_char *p) /* must work only up to 75 or 99 */ | ||
857 | { | ||
858 | *p=((*p/10)<<4)|(*p%10); | ||
859 | } | ||
860 | /*==========================================================================*/ | ||
861 | static INLINE u_int blk2msf(u_int blk) | ||
862 | { | ||
863 | MSF msf; | ||
864 | u_int mm; | ||
865 | |||
866 | msf.c[3] = 0; | ||
867 | msf.c[2] = (blk + CD_MSF_OFFSET) / (CD_SECS * CD_FRAMES); | ||
868 | mm = (blk + CD_MSF_OFFSET) % (CD_SECS * CD_FRAMES); | ||
869 | msf.c[1] = mm / CD_FRAMES; | ||
870 | msf.c[0] = mm % CD_FRAMES; | ||
871 | return (msf.n); | ||
872 | } | ||
873 | /*==========================================================================*/ | ||
874 | static INLINE u_int make16(u_char rh, u_char rl) | ||
875 | { | ||
876 | return ((rh<<8)|rl); | ||
877 | } | ||
878 | /*==========================================================================*/ | ||
879 | static INLINE u_int make32(u_int rh, u_int rl) | ||
880 | { | ||
881 | return ((rh<<16)|rl); | ||
882 | } | ||
883 | /*==========================================================================*/ | ||
884 | static INLINE u_char swap_nibbles(u_char i) | ||
885 | { | ||
886 | return ((i<<4)|(i>>4)); | ||
887 | } | ||
888 | /*==========================================================================*/ | ||
889 | static INLINE u_char byt2bcd(u_char i) | ||
890 | { | ||
891 | return (((i/10)<<4)+i%10); | ||
892 | } | ||
893 | /*==========================================================================*/ | ||
894 | static INLINE u_char bcd2bin(u_char bcd) | ||
895 | { | ||
896 | return ((bcd>>4)*10+(bcd&0x0F)); | ||
897 | } | ||
898 | /*==========================================================================*/ | ||
899 | static INLINE int msf2blk(int msfx) | ||
900 | { | ||
901 | MSF msf; | ||
902 | int i; | ||
903 | |||
904 | msf.n=msfx; | ||
905 | i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_MSF_OFFSET; | ||
906 | if (i<0) return (0); | ||
907 | return (i); | ||
908 | } | ||
909 | /*==========================================================================*/ | ||
910 | /* | ||
911 | * convert m-s-f_number (3 bytes only) to logical_block_address | ||
912 | */ | ||
913 | static INLINE int msf2lba(u_char *msf) | ||
914 | { | ||
915 | int i; | ||
916 | |||
917 | i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_MSF_OFFSET; | ||
918 | if (i<0) return (0); | ||
919 | return (i); | ||
920 | } | ||
921 | /*==========================================================================*/ | ||
922 | /* evaluate cc_ReadError code */ | ||
923 | static int sta2err(int sta) | ||
924 | { | ||
925 | if (famT_drive) | ||
926 | { | ||
927 | if (sta==0x00) return (0); | ||
928 | if (sta==0x01) return (-604); /* CRC error */ | ||
929 | if (sta==0x02) return (-602); /* drive not ready */ | ||
930 | if (sta==0x03) return (-607); /* unknown media */ | ||
931 | if (sta==0x04) return (-612); /* general failure */ | ||
932 | if (sta==0x05) return (0); | ||
933 | if (sta==0x06) return (-ERR_DISKCHANGE); /* disk change */ | ||
934 | if (sta==0x0b) return (-612); /* general failure */ | ||
935 | if (sta==0xff) return (-612); /* general failure */ | ||
936 | return (0); | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | if (sta<=2) return (sta); | ||
941 | if (sta==0x05) return (-604); /* CRC error */ | ||
942 | if (sta==0x06) return (-606); /* seek error */ | ||
943 | if (sta==0x0d) return (-606); /* seek error */ | ||
944 | if (sta==0x0e) return (-603); /* unknown command */ | ||
945 | if (sta==0x14) return (-603); /* unknown command */ | ||
946 | if (sta==0x0c) return (-611); /* read fault */ | ||
947 | if (sta==0x0f) return (-611); /* read fault */ | ||
948 | if (sta==0x10) return (-611); /* read fault */ | ||
949 | if (sta>=0x16) return (-612); /* general failure */ | ||
950 | if (sta==0x11) return (-ERR_DISKCHANGE); /* disk change (LCS: removed) */ | ||
951 | if (famL_drive) | ||
952 | if (sta==0x12) return (-ERR_DISKCHANGE); /* disk change (inserted) */ | ||
953 | return (-602); /* drive not ready */ | ||
954 | } | ||
955 | } | ||
956 | /*==========================================================================*/ | ||
957 | static INLINE void clr_cmdbuf(void) | ||
958 | { | ||
959 | int i; | ||
960 | |||
961 | for (i=0;i<10;i++) drvcmd[i]=0; | ||
962 | cmd_type=0; | ||
963 | } | ||
964 | /*==========================================================================*/ | ||
965 | static void flush_status(void) | ||
966 | { | ||
967 | int i; | ||
968 | |||
969 | sbp_sleep(15*HZ/10); | ||
970 | for (i=maxtim_data;i!=0;i--) inb(CDi_status); | ||
971 | } | ||
972 | /*====================================================================*/ | ||
973 | /* | ||
974 | * CDi status loop for Teac CD-55A (Rob Riggs) | ||
975 | * | ||
976 | * This is needed because for some strange reason | ||
977 | * the CD-55A can take a real long time to give a | ||
978 | * status response. This seems to happen after we | ||
979 | * issue a READ command where a long seek is involved. | ||
980 | * | ||
981 | * I tried to ensure that we get max throughput with | ||
982 | * minimal busy waiting. We busy wait at first, then | ||
983 | * "switch gears" and start sleeping. We sleep for | ||
984 | * longer periods of time the longer we wait. | ||
985 | * | ||
986 | */ | ||
987 | static int CDi_stat_loop_T(void) | ||
988 | { | ||
989 | int i, gear=1; | ||
990 | u_long timeout_1, timeout_2, timeout_3, timeout_4; | ||
991 | |||
992 | timeout_1 = jiffies + HZ / 50; /* sbp_sleep(0) for a short period */ | ||
993 | timeout_2 = jiffies + HZ / 5; /* nap for no more than 200ms */ | ||
994 | timeout_3 = jiffies + 5 * HZ; /* sleep for up to 5s */ | ||
995 | timeout_4 = jiffies + 45 * HZ; /* long sleep for up to 45s. */ | ||
996 | do | ||
997 | { | ||
998 | i = inb(CDi_status); | ||
999 | if (!(i&s_not_data_ready)) return (i); | ||
1000 | if (!(i&s_not_result_ready)) return (i); | ||
1001 | switch(gear) | ||
1002 | { | ||
1003 | case 4: | ||
1004 | sbp_sleep(HZ); | ||
1005 | if (time_after(jiffies, timeout_4)) gear++; | ||
1006 | msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n"); | ||
1007 | break; | ||
1008 | case 3: | ||
1009 | sbp_sleep(HZ/10); | ||
1010 | if (time_after(jiffies, timeout_3)) gear++; | ||
1011 | break; | ||
1012 | case 2: | ||
1013 | sbp_sleep(HZ/100); | ||
1014 | if (time_after(jiffies, timeout_2)) gear++; | ||
1015 | break; | ||
1016 | case 1: | ||
1017 | sbp_sleep(0); | ||
1018 | if (time_after(jiffies, timeout_1)) gear++; | ||
1019 | } | ||
1020 | } while (gear < 5); | ||
1021 | return -1; | ||
1022 | } | ||
1023 | /*==========================================================================*/ | ||
1024 | static int CDi_stat_loop(void) | ||
1025 | { | ||
1026 | int i,j; | ||
1027 | |||
1028 | for(timeout = jiffies + 10*HZ, i=maxtim_data; time_before(jiffies, timeout); ) | ||
1029 | { | ||
1030 | for ( ;i!=0;i--) | ||
1031 | { | ||
1032 | j=inb(CDi_status); | ||
1033 | if (!(j&s_not_data_ready)) return (j); | ||
1034 | if (!(j&s_not_result_ready)) return (j); | ||
1035 | if (fam0L_drive) if (j&s_attention) return (j); | ||
1036 | } | ||
1037 | sbp_sleep(1); | ||
1038 | i = 1; | ||
1039 | } | ||
1040 | msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__); | ||
1041 | return (-1); | ||
1042 | } | ||
1043 | /*==========================================================================*/ | ||
1044 | #if 00000 | ||
1045 | /*==========================================================================*/ | ||
1046 | static int tst_DataReady(void) | ||
1047 | { | ||
1048 | int i; | ||
1049 | |||
1050 | i=inb(CDi_status); | ||
1051 | if (i&s_not_data_ready) return (0); | ||
1052 | return (1); | ||
1053 | } | ||
1054 | /*==========================================================================*/ | ||
1055 | static int tst_ResultReady(void) | ||
1056 | { | ||
1057 | int i; | ||
1058 | |||
1059 | i=inb(CDi_status); | ||
1060 | if (i&s_not_result_ready) return (0); | ||
1061 | return (1); | ||
1062 | } | ||
1063 | /*==========================================================================*/ | ||
1064 | static int tst_Attention(void) | ||
1065 | { | ||
1066 | int i; | ||
1067 | |||
1068 | i=inb(CDi_status); | ||
1069 | if (i&s_attention) return (1); | ||
1070 | return (0); | ||
1071 | } | ||
1072 | /*==========================================================================*/ | ||
1073 | #endif | ||
1074 | /*==========================================================================*/ | ||
1075 | static int ResponseInfo(void) | ||
1076 | { | ||
1077 | int i,j,st=0; | ||
1078 | u_long timeout; | ||
1079 | |||
1080 | for (i=0,timeout=jiffies+HZ;i<response_count;i++) | ||
1081 | { | ||
1082 | for (j=maxtim_data; ; ) | ||
1083 | { | ||
1084 | for ( ;j!=0;j-- ) | ||
1085 | { | ||
1086 | st=inb(CDi_status); | ||
1087 | if (!(st&s_not_result_ready)) break; | ||
1088 | } | ||
1089 | if ((j!=0)||time_after_eq(jiffies, timeout)) break; | ||
1090 | sbp_sleep(1); | ||
1091 | j = 1; | ||
1092 | } | ||
1093 | if (time_after_eq(jiffies, timeout)) break; | ||
1094 | infobuf[i]=inb(CDi_info); | ||
1095 | } | ||
1096 | #if 000 | ||
1097 | while (!(inb(CDi_status)&s_not_result_ready)) | ||
1098 | { | ||
1099 | infobuf[i++]=inb(CDi_info); | ||
1100 | } | ||
1101 | j=i-response_count; | ||
1102 | if (j>0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); | ||
1103 | #endif /* 000 */ | ||
1104 | for (j=0;j<i;j++) | ||
1105 | sprintf(&msgbuf[j*3]," %02X",infobuf[j]); | ||
1106 | msgbuf[j*3]=0; | ||
1107 | msg(DBG_CMD,"ResponseInfo:%s (%d,%d)\n",msgbuf,response_count,i); | ||
1108 | j=response_count-i; | ||
1109 | if (j>0) return (-j); | ||
1110 | else return (i); | ||
1111 | } | ||
1112 | /*==========================================================================*/ | ||
1113 | static void EvaluateStatus(int st) | ||
1114 | { | ||
1115 | current_drive->status_bits=0; | ||
1116 | if (fam1_drive) current_drive->status_bits=st|p_success; | ||
1117 | else if (fam0_drive) | ||
1118 | { | ||
1119 | if (st&p_caddin_old) current_drive->status_bits |= p_door_closed|p_caddy_in; | ||
1120 | if (st&p_spinning) current_drive->status_bits |= p_spinning; | ||
1121 | if (st&p_check) current_drive->status_bits |= p_check; | ||
1122 | if (st&p_success_old) current_drive->status_bits |= p_success; | ||
1123 | if (st&p_busy_old) current_drive->status_bits |= p_busy_new; | ||
1124 | if (st&p_disk_ok) current_drive->status_bits |= p_disk_ok; | ||
1125 | } | ||
1126 | else if (famLV_drive) | ||
1127 | { | ||
1128 | current_drive->status_bits |= p_success; | ||
1129 | if (st&p_caddin_old) current_drive->status_bits |= p_disk_ok|p_caddy_in; | ||
1130 | if (st&p_spinning) current_drive->status_bits |= p_spinning; | ||
1131 | if (st&p_check) current_drive->status_bits |= p_check; | ||
1132 | if (st&p_busy_old) current_drive->status_bits |= p_busy_new; | ||
1133 | if (st&p_lcs_door_closed) current_drive->status_bits |= p_door_closed; | ||
1134 | if (st&p_lcs_door_locked) current_drive->status_bits |= p_door_locked; | ||
1135 | } | ||
1136 | else if (fam2_drive) | ||
1137 | { | ||
1138 | current_drive->status_bits |= p_success; | ||
1139 | if (st&p2_check) current_drive->status_bits |= p1_check; | ||
1140 | if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; | ||
1141 | if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; | ||
1142 | if (st&p2_busy1) current_drive->status_bits |= p1_busy; | ||
1143 | if (st&p2_busy2) current_drive->status_bits |= p1_busy; | ||
1144 | if (st&p2_spinning) current_drive->status_bits |= p1_spinning; | ||
1145 | if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; | ||
1146 | if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; | ||
1147 | } | ||
1148 | else if (famT_drive) | ||
1149 | { | ||
1150 | return; /* still needs to get coded */ | ||
1151 | current_drive->status_bits |= p_success; | ||
1152 | if (st&p2_check) current_drive->status_bits |= p1_check; | ||
1153 | if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; | ||
1154 | if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; | ||
1155 | if (st&p2_busy1) current_drive->status_bits |= p1_busy; | ||
1156 | if (st&p2_busy2) current_drive->status_bits |= p1_busy; | ||
1157 | if (st&p2_spinning) current_drive->status_bits |= p1_spinning; | ||
1158 | if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; | ||
1159 | if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; | ||
1160 | } | ||
1161 | return; | ||
1162 | } | ||
1163 | /*==========================================================================*/ | ||
1164 | static int cmd_out_T(void); | ||
1165 | |||
1166 | static int get_state_T(void) | ||
1167 | { | ||
1168 | int i; | ||
1169 | |||
1170 | clr_cmdbuf(); | ||
1171 | current_drive->n_bytes=1; | ||
1172 | drvcmd[0]=CMDT_STATUS; | ||
1173 | i=cmd_out_T(); | ||
1174 | if (i>=0) i=infobuf[0]; | ||
1175 | else | ||
1176 | { | ||
1177 | msg(DBG_TEA,"get_state_T error %d\n", i); | ||
1178 | return (i); | ||
1179 | } | ||
1180 | if (i>=0) | ||
1181 | /* 2: closed, disk in */ | ||
1182 | current_drive->status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok; | ||
1183 | else if (current_drive->error_state==6) | ||
1184 | { | ||
1185 | /* 3: closed, disk in, changed ("06 xx xx") */ | ||
1186 | current_drive->status_bits=p1_door_closed|p1_disk_in; | ||
1187 | current_drive->CD_changed=0xFF; | ||
1188 | current_drive->diskstate_flags &= ~toc_bit; | ||
1189 | } | ||
1190 | else if ((current_drive->error_state!=2)||(current_drive->b3!=0x3A)||(current_drive->b4==0x00)) | ||
1191 | { | ||
1192 | /* 1: closed, no disk ("xx yy zz"or "02 3A 00") */ | ||
1193 | current_drive->status_bits=p1_door_closed; | ||
1194 | current_drive->open_count=0; | ||
1195 | } | ||
1196 | else if (current_drive->b4==0x01) | ||
1197 | { | ||
1198 | /* 0: open ("02 3A 01") */ | ||
1199 | current_drive->status_bits=0; | ||
1200 | current_drive->open_count=0; | ||
1201 | } | ||
1202 | else | ||
1203 | { | ||
1204 | /* 1: closed, no disk ("02 3A xx") */ | ||
1205 | current_drive->status_bits=p1_door_closed; | ||
1206 | current_drive->open_count=0; | ||
1207 | } | ||
1208 | return (current_drive->status_bits); | ||
1209 | } | ||
1210 | /*==========================================================================*/ | ||
1211 | static int ResponseStatus(void) | ||
1212 | { | ||
1213 | int i,j; | ||
1214 | u_long timeout; | ||
1215 | |||
1216 | msg(DBG_STA,"doing ResponseStatus...\n"); | ||
1217 | if (famT_drive) return (get_state_T()); | ||
1218 | if (flags_cmd_out & f_respo3) timeout = jiffies; | ||
1219 | else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ; | ||
1220 | else timeout = jiffies + 4*HZ; | ||
1221 | j=maxtim_8; | ||
1222 | do | ||
1223 | { | ||
1224 | for ( ;j!=0;j--) | ||
1225 | { | ||
1226 | i=inb(CDi_status); | ||
1227 | if (!(i&s_not_result_ready)) break; | ||
1228 | } | ||
1229 | if ((j!=0)||time_after(jiffies, timeout)) break; | ||
1230 | sbp_sleep(1); | ||
1231 | j = 1; | ||
1232 | } | ||
1233 | while (1); | ||
1234 | if (j==0) | ||
1235 | { | ||
1236 | if ((flags_cmd_out & f_respo3) == 0) | ||
1237 | msg(DBG_STA,"ResponseStatus: timeout.\n"); | ||
1238 | current_drive->status_bits=0; | ||
1239 | return (-401); | ||
1240 | } | ||
1241 | i=inb(CDi_info); | ||
1242 | msg(DBG_STA,"ResponseStatus: response %02X.\n", i); | ||
1243 | EvaluateStatus(i); | ||
1244 | msg(DBG_STA,"status_bits=%02X, i=%02X\n",current_drive->status_bits,i); | ||
1245 | return (current_drive->status_bits); | ||
1246 | } | ||
1247 | /*==========================================================================*/ | ||
1248 | static void cc_ReadStatus(void) | ||
1249 | { | ||
1250 | int i; | ||
1251 | |||
1252 | msg(DBG_STA,"giving cc_ReadStatus command\n"); | ||
1253 | if (famT_drive) return; | ||
1254 | SBPCD_CLI; | ||
1255 | if (fam0LV_drive) OUT(CDo_command,CMD0_STATUS); | ||
1256 | else if (fam1_drive) OUT(CDo_command,CMD1_STATUS); | ||
1257 | else if (fam2_drive) OUT(CDo_command,CMD2_STATUS); | ||
1258 | if (!fam0LV_drive) for (i=0;i<6;i++) OUT(CDo_command,0); | ||
1259 | SBPCD_STI; | ||
1260 | } | ||
1261 | /*==========================================================================*/ | ||
1262 | static int cc_ReadError(void) | ||
1263 | { | ||
1264 | int i; | ||
1265 | |||
1266 | clr_cmdbuf(); | ||
1267 | msg(DBG_ERR,"giving cc_ReadError command.\n"); | ||
1268 | if (fam1_drive) | ||
1269 | { | ||
1270 | drvcmd[0]=CMD1_READ_ERR; | ||
1271 | response_count=8; | ||
1272 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1273 | } | ||
1274 | else if (fam0LV_drive) | ||
1275 | { | ||
1276 | drvcmd[0]=CMD0_READ_ERR; | ||
1277 | response_count=6; | ||
1278 | if (famLV_drive) | ||
1279 | flags_cmd_out=f_putcmd; | ||
1280 | else | ||
1281 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus; | ||
1282 | } | ||
1283 | else if (fam2_drive) | ||
1284 | { | ||
1285 | drvcmd[0]=CMD2_READ_ERR; | ||
1286 | response_count=6; | ||
1287 | flags_cmd_out=f_putcmd; | ||
1288 | } | ||
1289 | else if (famT_drive) | ||
1290 | { | ||
1291 | response_count=5; | ||
1292 | drvcmd[0]=CMDT_READ_ERR; | ||
1293 | } | ||
1294 | i=cmd_out(); | ||
1295 | current_drive->error_byte=0; | ||
1296 | msg(DBG_ERR,"cc_ReadError: cmd_out(CMDx_READ_ERR) returns %d (%02X)\n",i,i); | ||
1297 | if (i<0) return (i); | ||
1298 | if (fam0V_drive) i=1; | ||
1299 | else i=2; | ||
1300 | current_drive->error_byte=infobuf[i]; | ||
1301 | msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,current_drive->error_byte,current_drive->error_byte); | ||
1302 | i=sta2err(infobuf[i]); | ||
1303 | if (i==-ERR_DISKCHANGE) | ||
1304 | { | ||
1305 | current_drive->CD_changed=0xFF; | ||
1306 | current_drive->diskstate_flags &= ~toc_bit; | ||
1307 | } | ||
1308 | return (i); | ||
1309 | } | ||
1310 | /*==========================================================================*/ | ||
1311 | static int cc_DriveReset(void); | ||
1312 | |||
1313 | static int cmd_out_T(void) | ||
1314 | { | ||
1315 | #undef CMDT_TRIES | ||
1316 | #define CMDT_TRIES 1000 | ||
1317 | #define TEST_FALSE_FF 1 | ||
1318 | |||
1319 | int i, j, l=0, m, ntries; | ||
1320 | unsigned long flags; | ||
1321 | |||
1322 | current_drive->error_state=0; | ||
1323 | current_drive->b3=0; | ||
1324 | current_drive->b4=0; | ||
1325 | current_drive->f_drv_error=0; | ||
1326 | for (i=0;i<10;i++) sprintf(&msgbuf[i*3]," %02X",drvcmd[i]); | ||
1327 | msgbuf[i*3]=0; | ||
1328 | msg(DBG_CMD,"cmd_out_T:%s\n",msgbuf); | ||
1329 | |||
1330 | OUT(CDo_sel_i_d,0); | ||
1331 | OUT(CDo_enable,current_drive->drv_sel); | ||
1332 | i=inb(CDi_status); | ||
1333 | do_16bit=0; | ||
1334 | if ((f_16bit)&&(!(i&0x80))) | ||
1335 | { | ||
1336 | do_16bit=1; | ||
1337 | msg(DBG_TEA,"cmd_out_T: do_16bit set.\n"); | ||
1338 | } | ||
1339 | if (!(i&s_not_result_ready)) | ||
1340 | do | ||
1341 | { | ||
1342 | j=inb(CDi_info); | ||
1343 | i=inb(CDi_status); | ||
1344 | sbp_sleep(0); | ||
1345 | msg(DBG_TEA,"cmd_out_T: spurious !s_not_result_ready. (%02X)\n", j); | ||
1346 | } | ||
1347 | while (!(i&s_not_result_ready)); | ||
1348 | save_flags(flags); cli(); | ||
1349 | for (i=0;i<10;i++) OUT(CDo_command,drvcmd[i]); | ||
1350 | restore_flags(flags); | ||
1351 | for (ntries=CMDT_TRIES;ntries>0;ntries--) | ||
1352 | { | ||
1353 | if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ | ||
1354 | #if 01 | ||
1355 | OUT(CDo_sel_i_d,1); | ||
1356 | #endif /* 01 */ | ||
1357 | if (teac==2) | ||
1358 | { | ||
1359 | if ((i=CDi_stat_loop_T()) == -1) break; | ||
1360 | } | ||
1361 | else | ||
1362 | { | ||
1363 | #if 0 | ||
1364 | OUT(CDo_sel_i_d,1); | ||
1365 | #endif /* 0 */ | ||
1366 | i=inb(CDi_status); | ||
1367 | } | ||
1368 | if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ | ||
1369 | { | ||
1370 | OUT(CDo_sel_i_d,1); | ||
1371 | if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ | ||
1372 | if (drvcmd[0]==CMDT_DISKINFO) | ||
1373 | { | ||
1374 | l=0; | ||
1375 | do | ||
1376 | { | ||
1377 | if (do_16bit) | ||
1378 | { | ||
1379 | i=inw(CDi_data); | ||
1380 | infobuf[l++]=i&0x0ff; | ||
1381 | infobuf[l++]=i>>8; | ||
1382 | #if TEST_FALSE_FF | ||
1383 | if ((l==2)&&(infobuf[0]==0x0ff)) | ||
1384 | { | ||
1385 | infobuf[0]=infobuf[1]; | ||
1386 | l=1; | ||
1387 | msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n"); | ||
1388 | } | ||
1389 | #endif /* TEST_FALSE_FF */ | ||
1390 | } | ||
1391 | else infobuf[l++]=inb(CDi_data); | ||
1392 | i=inb(CDi_status); | ||
1393 | } | ||
1394 | while (!(i&s_not_data_ready)); | ||
1395 | for (j=0;j<l;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]); | ||
1396 | msgbuf[j*3]=0; | ||
1397 | msg(DBG_CMD,"cmd_out_T data response:%s\n", msgbuf); | ||
1398 | } | ||
1399 | else | ||
1400 | { | ||
1401 | msg(DBG_TEA,"cmd_out_T: data response with cmd_%02X!\n", | ||
1402 | drvcmd[0]); | ||
1403 | j=0; | ||
1404 | do | ||
1405 | { | ||
1406 | if (do_16bit) i=inw(CDi_data); | ||
1407 | else i=inb(CDi_data); | ||
1408 | j++; | ||
1409 | i=inb(CDi_status); | ||
1410 | } | ||
1411 | while (!(i&s_not_data_ready)); | ||
1412 | msg(DBG_TEA,"cmd_out_T: data response: discarded %d bytes/words.\n", j); | ||
1413 | fatal_err++; | ||
1414 | } | ||
1415 | } | ||
1416 | i=inb(CDi_status); | ||
1417 | if (!(i&s_not_result_ready)) | ||
1418 | { | ||
1419 | OUT(CDo_sel_i_d,0); | ||
1420 | if (drvcmd[0]==CMDT_DISKINFO) m=l; | ||
1421 | else m=0; | ||
1422 | do | ||
1423 | { | ||
1424 | infobuf[m++]=inb(CDi_info); | ||
1425 | i=inb(CDi_status); | ||
1426 | } | ||
1427 | while (!(i&s_not_result_ready)); | ||
1428 | for (j=0;j<m;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]); | ||
1429 | msgbuf[j*3]=0; | ||
1430 | msg(DBG_CMD,"cmd_out_T info response:%s\n", msgbuf); | ||
1431 | if (drvcmd[0]==CMDT_DISKINFO) | ||
1432 | { | ||
1433 | infobuf[0]=infobuf[l]; | ||
1434 | if (infobuf[0]!=0x02) return (l); /* data length */ | ||
1435 | } | ||
1436 | else if (infobuf[0]!=0x02) return (m); /* info length */ | ||
1437 | do | ||
1438 | { | ||
1439 | ++recursion; | ||
1440 | if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (%02X): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", drvcmd[0], recursion); | ||
1441 | clr_cmdbuf(); | ||
1442 | drvcmd[0]=CMDT_READ_ERR; | ||
1443 | j=cmd_out_T(); /* !!! recursive here !!! */ | ||
1444 | --recursion; | ||
1445 | sbp_sleep(1); | ||
1446 | } | ||
1447 | while (j<0); | ||
1448 | current_drive->error_state=infobuf[2]; | ||
1449 | current_drive->b3=infobuf[3]; | ||
1450 | current_drive->b4=infobuf[4]; | ||
1451 | if (current_drive->f_drv_error) | ||
1452 | { | ||
1453 | current_drive->f_drv_error=0; | ||
1454 | cc_DriveReset(); | ||
1455 | current_drive->error_state=2; | ||
1456 | } | ||
1457 | return (-current_drive->error_state-400); | ||
1458 | } | ||
1459 | if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ | ||
1460 | if ((teac==0)||(ntries<(CMDT_TRIES-5))) sbp_sleep(HZ/10); | ||
1461 | else sbp_sleep(HZ/100); | ||
1462 | if (ntries>(CMDT_TRIES-50)) continue; | ||
1463 | msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1); | ||
1464 | } | ||
1465 | current_drive->f_drv_error=1; | ||
1466 | cc_DriveReset(); | ||
1467 | current_drive->error_state=2; | ||
1468 | return (-99); | ||
1469 | } | ||
1470 | /*==========================================================================*/ | ||
1471 | static int cmd_out(void) | ||
1472 | { | ||
1473 | int i=0; | ||
1474 | |||
1475 | if (famT_drive) return(cmd_out_T()); | ||
1476 | |||
1477 | if (flags_cmd_out&f_putcmd) | ||
1478 | { | ||
1479 | unsigned long flags; | ||
1480 | for (i=0;i<7;i++) | ||
1481 | sprintf(&msgbuf[i*3], " %02X", drvcmd[i]); | ||
1482 | msgbuf[i*3]=0; | ||
1483 | msg(DBG_CMD,"cmd_out:%s\n", msgbuf); | ||
1484 | save_flags(flags); cli(); | ||
1485 | for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); | ||
1486 | restore_flags(flags); | ||
1487 | } | ||
1488 | if (response_count!=0) | ||
1489 | { | ||
1490 | if (cmd_type!=0) | ||
1491 | { | ||
1492 | if (sbpro_type==1) OUT(CDo_sel_i_d,1); | ||
1493 | msg(DBG_INF,"misleaded to try ResponseData.\n"); | ||
1494 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
1495 | return (-22); | ||
1496 | } | ||
1497 | else i=ResponseInfo(); | ||
1498 | if (i<0) return (i); | ||
1499 | } | ||
1500 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to CDi_stat_loop.\n"); | ||
1501 | if (flags_cmd_out&f_lopsta) | ||
1502 | { | ||
1503 | i=CDi_stat_loop(); | ||
1504 | if ((i<0)||!(i&s_attention)) return (-8); | ||
1505 | } | ||
1506 | if (!(flags_cmd_out&f_getsta)) goto LOC_229; | ||
1507 | |||
1508 | LOC_228: | ||
1509 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadStatus.\n"); | ||
1510 | cc_ReadStatus(); | ||
1511 | |||
1512 | LOC_229: | ||
1513 | if (flags_cmd_out&f_ResponseStatus) | ||
1514 | { | ||
1515 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to ResponseStatus.\n"); | ||
1516 | i=ResponseStatus(); | ||
1517 | /* builds status_bits, returns orig. status or p_busy_new */ | ||
1518 | if (i<0) return (i); | ||
1519 | if (flags_cmd_out&(f_bit1|f_wait_if_busy)) | ||
1520 | { | ||
1521 | if (!st_check) | ||
1522 | { | ||
1523 | if ((flags_cmd_out&f_bit1)&&(i&p_success)) goto LOC_232; | ||
1524 | if ((!(flags_cmd_out&f_wait_if_busy))||(!st_busy)) goto LOC_228; | ||
1525 | } | ||
1526 | } | ||
1527 | } | ||
1528 | LOC_232: | ||
1529 | if (!(flags_cmd_out&f_obey_p_check)) return (0); | ||
1530 | if (!st_check) return (0); | ||
1531 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadError.\n"); | ||
1532 | i=cc_ReadError(); | ||
1533 | if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cmd_out OK.\n"); | ||
1534 | msg(DBG_000,"cmd_out: cc_ReadError=%d\n", i); | ||
1535 | return (i); | ||
1536 | } | ||
1537 | /*==========================================================================*/ | ||
1538 | static int cc_Seek(u_int pos, char f_blk_msf) | ||
1539 | { | ||
1540 | int i; | ||
1541 | |||
1542 | clr_cmdbuf(); | ||
1543 | if (f_blk_msf>1) return (-3); | ||
1544 | if (fam0V_drive) | ||
1545 | { | ||
1546 | drvcmd[0]=CMD0_SEEK; | ||
1547 | if (f_blk_msf==1) pos=msf2blk(pos); | ||
1548 | drvcmd[2]=(pos>>16)&0x00FF; | ||
1549 | drvcmd[3]=(pos>>8)&0x00FF; | ||
1550 | drvcmd[4]=pos&0x00FF; | ||
1551 | if (fam0_drive) | ||
1552 | flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | | ||
1553 | f_ResponseStatus | f_obey_p_check | f_bit1; | ||
1554 | else | ||
1555 | flags_cmd_out = f_putcmd; | ||
1556 | } | ||
1557 | else if (fam1L_drive) | ||
1558 | { | ||
1559 | drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */ | ||
1560 | if (f_blk_msf==0) pos=blk2msf(pos); | ||
1561 | drvcmd[1]=(pos>>16)&0x00FF; | ||
1562 | drvcmd[2]=(pos>>8)&0x00FF; | ||
1563 | drvcmd[3]=pos&0x00FF; | ||
1564 | if (famL_drive) | ||
1565 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1566 | else | ||
1567 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1568 | } | ||
1569 | else if (fam2_drive) | ||
1570 | { | ||
1571 | drvcmd[0]=CMD2_SEEK; | ||
1572 | if (f_blk_msf==0) pos=blk2msf(pos); | ||
1573 | drvcmd[2]=(pos>>24)&0x00FF; | ||
1574 | drvcmd[3]=(pos>>16)&0x00FF; | ||
1575 | drvcmd[4]=(pos>>8)&0x00FF; | ||
1576 | drvcmd[5]=pos&0x00FF; | ||
1577 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1578 | } | ||
1579 | else if (famT_drive) | ||
1580 | { | ||
1581 | drvcmd[0]=CMDT_SEEK; | ||
1582 | if (f_blk_msf==1) pos=msf2blk(pos); | ||
1583 | drvcmd[2]=(pos>>24)&0x00FF; | ||
1584 | drvcmd[3]=(pos>>16)&0x00FF; | ||
1585 | drvcmd[4]=(pos>>8)&0x00FF; | ||
1586 | drvcmd[5]=pos&0x00FF; | ||
1587 | current_drive->n_bytes=1; | ||
1588 | } | ||
1589 | response_count=0; | ||
1590 | i=cmd_out(); | ||
1591 | return (i); | ||
1592 | } | ||
1593 | /*==========================================================================*/ | ||
1594 | static int cc_SpinUp(void) | ||
1595 | { | ||
1596 | int i; | ||
1597 | |||
1598 | msg(DBG_SPI,"SpinUp.\n"); | ||
1599 | current_drive->in_SpinUp = 1; | ||
1600 | clr_cmdbuf(); | ||
1601 | if (fam0LV_drive) | ||
1602 | { | ||
1603 | drvcmd[0]=CMD0_SPINUP; | ||
1604 | if (fam0L_drive) | ||
1605 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| | ||
1606 | f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1607 | else | ||
1608 | flags_cmd_out=f_putcmd; | ||
1609 | } | ||
1610 | else if (fam1_drive) | ||
1611 | { | ||
1612 | drvcmd[0]=CMD1_SPINUP; | ||
1613 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1614 | } | ||
1615 | else if (fam2_drive) | ||
1616 | { | ||
1617 | drvcmd[0]=CMD2_TRAY_CTL; | ||
1618 | drvcmd[4]=0x01; /* "spinup" */ | ||
1619 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1620 | } | ||
1621 | else if (famT_drive) | ||
1622 | { | ||
1623 | drvcmd[0]=CMDT_TRAY_CTL; | ||
1624 | drvcmd[4]=0x03; /* "insert", it hopefully spins the drive up */ | ||
1625 | } | ||
1626 | response_count=0; | ||
1627 | i=cmd_out(); | ||
1628 | current_drive->in_SpinUp = 0; | ||
1629 | return (i); | ||
1630 | } | ||
1631 | /*==========================================================================*/ | ||
1632 | static int cc_SpinDown(void) | ||
1633 | { | ||
1634 | int i; | ||
1635 | |||
1636 | if (fam0_drive) return (0); | ||
1637 | clr_cmdbuf(); | ||
1638 | response_count=0; | ||
1639 | if (fam1_drive) | ||
1640 | { | ||
1641 | drvcmd[0]=CMD1_SPINDOWN; | ||
1642 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
1643 | } | ||
1644 | else if (fam2_drive) | ||
1645 | { | ||
1646 | drvcmd[0]=CMD2_TRAY_CTL; | ||
1647 | drvcmd[4]=0x02; /* "eject" */ | ||
1648 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1649 | } | ||
1650 | else if (famL_drive) | ||
1651 | { | ||
1652 | drvcmd[0]=CMDL_SPINDOWN; | ||
1653 | drvcmd[1]=1; | ||
1654 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1655 | } | ||
1656 | else if (famV_drive) | ||
1657 | { | ||
1658 | drvcmd[0]=CMDV_SPINDOWN; | ||
1659 | flags_cmd_out=f_putcmd; | ||
1660 | } | ||
1661 | else if (famT_drive) | ||
1662 | { | ||
1663 | drvcmd[0]=CMDT_TRAY_CTL; | ||
1664 | drvcmd[4]=0x02; /* "eject" */ | ||
1665 | } | ||
1666 | i=cmd_out(); | ||
1667 | return (i); | ||
1668 | } | ||
1669 | /*==========================================================================*/ | ||
1670 | static int cc_get_mode_T(void) | ||
1671 | { | ||
1672 | int i; | ||
1673 | |||
1674 | clr_cmdbuf(); | ||
1675 | response_count=10; | ||
1676 | drvcmd[0]=CMDT_GETMODE; | ||
1677 | drvcmd[4]=response_count; | ||
1678 | i=cmd_out_T(); | ||
1679 | return (i); | ||
1680 | } | ||
1681 | /*==========================================================================*/ | ||
1682 | static int cc_set_mode_T(void) | ||
1683 | { | ||
1684 | int i; | ||
1685 | |||
1686 | clr_cmdbuf(); | ||
1687 | response_count=1; | ||
1688 | drvcmd[0]=CMDT_SETMODE; | ||
1689 | drvcmd[1]=current_drive->speed_byte; | ||
1690 | drvcmd[2]=current_drive->frmsiz>>8; | ||
1691 | drvcmd[3]=current_drive->frmsiz&0x0FF; | ||
1692 | drvcmd[4]=current_drive->f_XA; /* 1: XA */ | ||
1693 | drvcmd[5]=current_drive->type_byte; /* 0, 1, 3 */ | ||
1694 | drvcmd[6]=current_drive->mode_xb_6; | ||
1695 | drvcmd[7]=current_drive->mode_yb_7|current_drive->volume_control; | ||
1696 | drvcmd[8]=current_drive->mode_xb_8; | ||
1697 | drvcmd[9]=current_drive->delay; | ||
1698 | i=cmd_out_T(); | ||
1699 | return (i); | ||
1700 | } | ||
1701 | /*==========================================================================*/ | ||
1702 | static int cc_prep_mode_T(void) | ||
1703 | { | ||
1704 | int i, j; | ||
1705 | |||
1706 | i=cc_get_mode_T(); | ||
1707 | if (i<0) return (i); | ||
1708 | for (i=0;i<10;i++) | ||
1709 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
1710 | msgbuf[i*3]=0; | ||
1711 | msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); | ||
1712 | current_drive->speed_byte=0x02; /* 0x02: auto quad, 0x82: quad, 0x81: double, 0x80: single */ | ||
1713 | current_drive->frmsiz=make16(infobuf[2],infobuf[3]); | ||
1714 | current_drive->f_XA=infobuf[4]; | ||
1715 | if (current_drive->f_XA==0) current_drive->type_byte=0; | ||
1716 | else current_drive->type_byte=1; | ||
1717 | current_drive->mode_xb_6=infobuf[6]; | ||
1718 | current_drive->mode_yb_7=1; | ||
1719 | current_drive->mode_xb_8=infobuf[8]; | ||
1720 | current_drive->delay=0; /* 0, 1, 2, 3 */ | ||
1721 | j=cc_set_mode_T(); | ||
1722 | i=cc_get_mode_T(); | ||
1723 | for (i=0;i<10;i++) | ||
1724 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
1725 | msgbuf[i*3]=0; | ||
1726 | msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); | ||
1727 | return (j); | ||
1728 | } | ||
1729 | /*==========================================================================*/ | ||
1730 | static int cc_SetSpeed(u_char speed, u_char x1, u_char x2) | ||
1731 | { | ||
1732 | int i; | ||
1733 | |||
1734 | if (fam0LV_drive) return (0); | ||
1735 | clr_cmdbuf(); | ||
1736 | response_count=0; | ||
1737 | if (fam1_drive) | ||
1738 | { | ||
1739 | drvcmd[0]=CMD1_SETMODE; | ||
1740 | drvcmd[1]=0x03; | ||
1741 | drvcmd[2]=speed; | ||
1742 | drvcmd[3]=x1; | ||
1743 | drvcmd[4]=x2; | ||
1744 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
1745 | } | ||
1746 | else if (fam2_drive) | ||
1747 | { | ||
1748 | drvcmd[0]=CMD2_SETSPEED; | ||
1749 | if (speed&speed_auto) | ||
1750 | { | ||
1751 | drvcmd[2]=0xFF; | ||
1752 | drvcmd[3]=0xFF; | ||
1753 | } | ||
1754 | else | ||
1755 | { | ||
1756 | drvcmd[2]=0; | ||
1757 | drvcmd[3]=150; | ||
1758 | } | ||
1759 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
1760 | } | ||
1761 | else if (famT_drive) | ||
1762 | { | ||
1763 | return (0); | ||
1764 | } | ||
1765 | i=cmd_out(); | ||
1766 | return (i); | ||
1767 | } | ||
1768 | /*==========================================================================*/ | ||
1769 | static int cc_SetVolume(void) | ||
1770 | { | ||
1771 | int i; | ||
1772 | u_char channel0,channel1,volume0,volume1; | ||
1773 | u_char control0,value0,control1,value1; | ||
1774 | |||
1775 | current_drive->diskstate_flags &= ~volume_bit; | ||
1776 | clr_cmdbuf(); | ||
1777 | channel0=current_drive->vol_chan0; | ||
1778 | volume0=current_drive->vol_ctrl0; | ||
1779 | channel1=control1=current_drive->vol_chan1; | ||
1780 | volume1=value1=current_drive->vol_ctrl1; | ||
1781 | control0=value0=0; | ||
1782 | |||
1783 | if (famV_drive) return (0); | ||
1784 | |||
1785 | if (((current_drive->drv_options&audio_mono)!=0)&&(current_drive->drv_type>=drv_211)) | ||
1786 | { | ||
1787 | if ((volume0!=0)&&(volume1==0)) | ||
1788 | { | ||
1789 | volume1=volume0; | ||
1790 | channel1=channel0; | ||
1791 | } | ||
1792 | else if ((volume0==0)&&(volume1!=0)) | ||
1793 | { | ||
1794 | volume0=volume1; | ||
1795 | channel0=channel1; | ||
1796 | } | ||
1797 | } | ||
1798 | if (channel0>1) | ||
1799 | { | ||
1800 | channel0=0; | ||
1801 | volume0=0; | ||
1802 | } | ||
1803 | if (channel1>1) | ||
1804 | { | ||
1805 | channel1=1; | ||
1806 | volume1=0; | ||
1807 | } | ||
1808 | |||
1809 | if (fam1_drive) | ||
1810 | { | ||
1811 | control0=channel0+1; | ||
1812 | control1=channel1+1; | ||
1813 | value0=(volume0>volume1)?volume0:volume1; | ||
1814 | value1=value0; | ||
1815 | if (volume0==0) control0=0; | ||
1816 | if (volume1==0) control1=0; | ||
1817 | drvcmd[0]=CMD1_SETMODE; | ||
1818 | drvcmd[1]=0x05; | ||
1819 | drvcmd[3]=control0; | ||
1820 | drvcmd[4]=value0; | ||
1821 | drvcmd[5]=control1; | ||
1822 | drvcmd[6]=value1; | ||
1823 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
1824 | } | ||
1825 | else if (fam2_drive) | ||
1826 | { | ||
1827 | control0=channel0+1; | ||
1828 | control1=channel1+1; | ||
1829 | value0=(volume0>volume1)?volume0:volume1; | ||
1830 | value1=value0; | ||
1831 | if (volume0==0) control0=0; | ||
1832 | if (volume1==0) control1=0; | ||
1833 | drvcmd[0]=CMD2_SETMODE; | ||
1834 | drvcmd[1]=0x0E; | ||
1835 | drvcmd[3]=control0; | ||
1836 | drvcmd[4]=value0; | ||
1837 | drvcmd[5]=control1; | ||
1838 | drvcmd[6]=value1; | ||
1839 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
1840 | } | ||
1841 | else if (famL_drive) | ||
1842 | { | ||
1843 | if ((volume0==0)||(channel0!=0)) control0 |= 0x80; | ||
1844 | if ((volume1==0)||(channel1!=1)) control0 |= 0x40; | ||
1845 | if (volume0|volume1) value0=0x80; | ||
1846 | drvcmd[0]=CMDL_SETMODE; | ||
1847 | drvcmd[1]=0x03; | ||
1848 | drvcmd[4]=control0; | ||
1849 | drvcmd[5]=value0; | ||
1850 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
1851 | } | ||
1852 | else if (fam0_drive) /* different firmware levels */ | ||
1853 | { | ||
1854 | if (current_drive->drv_type>=drv_300) | ||
1855 | { | ||
1856 | control0=volume0&0xFC; | ||
1857 | value0=volume1&0xFC; | ||
1858 | if ((volume0!=0)&&(volume0<4)) control0 |= 0x04; | ||
1859 | if ((volume1!=0)&&(volume1<4)) value0 |= 0x04; | ||
1860 | if (channel0!=0) control0 |= 0x01; | ||
1861 | if (channel1==1) value0 |= 0x01; | ||
1862 | } | ||
1863 | else | ||
1864 | { | ||
1865 | value0=(volume0>volume1)?volume0:volume1; | ||
1866 | if (current_drive->drv_type<drv_211) | ||
1867 | { | ||
1868 | if (channel0!=0) | ||
1869 | { | ||
1870 | i=channel1; | ||
1871 | channel1=channel0; | ||
1872 | channel0=i; | ||
1873 | i=volume1; | ||
1874 | volume1=volume0; | ||
1875 | volume0=i; | ||
1876 | } | ||
1877 | if (channel0==channel1) | ||
1878 | { | ||
1879 | if (channel0==0) | ||
1880 | { | ||
1881 | channel1=1; | ||
1882 | volume1=0; | ||
1883 | volume0=value0; | ||
1884 | } | ||
1885 | else | ||
1886 | { | ||
1887 | channel0=0; | ||
1888 | volume0=0; | ||
1889 | volume1=value0; | ||
1890 | } | ||
1891 | } | ||
1892 | } | ||
1893 | |||
1894 | if ((volume0!=0)&&(volume1!=0)) | ||
1895 | { | ||
1896 | if (volume0==0xFF) volume1=0xFF; | ||
1897 | else if (volume1==0xFF) volume0=0xFF; | ||
1898 | } | ||
1899 | else if (current_drive->drv_type<drv_201) volume0=volume1=value0; | ||
1900 | |||
1901 | if (current_drive->drv_type>=drv_201) | ||
1902 | { | ||
1903 | if (volume0==0) control0 |= 0x80; | ||
1904 | if (volume1==0) control0 |= 0x40; | ||
1905 | } | ||
1906 | if (current_drive->drv_type>=drv_211) | ||
1907 | { | ||
1908 | if (channel0!=0) control0 |= 0x20; | ||
1909 | if (channel1!=1) control0 |= 0x10; | ||
1910 | } | ||
1911 | } | ||
1912 | drvcmd[0]=CMD0_SETMODE; | ||
1913 | drvcmd[1]=0x83; | ||
1914 | drvcmd[4]=control0; | ||
1915 | drvcmd[5]=value0; | ||
1916 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
1917 | } | ||
1918 | else if (famT_drive) | ||
1919 | { | ||
1920 | current_drive->volume_control=0; | ||
1921 | if (!volume0) current_drive->volume_control|=0x10; | ||
1922 | if (!volume1) current_drive->volume_control|=0x20; | ||
1923 | i=cc_prep_mode_T(); | ||
1924 | if (i<0) return (i); | ||
1925 | } | ||
1926 | if (!famT_drive) | ||
1927 | { | ||
1928 | response_count=0; | ||
1929 | i=cmd_out(); | ||
1930 | if (i<0) return (i); | ||
1931 | } | ||
1932 | current_drive->diskstate_flags |= volume_bit; | ||
1933 | return (0); | ||
1934 | } | ||
1935 | /*==========================================================================*/ | ||
1936 | static int GetStatus(void) | ||
1937 | { | ||
1938 | int i; | ||
1939 | |||
1940 | if (famT_drive) return (0); | ||
1941 | flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check; | ||
1942 | response_count=0; | ||
1943 | cmd_type=0; | ||
1944 | i=cmd_out(); | ||
1945 | return (i); | ||
1946 | } | ||
1947 | /*==========================================================================*/ | ||
1948 | static int cc_DriveReset(void) | ||
1949 | { | ||
1950 | int i; | ||
1951 | |||
1952 | msg(DBG_RES,"cc_DriveReset called.\n"); | ||
1953 | clr_cmdbuf(); | ||
1954 | response_count=0; | ||
1955 | if (fam0LV_drive) OUT(CDo_reset,0x00); | ||
1956 | else if (fam1_drive) | ||
1957 | { | ||
1958 | drvcmd[0]=CMD1_RESET; | ||
1959 | flags_cmd_out=f_putcmd; | ||
1960 | i=cmd_out(); | ||
1961 | } | ||
1962 | else if (fam2_drive) | ||
1963 | { | ||
1964 | drvcmd[0]=CMD2_RESET; | ||
1965 | flags_cmd_out=f_putcmd; | ||
1966 | i=cmd_out(); | ||
1967 | OUT(CDo_reset,0x00); | ||
1968 | } | ||
1969 | else if (famT_drive) | ||
1970 | { | ||
1971 | OUT(CDo_sel_i_d,0); | ||
1972 | OUT(CDo_enable,current_drive->drv_sel); | ||
1973 | OUT(CDo_command,CMDT_RESET); | ||
1974 | for (i=1;i<10;i++) OUT(CDo_command,0); | ||
1975 | } | ||
1976 | if (fam0LV_drive) sbp_sleep(5*HZ); /* wait 5 seconds */ | ||
1977 | else sbp_sleep(1*HZ); /* wait a second */ | ||
1978 | #if 1 | ||
1979 | if (famT_drive) | ||
1980 | { | ||
1981 | msg(DBG_TEA, "================CMDT_RESET given=================.\n"); | ||
1982 | sbp_sleep(3*HZ); | ||
1983 | } | ||
1984 | #endif /* 1 */ | ||
1985 | flush_status(); | ||
1986 | i=GetStatus(); | ||
1987 | if (i<0) return i; | ||
1988 | if (!famT_drive) | ||
1989 | if (current_drive->error_byte!=aud_12) return -501; | ||
1990 | return (0); | ||
1991 | } | ||
1992 | |||
1993 | /*==========================================================================*/ | ||
1994 | static int SetSpeed(void) | ||
1995 | { | ||
1996 | int i, speed; | ||
1997 | |||
1998 | if (!(current_drive->drv_options&(speed_auto|speed_300|speed_150))) return (0); | ||
1999 | speed=speed_auto; | ||
2000 | if (!(current_drive->drv_options&speed_auto)) | ||
2001 | { | ||
2002 | speed |= speed_300; | ||
2003 | if (!(current_drive->drv_options&speed_300)) speed=0; | ||
2004 | } | ||
2005 | i=cc_SetSpeed(speed,0,0); | ||
2006 | return (i); | ||
2007 | } | ||
2008 | |||
2009 | static void switch_drive(struct sbpcd_drive *); | ||
2010 | |||
2011 | static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed) | ||
2012 | { | ||
2013 | struct sbpcd_drive *p = cdi->handle; | ||
2014 | if (p != current_drive) | ||
2015 | switch_drive(p); | ||
2016 | |||
2017 | return cc_SetSpeed(speed == 2 ? speed_300 : speed_150, 0, 0); | ||
2018 | } | ||
2019 | |||
2020 | /*==========================================================================*/ | ||
2021 | static int DriveReset(void) | ||
2022 | { | ||
2023 | int i; | ||
2024 | |||
2025 | i=cc_DriveReset(); | ||
2026 | if (i<0) return (-22); | ||
2027 | do | ||
2028 | { | ||
2029 | i=GetStatus(); | ||
2030 | if ((i<0)&&(i!=-ERR_DISKCHANGE)) { | ||
2031 | return (-2); /* from sta2err */ | ||
2032 | } | ||
2033 | if (!st_caddy_in) break; | ||
2034 | sbp_sleep(1); | ||
2035 | } | ||
2036 | while (!st_diskok); | ||
2037 | #if 000 | ||
2038 | current_drive->CD_changed=1; | ||
2039 | #endif | ||
2040 | if ((st_door_closed) && (st_caddy_in)) | ||
2041 | { | ||
2042 | i=DiskInfo(); | ||
2043 | if (i<0) return (-23); | ||
2044 | } | ||
2045 | return (0); | ||
2046 | } | ||
2047 | |||
2048 | static int sbpcd_reset(struct cdrom_device_info *cdi) | ||
2049 | { | ||
2050 | struct sbpcd_drive *p = cdi->handle; | ||
2051 | if (p != current_drive) | ||
2052 | switch_drive(p); | ||
2053 | return DriveReset(); | ||
2054 | } | ||
2055 | |||
2056 | /*==========================================================================*/ | ||
2057 | static int cc_PlayAudio(int pos_audio_start,int pos_audio_end) | ||
2058 | { | ||
2059 | int i, j, n; | ||
2060 | |||
2061 | if (current_drive->audio_state==audio_playing) return (-EINVAL); | ||
2062 | clr_cmdbuf(); | ||
2063 | response_count=0; | ||
2064 | if (famLV_drive) | ||
2065 | { | ||
2066 | drvcmd[0]=CMDL_PLAY; | ||
2067 | i=msf2blk(pos_audio_start); | ||
2068 | n=msf2blk(pos_audio_end)+1-i; | ||
2069 | drvcmd[1]=(i>>16)&0x00FF; | ||
2070 | drvcmd[2]=(i>>8)&0x00FF; | ||
2071 | drvcmd[3]=i&0x00FF; | ||
2072 | drvcmd[4]=(n>>16)&0x00FF; | ||
2073 | drvcmd[5]=(n>>8)&0x00FF; | ||
2074 | drvcmd[6]=n&0x00FF; | ||
2075 | if (famL_drive) | ||
2076 | flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | | ||
2077 | f_ResponseStatus | f_obey_p_check | f_wait_if_busy; | ||
2078 | else | ||
2079 | flags_cmd_out = f_putcmd; | ||
2080 | } | ||
2081 | else | ||
2082 | { | ||
2083 | j=1; | ||
2084 | if (fam1_drive) | ||
2085 | { | ||
2086 | drvcmd[0]=CMD1_PLAY_MSF; | ||
2087 | flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | | ||
2088 | f_obey_p_check | f_wait_if_busy; | ||
2089 | } | ||
2090 | else if (fam2_drive) | ||
2091 | { | ||
2092 | drvcmd[0]=CMD2_PLAY_MSF; | ||
2093 | flags_cmd_out = f_putcmd | f_ResponseStatus | f_obey_p_check; | ||
2094 | } | ||
2095 | else if (famT_drive) | ||
2096 | { | ||
2097 | drvcmd[0]=CMDT_PLAY_MSF; | ||
2098 | j=3; | ||
2099 | response_count=1; | ||
2100 | } | ||
2101 | else if (fam0_drive) | ||
2102 | { | ||
2103 | drvcmd[0]=CMD0_PLAY_MSF; | ||
2104 | flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | | ||
2105 | f_ResponseStatus | f_obey_p_check | f_wait_if_busy; | ||
2106 | } | ||
2107 | drvcmd[j]=(pos_audio_start>>16)&0x00FF; | ||
2108 | drvcmd[j+1]=(pos_audio_start>>8)&0x00FF; | ||
2109 | drvcmd[j+2]=pos_audio_start&0x00FF; | ||
2110 | drvcmd[j+3]=(pos_audio_end>>16)&0x00FF; | ||
2111 | drvcmd[j+4]=(pos_audio_end>>8)&0x00FF; | ||
2112 | drvcmd[j+5]=pos_audio_end&0x00FF; | ||
2113 | } | ||
2114 | i=cmd_out(); | ||
2115 | return (i); | ||
2116 | } | ||
2117 | /*==========================================================================*/ | ||
2118 | static int cc_Pause_Resume(int pau_res) | ||
2119 | { | ||
2120 | int i; | ||
2121 | |||
2122 | clr_cmdbuf(); | ||
2123 | response_count=0; | ||
2124 | if (fam1_drive) | ||
2125 | { | ||
2126 | drvcmd[0]=CMD1_PAU_RES; | ||
2127 | if (pau_res!=1) drvcmd[1]=0x80; | ||
2128 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
2129 | } | ||
2130 | else if (fam2_drive) | ||
2131 | { | ||
2132 | drvcmd[0]=CMD2_PAU_RES; | ||
2133 | if (pau_res!=1) drvcmd[2]=0x01; | ||
2134 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
2135 | } | ||
2136 | else if (fam0LV_drive) | ||
2137 | { | ||
2138 | drvcmd[0]=CMD0_PAU_RES; | ||
2139 | if (pau_res!=1) drvcmd[1]=0x80; | ||
2140 | if (famL_drive) | ||
2141 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus| | ||
2142 | f_obey_p_check|f_bit1; | ||
2143 | else if (famV_drive) | ||
2144 | flags_cmd_out=f_putcmd; | ||
2145 | else | ||
2146 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus| | ||
2147 | f_obey_p_check; | ||
2148 | } | ||
2149 | else if (famT_drive) | ||
2150 | { | ||
2151 | if (pau_res==3) return (cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end)); | ||
2152 | else if (pau_res==1) drvcmd[0]=CMDT_PAUSE; | ||
2153 | else return (-56); | ||
2154 | } | ||
2155 | i=cmd_out(); | ||
2156 | return (i); | ||
2157 | } | ||
2158 | /*==========================================================================*/ | ||
2159 | static int cc_LockDoor(char lock) | ||
2160 | { | ||
2161 | int i; | ||
2162 | |||
2163 | if (fam0_drive) return (0); | ||
2164 | msg(DBG_LCK,"cc_LockDoor: %d (drive %d)\n", lock, current_drive - D_S); | ||
2165 | msg(DBG_LCS,"p_door_locked bit %d before\n", st_door_locked); | ||
2166 | clr_cmdbuf(); | ||
2167 | response_count=0; | ||
2168 | if (fam1_drive) | ||
2169 | { | ||
2170 | drvcmd[0]=CMD1_LOCK_CTL; | ||
2171 | if (lock==1) drvcmd[1]=0x01; | ||
2172 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2173 | } | ||
2174 | else if (fam2_drive) | ||
2175 | { | ||
2176 | drvcmd[0]=CMD2_LOCK_CTL; | ||
2177 | if (lock==1) drvcmd[4]=0x01; | ||
2178 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
2179 | } | ||
2180 | else if (famLV_drive) | ||
2181 | { | ||
2182 | drvcmd[0]=CMDL_LOCK_CTL; | ||
2183 | if (lock==1) drvcmd[1]=0x01; | ||
2184 | if (famL_drive) | ||
2185 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
2186 | else | ||
2187 | flags_cmd_out=f_putcmd; | ||
2188 | } | ||
2189 | else if (famT_drive) | ||
2190 | { | ||
2191 | drvcmd[0]=CMDT_LOCK_CTL; | ||
2192 | if (lock==1) drvcmd[4]=0x01; | ||
2193 | } | ||
2194 | i=cmd_out(); | ||
2195 | msg(DBG_LCS,"p_door_locked bit %d after\n", st_door_locked); | ||
2196 | return (i); | ||
2197 | } | ||
2198 | /*==========================================================================*/ | ||
2199 | /*==========================================================================*/ | ||
2200 | static int UnLockDoor(void) | ||
2201 | { | ||
2202 | int i,j; | ||
2203 | |||
2204 | j=20; | ||
2205 | do | ||
2206 | { | ||
2207 | i=cc_LockDoor(0); | ||
2208 | --j; | ||
2209 | sbp_sleep(1); | ||
2210 | } | ||
2211 | while ((i<0)&&(j)); | ||
2212 | if (i<0) | ||
2213 | { | ||
2214 | cc_DriveReset(); | ||
2215 | return -84; | ||
2216 | } | ||
2217 | return (0); | ||
2218 | } | ||
2219 | /*==========================================================================*/ | ||
2220 | static int LockDoor(void) | ||
2221 | { | ||
2222 | int i,j; | ||
2223 | |||
2224 | j=20; | ||
2225 | do | ||
2226 | { | ||
2227 | i=cc_LockDoor(1); | ||
2228 | --j; | ||
2229 | sbp_sleep(1); | ||
2230 | } | ||
2231 | while ((i<0)&&(j)); | ||
2232 | if (j==0) | ||
2233 | { | ||
2234 | cc_DriveReset(); | ||
2235 | j=20; | ||
2236 | do | ||
2237 | { | ||
2238 | i=cc_LockDoor(1); | ||
2239 | --j; | ||
2240 | sbp_sleep(1); | ||
2241 | } | ||
2242 | while ((i<0)&&(j)); | ||
2243 | } | ||
2244 | return (i); | ||
2245 | } | ||
2246 | |||
2247 | static int sbpcd_lock_door(struct cdrom_device_info *cdi, int lock) | ||
2248 | { | ||
2249 | return lock ? LockDoor() : UnLockDoor(); | ||
2250 | } | ||
2251 | |||
2252 | /*==========================================================================*/ | ||
2253 | static int cc_CloseTray(void) | ||
2254 | { | ||
2255 | int i; | ||
2256 | |||
2257 | if (fam0_drive) return (0); | ||
2258 | msg(DBG_LCK,"cc_CloseTray (drive %d)\n", current_drive - D_S); | ||
2259 | msg(DBG_LCS,"p_door_closed bit %d before\n", st_door_closed); | ||
2260 | |||
2261 | clr_cmdbuf(); | ||
2262 | response_count=0; | ||
2263 | if (fam1_drive) | ||
2264 | { | ||
2265 | drvcmd[0]=CMD1_TRAY_CTL; | ||
2266 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
2267 | } | ||
2268 | else if (fam2_drive) | ||
2269 | { | ||
2270 | drvcmd[0]=CMD2_TRAY_CTL; | ||
2271 | drvcmd[1]=0x01; | ||
2272 | drvcmd[4]=0x03; /* "insert" */ | ||
2273 | flags_cmd_out=f_putcmd|f_ResponseStatus; | ||
2274 | } | ||
2275 | else if (famLV_drive) | ||
2276 | { | ||
2277 | drvcmd[0]=CMDL_TRAY_CTL; | ||
2278 | if (famLV_drive) | ||
2279 | flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| | ||
2280 | f_ResponseStatus|f_obey_p_check|f_bit1; | ||
2281 | else | ||
2282 | flags_cmd_out=f_putcmd; | ||
2283 | } | ||
2284 | else if (famT_drive) | ||
2285 | { | ||
2286 | drvcmd[0]=CMDT_TRAY_CTL; | ||
2287 | drvcmd[4]=0x03; /* "insert" */ | ||
2288 | } | ||
2289 | i=cmd_out(); | ||
2290 | msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed); | ||
2291 | |||
2292 | i=cc_ReadError(); | ||
2293 | flags_cmd_out |= f_respo2; | ||
2294 | cc_ReadStatus(); /* command: give 1-byte status */ | ||
2295 | i=ResponseStatus(); | ||
2296 | if (famT_drive&&(i<0)) | ||
2297 | { | ||
2298 | cc_DriveReset(); | ||
2299 | i=ResponseStatus(); | ||
2300 | #if 0 | ||
2301 | sbp_sleep(HZ); | ||
2302 | #endif /* 0 */ | ||
2303 | i=ResponseStatus(); | ||
2304 | } | ||
2305 | if (i<0) | ||
2306 | { | ||
2307 | msg(DBG_INF,"sbpcd cc_CloseTray: ResponseStatus timed out (%d).\n",i); | ||
2308 | } | ||
2309 | if (!(famT_drive)) | ||
2310 | { | ||
2311 | if (!st_spinning) | ||
2312 | { | ||
2313 | cc_SpinUp(); | ||
2314 | if (st_check) i=cc_ReadError(); | ||
2315 | flags_cmd_out |= f_respo2; | ||
2316 | cc_ReadStatus(); | ||
2317 | i=ResponseStatus(); | ||
2318 | } else { | ||
2319 | } | ||
2320 | } | ||
2321 | i=DiskInfo(); | ||
2322 | return (i); | ||
2323 | } | ||
2324 | |||
2325 | static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position) | ||
2326 | { | ||
2327 | int retval=0; | ||
2328 | switch_drive(cdi->handle); | ||
2329 | /* DUH! --AJK */ | ||
2330 | if(current_drive->CD_changed != 0xFF) { | ||
2331 | current_drive->CD_changed=0xFF; | ||
2332 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
2333 | } | ||
2334 | if (position == 1) { | ||
2335 | cc_SpinDown(); | ||
2336 | } else { | ||
2337 | retval=cc_CloseTray(); | ||
2338 | } | ||
2339 | return retval; | ||
2340 | } | ||
2341 | |||
2342 | /*==========================================================================*/ | ||
2343 | static int cc_ReadSubQ(void) | ||
2344 | { | ||
2345 | int i,j; | ||
2346 | |||
2347 | current_drive->diskstate_flags &= ~subq_bit; | ||
2348 | for (j=255;j>0;j--) | ||
2349 | { | ||
2350 | clr_cmdbuf(); | ||
2351 | if (fam1_drive) | ||
2352 | { | ||
2353 | drvcmd[0]=CMD1_READSUBQ; | ||
2354 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2355 | response_count=11; | ||
2356 | } | ||
2357 | else if (fam2_drive) | ||
2358 | { | ||
2359 | drvcmd[0]=CMD2_READSUBQ; | ||
2360 | drvcmd[1]=0x02; | ||
2361 | drvcmd[3]=0x01; | ||
2362 | flags_cmd_out=f_putcmd; | ||
2363 | response_count=10; | ||
2364 | } | ||
2365 | else if (fam0LV_drive) | ||
2366 | { | ||
2367 | drvcmd[0]=CMD0_READSUBQ; | ||
2368 | drvcmd[1]=0x02; | ||
2369 | if (famLV_drive) | ||
2370 | flags_cmd_out=f_putcmd; | ||
2371 | else | ||
2372 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2373 | response_count=13; | ||
2374 | } | ||
2375 | else if (famT_drive) | ||
2376 | { | ||
2377 | response_count=12; | ||
2378 | drvcmd[0]=CMDT_READSUBQ; | ||
2379 | drvcmd[1]=0x02; | ||
2380 | drvcmd[2]=0x40; | ||
2381 | drvcmd[3]=0x01; | ||
2382 | drvcmd[8]=response_count; | ||
2383 | } | ||
2384 | i=cmd_out(); | ||
2385 | if (i<0) return (i); | ||
2386 | for (i=0;i<response_count;i++) | ||
2387 | { | ||
2388 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
2389 | msgbuf[i*3]=0; | ||
2390 | msg(DBG_SQ1,"cc_ReadSubQ:%s\n", msgbuf); | ||
2391 | } | ||
2392 | if (famT_drive) break; | ||
2393 | if (infobuf[0]!=0) break; | ||
2394 | if ((!st_spinning) || (j==1)) | ||
2395 | { | ||
2396 | current_drive->SubQ_ctl_adr=current_drive->SubQ_trk=current_drive->SubQ_pnt_idx=current_drive->SubQ_whatisthis=0; | ||
2397 | current_drive->SubQ_run_tot=current_drive->SubQ_run_trk=0; | ||
2398 | return (0); | ||
2399 | } | ||
2400 | } | ||
2401 | if (famT_drive) current_drive->SubQ_ctl_adr=infobuf[1]; | ||
2402 | else current_drive->SubQ_ctl_adr=swap_nibbles(infobuf[1]); | ||
2403 | current_drive->SubQ_trk=byt2bcd(infobuf[2]); | ||
2404 | current_drive->SubQ_pnt_idx=byt2bcd(infobuf[3]); | ||
2405 | if (fam0LV_drive) i=5; | ||
2406 | else if (fam12_drive) i=4; | ||
2407 | else if (famT_drive) i=8; | ||
2408 | current_drive->SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ | ||
2409 | i=7; | ||
2410 | if (fam0LV_drive) i=9; | ||
2411 | else if (fam12_drive) i=7; | ||
2412 | else if (famT_drive) i=4; | ||
2413 | current_drive->SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ | ||
2414 | current_drive->SubQ_whatisthis=infobuf[i+3]; | ||
2415 | current_drive->diskstate_flags |= subq_bit; | ||
2416 | return (0); | ||
2417 | } | ||
2418 | /*==========================================================================*/ | ||
2419 | static int cc_ModeSense(void) | ||
2420 | { | ||
2421 | int i; | ||
2422 | |||
2423 | if (fam2_drive) return (0); | ||
2424 | if (famV_drive) return (0); | ||
2425 | current_drive->diskstate_flags &= ~frame_size_bit; | ||
2426 | clr_cmdbuf(); | ||
2427 | if (fam1_drive) | ||
2428 | { | ||
2429 | response_count=5; | ||
2430 | drvcmd[0]=CMD1_GETMODE; | ||
2431 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2432 | } | ||
2433 | else if (fam0L_drive) | ||
2434 | { | ||
2435 | response_count=2; | ||
2436 | drvcmd[0]=CMD0_GETMODE; | ||
2437 | if (famL_drive) flags_cmd_out=f_putcmd; | ||
2438 | else flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2439 | } | ||
2440 | else if (famT_drive) | ||
2441 | { | ||
2442 | response_count=10; | ||
2443 | drvcmd[0]=CMDT_GETMODE; | ||
2444 | drvcmd[4]=response_count; | ||
2445 | } | ||
2446 | i=cmd_out(); | ||
2447 | if (i<0) return (i); | ||
2448 | i=0; | ||
2449 | current_drive->sense_byte=0; | ||
2450 | if (fam1_drive) current_drive->sense_byte=infobuf[i++]; | ||
2451 | else if (famT_drive) | ||
2452 | { | ||
2453 | if (infobuf[4]==0x01) current_drive->xa_byte=0x20; | ||
2454 | else current_drive->xa_byte=0; | ||
2455 | i=2; | ||
2456 | } | ||
2457 | current_drive->frame_size=make16(infobuf[i],infobuf[i+1]); | ||
2458 | for (i=0;i<response_count;i++) | ||
2459 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
2460 | msgbuf[i*3]=0; | ||
2461 | msg(DBG_XA1,"cc_ModeSense:%s\n", msgbuf); | ||
2462 | |||
2463 | current_drive->diskstate_flags |= frame_size_bit; | ||
2464 | return (0); | ||
2465 | } | ||
2466 | /*==========================================================================*/ | ||
2467 | /*==========================================================================*/ | ||
2468 | static int cc_ModeSelect(int framesize) | ||
2469 | { | ||
2470 | int i; | ||
2471 | |||
2472 | if (fam2_drive) return (0); | ||
2473 | if (famV_drive) return (0); | ||
2474 | current_drive->diskstate_flags &= ~frame_size_bit; | ||
2475 | clr_cmdbuf(); | ||
2476 | current_drive->frame_size=framesize; | ||
2477 | if (framesize==CD_FRAMESIZE_RAW) current_drive->sense_byte=0x82; | ||
2478 | else current_drive->sense_byte=0x00; | ||
2479 | |||
2480 | msg(DBG_XA1,"cc_ModeSelect: %02X %04X\n", | ||
2481 | current_drive->sense_byte, current_drive->frame_size); | ||
2482 | |||
2483 | if (fam1_drive) | ||
2484 | { | ||
2485 | drvcmd[0]=CMD1_SETMODE; | ||
2486 | drvcmd[1]=0x00; | ||
2487 | drvcmd[2]=current_drive->sense_byte; | ||
2488 | drvcmd[3]=(current_drive->frame_size>>8)&0xFF; | ||
2489 | drvcmd[4]=current_drive->frame_size&0xFF; | ||
2490 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2491 | } | ||
2492 | else if (fam0L_drive) | ||
2493 | { | ||
2494 | drvcmd[0]=CMD0_SETMODE; | ||
2495 | drvcmd[1]=0x00; | ||
2496 | drvcmd[2]=(current_drive->frame_size>>8)&0xFF; | ||
2497 | drvcmd[3]=current_drive->frame_size&0xFF; | ||
2498 | drvcmd[4]=0x00; | ||
2499 | if(famL_drive) | ||
2500 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2501 | else | ||
2502 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2503 | } | ||
2504 | else if (famT_drive) | ||
2505 | { | ||
2506 | return (-1); | ||
2507 | } | ||
2508 | response_count=0; | ||
2509 | i=cmd_out(); | ||
2510 | if (i<0) return (i); | ||
2511 | current_drive->diskstate_flags |= frame_size_bit; | ||
2512 | return (0); | ||
2513 | } | ||
2514 | /*==========================================================================*/ | ||
2515 | static int cc_GetVolume(void) | ||
2516 | { | ||
2517 | int i; | ||
2518 | u_char switches; | ||
2519 | u_char chan0=0; | ||
2520 | u_char vol0=0; | ||
2521 | u_char chan1=1; | ||
2522 | u_char vol1=0; | ||
2523 | |||
2524 | if (famV_drive) return (0); | ||
2525 | current_drive->diskstate_flags &= ~volume_bit; | ||
2526 | clr_cmdbuf(); | ||
2527 | if (fam1_drive) | ||
2528 | { | ||
2529 | drvcmd[0]=CMD1_GETMODE; | ||
2530 | drvcmd[1]=0x05; | ||
2531 | response_count=5; | ||
2532 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2533 | } | ||
2534 | else if (fam2_drive) | ||
2535 | { | ||
2536 | drvcmd[0]=CMD2_GETMODE; | ||
2537 | drvcmd[1]=0x0E; | ||
2538 | response_count=5; | ||
2539 | flags_cmd_out=f_putcmd; | ||
2540 | } | ||
2541 | else if (fam0L_drive) | ||
2542 | { | ||
2543 | drvcmd[0]=CMD0_GETMODE; | ||
2544 | drvcmd[1]=0x03; | ||
2545 | response_count=2; | ||
2546 | if(famL_drive) | ||
2547 | flags_cmd_out=f_putcmd; | ||
2548 | else | ||
2549 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2550 | } | ||
2551 | else if (famT_drive) | ||
2552 | { | ||
2553 | i=cc_get_mode_T(); | ||
2554 | if (i<0) return (i); | ||
2555 | } | ||
2556 | if (!famT_drive) | ||
2557 | { | ||
2558 | i=cmd_out(); | ||
2559 | if (i<0) return (i); | ||
2560 | } | ||
2561 | if (fam1_drive) | ||
2562 | { | ||
2563 | chan0=infobuf[1]&0x0F; | ||
2564 | vol0=infobuf[2]; | ||
2565 | chan1=infobuf[3]&0x0F; | ||
2566 | vol1=infobuf[4]; | ||
2567 | if (chan0==0) | ||
2568 | { | ||
2569 | chan0=1; | ||
2570 | vol0=0; | ||
2571 | } | ||
2572 | if (chan1==0) | ||
2573 | { | ||
2574 | chan1=2; | ||
2575 | vol1=0; | ||
2576 | } | ||
2577 | chan0 >>= 1; | ||
2578 | chan1 >>= 1; | ||
2579 | } | ||
2580 | else if (fam2_drive) | ||
2581 | { | ||
2582 | chan0=infobuf[1]; | ||
2583 | vol0=infobuf[2]; | ||
2584 | chan1=infobuf[3]; | ||
2585 | vol1=infobuf[4]; | ||
2586 | } | ||
2587 | else if (famL_drive) | ||
2588 | { | ||
2589 | chan0=0; | ||
2590 | chan1=1; | ||
2591 | vol0=vol1=infobuf[1]; | ||
2592 | switches=infobuf[0]; | ||
2593 | if ((switches&0x80)!=0) chan0=1; | ||
2594 | if ((switches&0x40)!=0) chan1=0; | ||
2595 | } | ||
2596 | else if (fam0_drive) /* different firmware levels */ | ||
2597 | { | ||
2598 | chan0=0; | ||
2599 | chan1=1; | ||
2600 | vol0=vol1=infobuf[1]; | ||
2601 | if (current_drive->drv_type>=drv_201) | ||
2602 | { | ||
2603 | if (current_drive->drv_type<drv_300) | ||
2604 | { | ||
2605 | switches=infobuf[0]; | ||
2606 | if ((switches&0x80)!=0) vol0=0; | ||
2607 | if ((switches&0x40)!=0) vol1=0; | ||
2608 | if (current_drive->drv_type>=drv_211) | ||
2609 | { | ||
2610 | if ((switches&0x20)!=0) chan0=1; | ||
2611 | if ((switches&0x10)!=0) chan1=0; | ||
2612 | } | ||
2613 | } | ||
2614 | else | ||
2615 | { | ||
2616 | vol0=infobuf[0]; | ||
2617 | if ((vol0&0x01)!=0) chan0=1; | ||
2618 | if ((vol1&0x01)==0) chan1=0; | ||
2619 | vol0 &= 0xFC; | ||
2620 | vol1 &= 0xFC; | ||
2621 | if (vol0!=0) vol0 += 3; | ||
2622 | if (vol1!=0) vol1 += 3; | ||
2623 | } | ||
2624 | } | ||
2625 | } | ||
2626 | else if (famT_drive) | ||
2627 | { | ||
2628 | current_drive->volume_control=infobuf[7]; | ||
2629 | chan0=0; | ||
2630 | chan1=1; | ||
2631 | if (current_drive->volume_control&0x10) vol0=0; | ||
2632 | else vol0=0xff; | ||
2633 | if (current_drive->volume_control&0x20) vol1=0; | ||
2634 | else vol1=0xff; | ||
2635 | } | ||
2636 | current_drive->vol_chan0=chan0; | ||
2637 | current_drive->vol_ctrl0=vol0; | ||
2638 | current_drive->vol_chan1=chan1; | ||
2639 | current_drive->vol_ctrl1=vol1; | ||
2640 | #if 000 | ||
2641 | current_drive->vol_chan2=2; | ||
2642 | current_drive->vol_ctrl2=0xFF; | ||
2643 | current_drive->vol_chan3=3; | ||
2644 | current_drive->vol_ctrl3=0xFF; | ||
2645 | #endif /* 000 */ | ||
2646 | current_drive->diskstate_flags |= volume_bit; | ||
2647 | return (0); | ||
2648 | } | ||
2649 | /*==========================================================================*/ | ||
2650 | static int cc_ReadCapacity(void) | ||
2651 | { | ||
2652 | int i, j; | ||
2653 | |||
2654 | if (fam2_drive) return (0); /* some firmware lacks this command */ | ||
2655 | if (famLV_drive) return (0); /* some firmware lacks this command */ | ||
2656 | if (famT_drive) return (0); /* done with cc_ReadTocDescr() */ | ||
2657 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
2658 | for (j=3;j>0;j--) | ||
2659 | { | ||
2660 | clr_cmdbuf(); | ||
2661 | if (fam1_drive) | ||
2662 | { | ||
2663 | drvcmd[0]=CMD1_CAPACITY; | ||
2664 | response_count=5; | ||
2665 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2666 | } | ||
2667 | #if 00 | ||
2668 | else if (fam2_drive) | ||
2669 | { | ||
2670 | drvcmd[0]=CMD2_CAPACITY; | ||
2671 | response_count=8; | ||
2672 | flags_cmd_out=f_putcmd; | ||
2673 | } | ||
2674 | #endif | ||
2675 | else if (fam0_drive) | ||
2676 | { | ||
2677 | drvcmd[0]=CMD0_CAPACITY; | ||
2678 | response_count=5; | ||
2679 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2680 | } | ||
2681 | i=cmd_out(); | ||
2682 | if (i>=0) break; | ||
2683 | msg(DBG_000,"cc_ReadCapacity: cmd_out: err %d\n", i); | ||
2684 | cc_ReadError(); | ||
2685 | } | ||
2686 | if (j==0) return (i); | ||
2687 | if (fam1_drive) current_drive->CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_MSF_OFFSET; | ||
2688 | else if (fam0_drive) current_drive->CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])); | ||
2689 | #if 00 | ||
2690 | else if (fam2_drive) current_drive->CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3])); | ||
2691 | #endif | ||
2692 | current_drive->diskstate_flags |= cd_size_bit; | ||
2693 | msg(DBG_000,"cc_ReadCapacity: %d frames.\n", current_drive->CDsize_frm); | ||
2694 | return (0); | ||
2695 | } | ||
2696 | /*==========================================================================*/ | ||
2697 | static int cc_ReadTocDescr(void) | ||
2698 | { | ||
2699 | int i; | ||
2700 | |||
2701 | current_drive->diskstate_flags &= ~toc_bit; | ||
2702 | clr_cmdbuf(); | ||
2703 | if (fam1_drive) | ||
2704 | { | ||
2705 | drvcmd[0]=CMD1_DISKINFO; | ||
2706 | response_count=6; | ||
2707 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2708 | } | ||
2709 | else if (fam0LV_drive) | ||
2710 | { | ||
2711 | drvcmd[0]=CMD0_DISKINFO; | ||
2712 | response_count=6; | ||
2713 | if(famLV_drive) | ||
2714 | flags_cmd_out=f_putcmd; | ||
2715 | else | ||
2716 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2717 | } | ||
2718 | else if (fam2_drive) | ||
2719 | { | ||
2720 | /* possibly longer timeout periods necessary */ | ||
2721 | current_drive->f_multisession=0; | ||
2722 | drvcmd[0]=CMD2_DISKINFO; | ||
2723 | drvcmd[1]=0x02; | ||
2724 | drvcmd[2]=0xAB; | ||
2725 | drvcmd[3]=0xFF; /* session */ | ||
2726 | response_count=8; | ||
2727 | flags_cmd_out=f_putcmd; | ||
2728 | } | ||
2729 | else if (famT_drive) | ||
2730 | { | ||
2731 | current_drive->f_multisession=0; | ||
2732 | response_count=12; | ||
2733 | drvcmd[0]=CMDT_DISKINFO; | ||
2734 | drvcmd[1]=0x02; | ||
2735 | drvcmd[6]=CDROM_LEADOUT; | ||
2736 | drvcmd[8]=response_count; | ||
2737 | drvcmd[9]=0x00; | ||
2738 | } | ||
2739 | i=cmd_out(); | ||
2740 | if (i<0) return (i); | ||
2741 | if ((famT_drive)&&(i<response_count)) return (-100-i); | ||
2742 | if ((fam1_drive)||(fam2_drive)||(fam0LV_drive)) | ||
2743 | current_drive->xa_byte=infobuf[0]; | ||
2744 | if (fam2_drive) | ||
2745 | { | ||
2746 | current_drive->first_session=infobuf[1]; | ||
2747 | current_drive->last_session=infobuf[2]; | ||
2748 | current_drive->n_first_track=infobuf[3]; | ||
2749 | current_drive->n_last_track=infobuf[4]; | ||
2750 | if (current_drive->first_session!=current_drive->last_session) | ||
2751 | { | ||
2752 | current_drive->f_multisession=1; | ||
2753 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7]))); | ||
2754 | } | ||
2755 | #if 0 | ||
2756 | if (current_drive->first_session!=current_drive->last_session) | ||
2757 | { | ||
2758 | if (current_drive->last_session<=20) | ||
2759 | zwanzig=current_drive->last_session+1; | ||
2760 | else zwanzig=20; | ||
2761 | for (count=current_drive->first_session;count<zwanzig;count++) | ||
2762 | { | ||
2763 | drvcmd[0]=CMD2_DISKINFO; | ||
2764 | drvcmd[1]=0x02; | ||
2765 | drvcmd[2]=0xAB; | ||
2766 | drvcmd[3]=count; | ||
2767 | response_count=8; | ||
2768 | flags_cmd_out=f_putcmd; | ||
2769 | i=cmd_out(); | ||
2770 | if (i<0) return (i); | ||
2771 | current_drive->msf_multi_n[count]=make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7])); | ||
2772 | } | ||
2773 | current_drive->diskstate_flags |= multisession_bit; | ||
2774 | } | ||
2775 | #endif | ||
2776 | drvcmd[0]=CMD2_DISKINFO; | ||
2777 | drvcmd[1]=0x02; | ||
2778 | drvcmd[2]=0xAA; | ||
2779 | drvcmd[3]=0xFF; | ||
2780 | response_count=5; | ||
2781 | flags_cmd_out=f_putcmd; | ||
2782 | i=cmd_out(); | ||
2783 | if (i<0) return (i); | ||
2784 | current_drive->size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4])); | ||
2785 | current_drive->size_blk=msf2blk(current_drive->size_msf); | ||
2786 | current_drive->CDsize_frm=current_drive->size_blk+1; | ||
2787 | } | ||
2788 | else if (famT_drive) | ||
2789 | { | ||
2790 | current_drive->size_msf=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11])); | ||
2791 | current_drive->size_blk=msf2blk(current_drive->size_msf); | ||
2792 | current_drive->CDsize_frm=current_drive->size_blk+1; | ||
2793 | current_drive->n_first_track=infobuf[2]; | ||
2794 | current_drive->n_last_track=infobuf[3]; | ||
2795 | } | ||
2796 | else | ||
2797 | { | ||
2798 | current_drive->n_first_track=infobuf[1]; | ||
2799 | current_drive->n_last_track=infobuf[2]; | ||
2800 | current_drive->size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5])); | ||
2801 | current_drive->size_blk=msf2blk(current_drive->size_msf); | ||
2802 | if (famLV_drive) current_drive->CDsize_frm=current_drive->size_blk+1; | ||
2803 | } | ||
2804 | current_drive->diskstate_flags |= toc_bit; | ||
2805 | msg(DBG_TOC,"TocDesc: xa %02X firstt %02X lastt %02X size %08X firstses %02X lastsess %02X\n", | ||
2806 | current_drive->xa_byte, | ||
2807 | current_drive->n_first_track, | ||
2808 | current_drive->n_last_track, | ||
2809 | current_drive->size_msf, | ||
2810 | current_drive->first_session, | ||
2811 | current_drive->last_session); | ||
2812 | return (0); | ||
2813 | } | ||
2814 | /*==========================================================================*/ | ||
2815 | static int cc_ReadTocEntry(int num) | ||
2816 | { | ||
2817 | int i; | ||
2818 | |||
2819 | clr_cmdbuf(); | ||
2820 | if (fam1_drive) | ||
2821 | { | ||
2822 | drvcmd[0]=CMD1_READTOC; | ||
2823 | drvcmd[2]=num; | ||
2824 | response_count=8; | ||
2825 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2826 | } | ||
2827 | else if (fam2_drive) | ||
2828 | { | ||
2829 | /* possibly longer timeout periods necessary */ | ||
2830 | drvcmd[0]=CMD2_DISKINFO; | ||
2831 | drvcmd[1]=0x02; | ||
2832 | drvcmd[2]=num; | ||
2833 | response_count=5; | ||
2834 | flags_cmd_out=f_putcmd; | ||
2835 | } | ||
2836 | else if (fam0LV_drive) | ||
2837 | { | ||
2838 | drvcmd[0]=CMD0_READTOC; | ||
2839 | drvcmd[1]=0x02; | ||
2840 | drvcmd[2]=num; | ||
2841 | response_count=8; | ||
2842 | if (famLV_drive) | ||
2843 | flags_cmd_out=f_putcmd; | ||
2844 | else | ||
2845 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2846 | } | ||
2847 | else if (famT_drive) | ||
2848 | { | ||
2849 | response_count=12; | ||
2850 | drvcmd[0]=CMDT_DISKINFO; | ||
2851 | drvcmd[1]=0x02; | ||
2852 | drvcmd[6]=num; | ||
2853 | drvcmd[8]=response_count; | ||
2854 | drvcmd[9]=0x00; | ||
2855 | } | ||
2856 | i=cmd_out(); | ||
2857 | if (i<0) return (i); | ||
2858 | if ((famT_drive)&&(i<response_count)) return (-100-i); | ||
2859 | if ((fam1_drive)||(fam0LV_drive)) | ||
2860 | { | ||
2861 | current_drive->TocEnt_nixbyte=infobuf[0]; | ||
2862 | i=1; | ||
2863 | } | ||
2864 | else if (fam2_drive) i=0; | ||
2865 | else if (famT_drive) i=5; | ||
2866 | current_drive->TocEnt_ctl_adr=swap_nibbles(infobuf[i++]); | ||
2867 | if ((fam1_drive)||(fam0L_drive)) | ||
2868 | { | ||
2869 | current_drive->TocEnt_number=infobuf[i++]; | ||
2870 | current_drive->TocEnt_format=infobuf[i]; | ||
2871 | } | ||
2872 | else | ||
2873 | { | ||
2874 | current_drive->TocEnt_number=num; | ||
2875 | current_drive->TocEnt_format=0; | ||
2876 | } | ||
2877 | if (fam1_drive) i=4; | ||
2878 | else if (fam0LV_drive) i=5; | ||
2879 | else if (fam2_drive) i=2; | ||
2880 | else if (famT_drive) i=9; | ||
2881 | current_drive->TocEnt_address=make32(make16(0,infobuf[i]), | ||
2882 | make16(infobuf[i+1],infobuf[i+2])); | ||
2883 | for (i=0;i<response_count;i++) | ||
2884 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
2885 | msgbuf[i*3]=0; | ||
2886 | msg(DBG_ECS,"TocEntry:%s\n", msgbuf); | ||
2887 | msg(DBG_TOC,"TocEntry: %02X %02X %02X %02X %08X\n", | ||
2888 | current_drive->TocEnt_nixbyte, current_drive->TocEnt_ctl_adr, | ||
2889 | current_drive->TocEnt_number, current_drive->TocEnt_format, | ||
2890 | current_drive->TocEnt_address); | ||
2891 | return (0); | ||
2892 | } | ||
2893 | /*==========================================================================*/ | ||
2894 | static int cc_ReadPacket(void) | ||
2895 | { | ||
2896 | int i; | ||
2897 | |||
2898 | clr_cmdbuf(); | ||
2899 | drvcmd[0]=CMD0_PACKET; | ||
2900 | drvcmd[1]=response_count; | ||
2901 | if(famL_drive) flags_cmd_out=f_putcmd; | ||
2902 | else if (fam01_drive) | ||
2903 | flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; | ||
2904 | else if (fam2_drive) return (-1); /* not implemented yet */ | ||
2905 | else if (famT_drive) | ||
2906 | { | ||
2907 | return (-1); | ||
2908 | } | ||
2909 | i=cmd_out(); | ||
2910 | return (i); | ||
2911 | } | ||
2912 | /*==========================================================================*/ | ||
2913 | static int convert_UPC(u_char *p) | ||
2914 | { | ||
2915 | int i; | ||
2916 | |||
2917 | p++; | ||
2918 | if (fam0L_drive) p[13]=0; | ||
2919 | for (i=0;i<7;i++) | ||
2920 | { | ||
2921 | if (fam1_drive) current_drive->UPC_buf[i]=swap_nibbles(*p++); | ||
2922 | else if (fam0L_drive) | ||
2923 | { | ||
2924 | current_drive->UPC_buf[i]=((*p++)<<4)&0xFF; | ||
2925 | current_drive->UPC_buf[i] |= *p++; | ||
2926 | } | ||
2927 | else if (famT_drive) | ||
2928 | { | ||
2929 | return (-1); | ||
2930 | } | ||
2931 | else /* CD200 */ | ||
2932 | { | ||
2933 | return (-1); | ||
2934 | } | ||
2935 | } | ||
2936 | current_drive->UPC_buf[6] &= 0xF0; | ||
2937 | return (0); | ||
2938 | } | ||
2939 | /*==========================================================================*/ | ||
2940 | static int cc_ReadUPC(void) | ||
2941 | { | ||
2942 | int i; | ||
2943 | #if TEST_UPC | ||
2944 | int block, checksum; | ||
2945 | #endif /* TEST_UPC */ | ||
2946 | |||
2947 | if (fam2_drive) return (0); /* not implemented yet */ | ||
2948 | if (famT_drive) return (0); /* not implemented yet */ | ||
2949 | if (famV_drive) return (0); /* not implemented yet */ | ||
2950 | #if 1 | ||
2951 | if (fam0_drive) return (0); /* but it should work */ | ||
2952 | #endif | ||
2953 | |||
2954 | current_drive->diskstate_flags &= ~upc_bit; | ||
2955 | #if TEST_UPC | ||
2956 | for (block=CD_MSF_OFFSET+1;block<CD_MSF_OFFSET+200;block++) | ||
2957 | { | ||
2958 | #endif /* TEST_UPC */ | ||
2959 | clr_cmdbuf(); | ||
2960 | if (fam1_drive) | ||
2961 | { | ||
2962 | drvcmd[0]=CMD1_READ_UPC; | ||
2963 | #if TEST_UPC | ||
2964 | drvcmd[1]=(block>>16)&0xFF; | ||
2965 | drvcmd[2]=(block>>8)&0xFF; | ||
2966 | drvcmd[3]=block&0xFF; | ||
2967 | #endif /* TEST_UPC */ | ||
2968 | response_count=8; | ||
2969 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
2970 | } | ||
2971 | else if (fam0L_drive) | ||
2972 | { | ||
2973 | drvcmd[0]=CMD0_READ_UPC; | ||
2974 | #if TEST_UPC | ||
2975 | drvcmd[2]=(block>>16)&0xFF; | ||
2976 | drvcmd[3]=(block>>8)&0xFF; | ||
2977 | drvcmd[4]=block&0xFF; | ||
2978 | #endif /* TEST_UPC */ | ||
2979 | response_count=0; | ||
2980 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
2981 | } | ||
2982 | else if (fam2_drive) | ||
2983 | { | ||
2984 | return (-1); | ||
2985 | } | ||
2986 | else if (famT_drive) | ||
2987 | { | ||
2988 | return (-1); | ||
2989 | } | ||
2990 | i=cmd_out(); | ||
2991 | if (i<0) | ||
2992 | { | ||
2993 | msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i); | ||
2994 | return (i); | ||
2995 | } | ||
2996 | if (fam0L_drive) | ||
2997 | { | ||
2998 | response_count=16; | ||
2999 | if (famL_drive) flags_cmd_out=f_putcmd; | ||
3000 | i=cc_ReadPacket(); | ||
3001 | if (i<0) | ||
3002 | { | ||
3003 | msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i); | ||
3004 | return (i); | ||
3005 | } | ||
3006 | } | ||
3007 | #if TEST_UPC | ||
3008 | checksum=0; | ||
3009 | #endif /* TEST_UPC */ | ||
3010 | for (i=0;i<(fam1_drive?8:16);i++) | ||
3011 | { | ||
3012 | #if TEST_UPC | ||
3013 | checksum |= infobuf[i]; | ||
3014 | #endif /* TEST_UPC */ | ||
3015 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3016 | } | ||
3017 | msgbuf[i*3]=0; | ||
3018 | msg(DBG_UPC,"UPC info:%s\n", msgbuf); | ||
3019 | #if TEST_UPC | ||
3020 | if ((checksum&0x7F)!=0) break; | ||
3021 | } | ||
3022 | #endif /* TEST_UPC */ | ||
3023 | current_drive->UPC_ctl_adr=0; | ||
3024 | if (fam1_drive) i=0; | ||
3025 | else i=2; | ||
3026 | if ((infobuf[i]&0x80)!=0) | ||
3027 | { | ||
3028 | convert_UPC(&infobuf[i]); | ||
3029 | current_drive->UPC_ctl_adr = (current_drive->TocEnt_ctl_adr & 0xF0) | 0x02; | ||
3030 | } | ||
3031 | for (i=0;i<7;i++) | ||
3032 | sprintf(&msgbuf[i*3], " %02X", current_drive->UPC_buf[i]); | ||
3033 | sprintf(&msgbuf[i*3], " (%02X)", current_drive->UPC_ctl_adr); | ||
3034 | msgbuf[i*3+5]=0; | ||
3035 | msg(DBG_UPC,"UPC code:%s\n", msgbuf); | ||
3036 | current_drive->diskstate_flags |= upc_bit; | ||
3037 | return (0); | ||
3038 | } | ||
3039 | |||
3040 | static int sbpcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) | ||
3041 | { | ||
3042 | int i; | ||
3043 | unsigned char *mcnp = mcn->medium_catalog_number; | ||
3044 | unsigned char *resp; | ||
3045 | |||
3046 | current_drive->diskstate_flags &= ~upc_bit; | ||
3047 | clr_cmdbuf(); | ||
3048 | if (fam1_drive) | ||
3049 | { | ||
3050 | drvcmd[0]=CMD1_READ_UPC; | ||
3051 | response_count=8; | ||
3052 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
3053 | } | ||
3054 | else if (fam0L_drive) | ||
3055 | { | ||
3056 | drvcmd[0]=CMD0_READ_UPC; | ||
3057 | response_count=0; | ||
3058 | flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; | ||
3059 | } | ||
3060 | else if (fam2_drive) | ||
3061 | { | ||
3062 | return (-1); | ||
3063 | } | ||
3064 | else if (famT_drive) | ||
3065 | { | ||
3066 | return (-1); | ||
3067 | } | ||
3068 | i=cmd_out(); | ||
3069 | if (i<0) | ||
3070 | { | ||
3071 | msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i); | ||
3072 | return (i); | ||
3073 | } | ||
3074 | if (fam0L_drive) | ||
3075 | { | ||
3076 | response_count=16; | ||
3077 | if (famL_drive) flags_cmd_out=f_putcmd; | ||
3078 | i=cc_ReadPacket(); | ||
3079 | if (i<0) | ||
3080 | { | ||
3081 | msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i); | ||
3082 | return (i); | ||
3083 | } | ||
3084 | } | ||
3085 | current_drive->UPC_ctl_adr=0; | ||
3086 | if (fam1_drive) i=0; | ||
3087 | else i=2; | ||
3088 | |||
3089 | resp = infobuf + i; | ||
3090 | if (*resp++ == 0x80) { | ||
3091 | /* packed bcd to single ASCII digits */ | ||
3092 | *mcnp++ = (*resp >> 4) + '0'; | ||
3093 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3094 | *mcnp++ = (*resp >> 4) + '0'; | ||
3095 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3096 | *mcnp++ = (*resp >> 4) + '0'; | ||
3097 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3098 | *mcnp++ = (*resp >> 4) + '0'; | ||
3099 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3100 | *mcnp++ = (*resp >> 4) + '0'; | ||
3101 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3102 | *mcnp++ = (*resp >> 4) + '0'; | ||
3103 | *mcnp++ = (*resp++ & 0x0f) + '0'; | ||
3104 | *mcnp++ = (*resp >> 4) + '0'; | ||
3105 | } | ||
3106 | *mcnp = '\0'; | ||
3107 | |||
3108 | current_drive->diskstate_flags |= upc_bit; | ||
3109 | return (0); | ||
3110 | } | ||
3111 | |||
3112 | /*==========================================================================*/ | ||
3113 | static int cc_CheckMultiSession(void) | ||
3114 | { | ||
3115 | int i; | ||
3116 | |||
3117 | if (fam2_drive) return (0); | ||
3118 | current_drive->f_multisession=0; | ||
3119 | current_drive->lba_multi=0; | ||
3120 | if (fam0_drive) return (0); | ||
3121 | clr_cmdbuf(); | ||
3122 | if (fam1_drive) | ||
3123 | { | ||
3124 | drvcmd[0]=CMD1_MULTISESS; | ||
3125 | response_count=6; | ||
3126 | flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; | ||
3127 | i=cmd_out(); | ||
3128 | if (i<0) return (i); | ||
3129 | if ((infobuf[0]&0x80)!=0) | ||
3130 | { | ||
3131 | current_drive->f_multisession=1; | ||
3132 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[1]), | ||
3133 | make16(infobuf[2],infobuf[3]))); | ||
3134 | } | ||
3135 | } | ||
3136 | else if (famLV_drive) | ||
3137 | { | ||
3138 | drvcmd[0]=CMDL_MULTISESS; | ||
3139 | drvcmd[1]=3; | ||
3140 | drvcmd[2]=1; | ||
3141 | response_count=8; | ||
3142 | flags_cmd_out=f_putcmd; | ||
3143 | i=cmd_out(); | ||
3144 | if (i<0) return (i); | ||
3145 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]), | ||
3146 | make16(infobuf[6],infobuf[7]))); | ||
3147 | } | ||
3148 | else if (famT_drive) | ||
3149 | { | ||
3150 | response_count=12; | ||
3151 | drvcmd[0]=CMDT_DISKINFO; | ||
3152 | drvcmd[1]=0x02; | ||
3153 | drvcmd[6]=0; | ||
3154 | drvcmd[8]=response_count; | ||
3155 | drvcmd[9]=0x40; | ||
3156 | i=cmd_out(); | ||
3157 | if (i<0) return (i); | ||
3158 | if (i<response_count) return (-100-i); | ||
3159 | current_drive->first_session=infobuf[2]; | ||
3160 | current_drive->last_session=infobuf[3]; | ||
3161 | current_drive->track_of_last_session=infobuf[6]; | ||
3162 | if (current_drive->first_session!=current_drive->last_session) | ||
3163 | { | ||
3164 | current_drive->f_multisession=1; | ||
3165 | current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11]))); | ||
3166 | } | ||
3167 | } | ||
3168 | for (i=0;i<response_count;i++) | ||
3169 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3170 | msgbuf[i*3]=0; | ||
3171 | msg(DBG_MUL,"MultiSession Info:%s (%d)\n", msgbuf, current_drive->lba_multi); | ||
3172 | if (current_drive->lba_multi>200) | ||
3173 | { | ||
3174 | current_drive->f_multisession=1; | ||
3175 | msg(DBG_MUL,"MultiSession base: %06X\n", current_drive->lba_multi); | ||
3176 | } | ||
3177 | return (0); | ||
3178 | } | ||
3179 | /*==========================================================================*/ | ||
3180 | #ifdef FUTURE | ||
3181 | static int cc_SubChanInfo(int frame, int count, u_char *buffer) | ||
3182 | /* "frame" is a RED BOOK (msf-bin) address */ | ||
3183 | { | ||
3184 | int i; | ||
3185 | |||
3186 | if (fam0LV_drive) return (-ENOSYS); /* drive firmware lacks it */ | ||
3187 | if (famT_drive) | ||
3188 | { | ||
3189 | return (-1); | ||
3190 | } | ||
3191 | #if 0 | ||
3192 | if (current_drive->audio_state!=audio_playing) return (-ENODATA); | ||
3193 | #endif | ||
3194 | clr_cmdbuf(); | ||
3195 | drvcmd[0]=CMD1_SUBCHANINF; | ||
3196 | drvcmd[1]=(frame>>16)&0xFF; | ||
3197 | drvcmd[2]=(frame>>8)&0xFF; | ||
3198 | drvcmd[3]=frame&0xFF; | ||
3199 | drvcmd[5]=(count>>8)&0xFF; | ||
3200 | drvcmd[6]=count&0xFF; | ||
3201 | flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; | ||
3202 | cmd_type=READ_SC; | ||
3203 | current_drive->frame_size=CD_FRAMESIZE_SUB; | ||
3204 | i=cmd_out(); /* which buffer to use? */ | ||
3205 | return (i); | ||
3206 | } | ||
3207 | #endif /* FUTURE */ | ||
3208 | /*==========================================================================*/ | ||
3209 | static void __init check_datarate(void) | ||
3210 | { | ||
3211 | int i=0; | ||
3212 | |||
3213 | msg(DBG_IOX,"check_datarate entered.\n"); | ||
3214 | datarate=0; | ||
3215 | #if TEST_STI | ||
3216 | for (i=0;i<=1000;i++) printk("."); | ||
3217 | #endif | ||
3218 | /* set a timer to make (timed_out_delay!=0) after 1.1 seconds */ | ||
3219 | #if 1 | ||
3220 | del_timer(&delay_timer); | ||
3221 | #endif | ||
3222 | delay_timer.expires=jiffies+11*HZ/10; | ||
3223 | timed_out_delay=0; | ||
3224 | add_timer(&delay_timer); | ||
3225 | #if 0 | ||
3226 | msg(DBG_TIM,"delay timer started (11*HZ/10).\n"); | ||
3227 | #endif | ||
3228 | do | ||
3229 | { | ||
3230 | i=inb(CDi_status); | ||
3231 | datarate++; | ||
3232 | #if 1 | ||
3233 | if (datarate>0x6FFFFFFF) break; | ||
3234 | #endif | ||
3235 | } | ||
3236 | while (!timed_out_delay); | ||
3237 | del_timer(&delay_timer); | ||
3238 | #if 0 | ||
3239 | msg(DBG_TIM,"datarate: %04X\n", datarate); | ||
3240 | #endif | ||
3241 | if (datarate<65536) datarate=65536; | ||
3242 | maxtim16=datarate*16; | ||
3243 | maxtim04=datarate*4; | ||
3244 | maxtim02=datarate*2; | ||
3245 | maxtim_8=datarate/32; | ||
3246 | #if LONG_TIMING | ||
3247 | maxtim_data=datarate/100; | ||
3248 | #else | ||
3249 | maxtim_data=datarate/300; | ||
3250 | #endif /* LONG_TIMING */ | ||
3251 | #if 0 | ||
3252 | msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data); | ||
3253 | #endif | ||
3254 | } | ||
3255 | /*==========================================================================*/ | ||
3256 | #if 0 | ||
3257 | static int c2_ReadError(int fam) | ||
3258 | { | ||
3259 | int i; | ||
3260 | |||
3261 | clr_cmdbuf(); | ||
3262 | response_count=9; | ||
3263 | clr_respo_buf(9); | ||
3264 | if (fam==1) | ||
3265 | { | ||
3266 | drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */ | ||
3267 | i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus); | ||
3268 | } | ||
3269 | else if (fam==2) | ||
3270 | { | ||
3271 | drvcmd[0]=CMD2_READ_ERR; | ||
3272 | i=do_cmd(f_putcmd); | ||
3273 | } | ||
3274 | else return (-1); | ||
3275 | return (i); | ||
3276 | } | ||
3277 | #endif | ||
3278 | /*==========================================================================*/ | ||
3279 | static void __init ask_mail(void) | ||
3280 | { | ||
3281 | int i; | ||
3282 | |||
3283 | msg(DBG_INF, "please mail the following lines to emoenke@gwdg.de\n"); | ||
3284 | msg(DBG_INF, "(don't mail if you are not using the actual kernel):\n"); | ||
3285 | msg(DBG_INF, "%s\n", VERSION); | ||
3286 | msg(DBG_INF, "address %03X, type %s, drive %s (ID %d)\n", | ||
3287 | CDo_command, type, current_drive->drive_model, current_drive->drv_id); | ||
3288 | for (i=0;i<12;i++) | ||
3289 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3290 | msgbuf[i*3]=0; | ||
3291 | msg(DBG_INF,"infobuf =%s\n", msgbuf); | ||
3292 | for (i=0;i<12;i++) | ||
3293 | sprintf(&msgbuf[i*3], " %c ", infobuf[i]); | ||
3294 | msgbuf[i*3]=0; | ||
3295 | msg(DBG_INF,"infobuf =%s\n", msgbuf); | ||
3296 | } | ||
3297 | /*==========================================================================*/ | ||
3298 | static int __init check_version(void) | ||
3299 | { | ||
3300 | int i, j, l; | ||
3301 | int teac_possible=0; | ||
3302 | |||
3303 | msg(DBG_INI,"check_version: id=%d, d=%d.\n", current_drive->drv_id, current_drive - D_S); | ||
3304 | current_drive->drv_type=0; | ||
3305 | |||
3306 | /* check for CR-52x, CR-56x, LCS-7260 and ECS-AT */ | ||
3307 | /* clear any pending error state */ | ||
3308 | clr_cmdbuf(); | ||
3309 | drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */ | ||
3310 | response_count=9; | ||
3311 | flags_cmd_out=f_putcmd; | ||
3312 | i=cmd_out(); | ||
3313 | if (i<0) msg(DBG_INI,"CMD0_READ_ERR returns %d (ok anyway).\n",i); | ||
3314 | /* read drive version */ | ||
3315 | clr_cmdbuf(); | ||
3316 | for (i=0;i<12;i++) infobuf[i]=0; | ||
3317 | drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */ | ||
3318 | response_count=12; /* fam1: only 11 */ | ||
3319 | flags_cmd_out=f_putcmd; | ||
3320 | i=cmd_out(); | ||
3321 | if (i<-1) msg(DBG_INI,"CMD0_READ_VER returns %d\n",i); | ||
3322 | if (i==-11) teac_possible++; | ||
3323 | j=0; | ||
3324 | for (i=0;i<12;i++) j+=infobuf[i]; | ||
3325 | if (j) | ||
3326 | { | ||
3327 | for (i=0;i<12;i++) | ||
3328 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3329 | msgbuf[i*3]=0; | ||
3330 | msg(DBG_ECS,"infobuf =%s\n", msgbuf); | ||
3331 | for (i=0;i<12;i++) | ||
3332 | sprintf(&msgbuf[i*3], " %c ", infobuf[i]); | ||
3333 | msgbuf[i*3]=0; | ||
3334 | msg(DBG_ECS,"infobuf =%s\n", msgbuf); | ||
3335 | } | ||
3336 | for (i=0;i<4;i++) if (infobuf[i]!=family1[i]) break; | ||
3337 | if (i==4) | ||
3338 | { | ||
3339 | current_drive->drive_model[0]='C'; | ||
3340 | current_drive->drive_model[1]='R'; | ||
3341 | current_drive->drive_model[2]='-'; | ||
3342 | current_drive->drive_model[3]='5'; | ||
3343 | current_drive->drive_model[4]=infobuf[i++]; | ||
3344 | current_drive->drive_model[5]=infobuf[i++]; | ||
3345 | current_drive->drive_model[6]=0; | ||
3346 | current_drive->drv_type=drv_fam1; | ||
3347 | } | ||
3348 | if (!current_drive->drv_type) | ||
3349 | { | ||
3350 | for (i=0;i<8;i++) if (infobuf[i]!=family0[i]) break; | ||
3351 | if (i==8) | ||
3352 | { | ||
3353 | current_drive->drive_model[0]='C'; | ||
3354 | current_drive->drive_model[1]='R'; | ||
3355 | current_drive->drive_model[2]='-'; | ||
3356 | current_drive->drive_model[3]='5'; | ||
3357 | current_drive->drive_model[4]='2'; | ||
3358 | current_drive->drive_model[5]='x'; | ||
3359 | current_drive->drive_model[6]=0; | ||
3360 | current_drive->drv_type=drv_fam0; | ||
3361 | } | ||
3362 | } | ||
3363 | if (!current_drive->drv_type) | ||
3364 | { | ||
3365 | for (i=0;i<8;i++) if (infobuf[i]!=familyL[i]) break; | ||
3366 | if (i==8) | ||
3367 | { | ||
3368 | for (j=0;j<8;j++) | ||
3369 | current_drive->drive_model[j]=infobuf[j]; | ||
3370 | current_drive->drive_model[8]=0; | ||
3371 | current_drive->drv_type=drv_famL; | ||
3372 | } | ||
3373 | } | ||
3374 | if (!current_drive->drv_type) | ||
3375 | { | ||
3376 | for (i=0;i<6;i++) if (infobuf[i]!=familyV[i]) break; | ||
3377 | if (i==6) | ||
3378 | { | ||
3379 | for (j=0;j<6;j++) | ||
3380 | current_drive->drive_model[j]=infobuf[j]; | ||
3381 | current_drive->drive_model[6]=0; | ||
3382 | current_drive->drv_type=drv_famV; | ||
3383 | i+=2; /* 2 blanks before version */ | ||
3384 | } | ||
3385 | } | ||
3386 | if (!current_drive->drv_type) | ||
3387 | { | ||
3388 | /* check for CD200 */ | ||
3389 | clr_cmdbuf(); | ||
3390 | drvcmd[0]=CMD2_READ_ERR; | ||
3391 | response_count=9; | ||
3392 | flags_cmd_out=f_putcmd; | ||
3393 | i=cmd_out(); | ||
3394 | if (i<0) msg(DBG_INI,"CMD2_READERR returns %d (ok anyway).\n",i); | ||
3395 | if (i<0) msg(DBG_000,"CMD2_READERR returns %d (ok anyway).\n",i); | ||
3396 | /* read drive version */ | ||
3397 | clr_cmdbuf(); | ||
3398 | for (i=0;i<12;i++) infobuf[i]=0; | ||
3399 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
3400 | #if 0 | ||
3401 | OUT(CDo_reset,0); | ||
3402 | sbp_sleep(6*HZ); | ||
3403 | OUT(CDo_enable,current_drive->drv_sel); | ||
3404 | #endif | ||
3405 | drvcmd[0]=CMD2_READ_VER; | ||
3406 | response_count=12; | ||
3407 | flags_cmd_out=f_putcmd; | ||
3408 | i=cmd_out(); | ||
3409 | if (i<0) msg(DBG_INI,"CMD2_READ_VER returns %d\n",i); | ||
3410 | if (i==-7) teac_possible++; | ||
3411 | j=0; | ||
3412 | for (i=0;i<12;i++) j+=infobuf[i]; | ||
3413 | if (j) | ||
3414 | { | ||
3415 | for (i=0;i<12;i++) | ||
3416 | sprintf(&msgbuf[i*3], " %02X", infobuf[i]); | ||
3417 | msgbuf[i*3]=0; | ||
3418 | msg(DBG_IDX,"infobuf =%s\n", msgbuf); | ||
3419 | for (i=0;i<12;i++) | ||
3420 | sprintf(&msgbuf[i*3], " %c ", infobuf[i]); | ||
3421 | msgbuf[i*3]=0; | ||
3422 | msg(DBG_IDX,"infobuf =%s\n", msgbuf); | ||
3423 | } | ||
3424 | if (i>=0) | ||
3425 | { | ||
3426 | for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break; | ||
3427 | if (i==5) | ||
3428 | { | ||
3429 | current_drive->drive_model[0]='C'; | ||
3430 | current_drive->drive_model[1]='D'; | ||
3431 | current_drive->drive_model[2]='2'; | ||
3432 | current_drive->drive_model[3]='0'; | ||
3433 | current_drive->drive_model[4]='0'; | ||
3434 | current_drive->drive_model[5]=infobuf[i++]; | ||
3435 | current_drive->drive_model[6]=infobuf[i++]; | ||
3436 | current_drive->drive_model[7]=0; | ||
3437 | current_drive->drv_type=drv_fam2; | ||
3438 | } | ||
3439 | } | ||
3440 | } | ||
3441 | if (!current_drive->drv_type) | ||
3442 | { | ||
3443 | /* check for TEAC CD-55A */ | ||
3444 | msg(DBG_TEA,"teac_possible: %d\n",teac_possible); | ||
3445 | for (j=1;j<=((current_drive->drv_id==0)?3:1);j++) | ||
3446 | { | ||
3447 | for (l=1;l<=((current_drive->drv_id==0)?10:1);l++) | ||
3448 | { | ||
3449 | msg(DBG_TEA,"TEAC reset #%d-%d.\n", j, l); | ||
3450 | if (sbpro_type==1) OUT(CDo_reset,0); | ||
3451 | else | ||
3452 | { | ||
3453 | OUT(CDo_enable,current_drive->drv_sel); | ||
3454 | OUT(CDo_sel_i_d,0); | ||
3455 | OUT(CDo_command,CMDT_RESET); | ||
3456 | for (i=0;i<9;i++) OUT(CDo_command,0); | ||
3457 | } | ||
3458 | sbp_sleep(5*HZ/10); | ||
3459 | OUT(CDo_enable,current_drive->drv_sel); | ||
3460 | OUT(CDo_sel_i_d,0); | ||
3461 | i=inb(CDi_status); | ||
3462 | msg(DBG_TEA,"TEAC CDi_status: %02X.\n",i); | ||
3463 | #if 0 | ||
3464 | if (i&s_not_result_ready) continue; /* drive not present or ready */ | ||
3465 | #endif | ||
3466 | i=inb(CDi_info); | ||
3467 | msg(DBG_TEA,"TEAC CDi_info: %02X.\n",i); | ||
3468 | if (i==0x55) break; /* drive found */ | ||
3469 | } | ||
3470 | if (i==0x55) break; /* drive found */ | ||
3471 | } | ||
3472 | if (i==0x55) /* drive found */ | ||
3473 | { | ||
3474 | msg(DBG_TEA,"TEAC drive found.\n"); | ||
3475 | clr_cmdbuf(); | ||
3476 | flags_cmd_out=f_putcmd; | ||
3477 | response_count=12; | ||
3478 | drvcmd[0]=CMDT_READ_VER; | ||
3479 | drvcmd[4]=response_count; | ||
3480 | for (i=0;i<12;i++) infobuf[i]=0; | ||
3481 | i=cmd_out_T(); | ||
3482 | if (i!=0) msg(DBG_TEA,"cmd_out_T(CMDT_READ_VER) returns %d.\n",i); | ||
3483 | for (i=1;i<6;i++) if (infobuf[i]!=familyT[i-1]) break; | ||
3484 | if (i==6) | ||
3485 | { | ||
3486 | current_drive->drive_model[0]='C'; | ||
3487 | current_drive->drive_model[1]='D'; | ||
3488 | current_drive->drive_model[2]='-'; | ||
3489 | current_drive->drive_model[3]='5'; | ||
3490 | current_drive->drive_model[4]='5'; | ||
3491 | current_drive->drive_model[5]=0; | ||
3492 | current_drive->drv_type=drv_famT; | ||
3493 | } | ||
3494 | } | ||
3495 | } | ||
3496 | if (!current_drive->drv_type) | ||
3497 | { | ||
3498 | msg(DBG_TEA,"no drive found at address %03X under ID %d.\n",CDo_command,current_drive->drv_id); | ||
3499 | return (-522); | ||
3500 | } | ||
3501 | for (j=0;j<4;j++) current_drive->firmware_version[j]=infobuf[i+j]; | ||
3502 | if (famL_drive) | ||
3503 | { | ||
3504 | u_char lcs_firm_e1[]="A E1"; | ||
3505 | u_char lcs_firm_f4[]="A4F4"; | ||
3506 | |||
3507 | for (j=0;j<4;j++) | ||
3508 | if (current_drive->firmware_version[j]!=lcs_firm_e1[j]) break; | ||
3509 | if (j==4) current_drive->drv_type=drv_e1; | ||
3510 | |||
3511 | for (j=0;j<4;j++) | ||
3512 | if (current_drive->firmware_version[j]!=lcs_firm_f4[j]) break; | ||
3513 | if (j==4) current_drive->drv_type=drv_f4; | ||
3514 | |||
3515 | if (current_drive->drv_type==drv_famL) ask_mail(); | ||
3516 | } | ||
3517 | else if (famT_drive) | ||
3518 | { | ||
3519 | j=infobuf[4]; /* one-byte version??? - here: 0x15 */ | ||
3520 | if (j=='5') | ||
3521 | { | ||
3522 | current_drive->firmware_version[0]=infobuf[7]; | ||
3523 | current_drive->firmware_version[1]=infobuf[8]; | ||
3524 | current_drive->firmware_version[2]=infobuf[10]; | ||
3525 | current_drive->firmware_version[3]=infobuf[11]; | ||
3526 | } | ||
3527 | else | ||
3528 | { | ||
3529 | if (j!=0x15) ask_mail(); | ||
3530 | current_drive->firmware_version[0]='0'; | ||
3531 | current_drive->firmware_version[1]='.'; | ||
3532 | current_drive->firmware_version[2]='0'+(j>>4); | ||
3533 | current_drive->firmware_version[3]='0'+(j&0x0f); | ||
3534 | } | ||
3535 | } | ||
3536 | else /* CR-52x, CR-56x, CD200, ECS-AT */ | ||
3537 | { | ||
3538 | j = (current_drive->firmware_version[0] & 0x0F) * 100 + | ||
3539 | (current_drive->firmware_version[2] & 0x0F) *10 + | ||
3540 | (current_drive->firmware_version[3] & 0x0F); | ||
3541 | if (fam0_drive) | ||
3542 | { | ||
3543 | if (j<200) current_drive->drv_type=drv_199; | ||
3544 | else if (j<201) current_drive->drv_type=drv_200; | ||
3545 | else if (j<210) current_drive->drv_type=drv_201; | ||
3546 | else if (j<211) current_drive->drv_type=drv_210; | ||
3547 | else if (j<300) current_drive->drv_type=drv_211; | ||
3548 | else if (j>=300) current_drive->drv_type=drv_300; | ||
3549 | } | ||
3550 | else if (fam1_drive) | ||
3551 | { | ||
3552 | if (j<100) current_drive->drv_type=drv_099; | ||
3553 | else | ||
3554 | { | ||
3555 | current_drive->drv_type=drv_100; | ||
3556 | if ((j!=500)&&(j!=102)) ask_mail(); | ||
3557 | } | ||
3558 | } | ||
3559 | else if (fam2_drive) | ||
3560 | { | ||
3561 | if (current_drive->drive_model[5]=='F') | ||
3562 | { | ||
3563 | if ((j!=1)&&(j!=35)&&(j!=200)&&(j!=210)) | ||
3564 | ask_mail(); /* unknown version at time */ | ||
3565 | } | ||
3566 | else | ||
3567 | { | ||
3568 | msg(DBG_INF,"this CD200 drive is not fully supported yet - only audio will work.\n"); | ||
3569 | if ((j!=101)&&(j!=35)) | ||
3570 | ask_mail(); /* unknown version at time */ | ||
3571 | } | ||
3572 | } | ||
3573 | else if (famV_drive) | ||
3574 | { | ||
3575 | if ((j==100)||(j==150)) current_drive->drv_type=drv_at; | ||
3576 | ask_mail(); /* hopefully we get some feedback by this */ | ||
3577 | } | ||
3578 | } | ||
3579 | msg(DBG_LCS,"drive type %02X\n",current_drive->drv_type); | ||
3580 | msg(DBG_INI,"check_version done.\n"); | ||
3581 | return (0); | ||
3582 | } | ||
3583 | /*==========================================================================*/ | ||
3584 | static void switch_drive(struct sbpcd_drive *p) | ||
3585 | { | ||
3586 | current_drive = p; | ||
3587 | OUT(CDo_enable,current_drive->drv_sel); | ||
3588 | msg(DBG_DID,"drive %d (ID=%d) activated.\n", | ||
3589 | current_drive - D_S, current_drive->drv_id); | ||
3590 | return; | ||
3591 | } | ||
3592 | /*==========================================================================*/ | ||
3593 | #ifdef PATH_CHECK | ||
3594 | /* | ||
3595 | * probe for the presence of an interface card | ||
3596 | */ | ||
3597 | static int __init check_card(int port) | ||
3598 | { | ||
3599 | #undef N_RESPO | ||
3600 | #define N_RESPO 20 | ||
3601 | int i, j, k; | ||
3602 | u_char response[N_RESPO]; | ||
3603 | u_char save_port0; | ||
3604 | u_char save_port3; | ||
3605 | |||
3606 | msg(DBG_INI,"check_card entered.\n"); | ||
3607 | save_port0=inb(port+0); | ||
3608 | save_port3=inb(port+3); | ||
3609 | |||
3610 | for (j=0;j<NR_SBPCD;j++) | ||
3611 | { | ||
3612 | OUT(port+3,j) ; /* enable drive #j */ | ||
3613 | OUT(port+0,CMD0_PATH_CHECK); | ||
3614 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3615 | for (k=0;k<N_RESPO;k++) response[k]=0; | ||
3616 | for (k=0;k<N_RESPO;k++) | ||
3617 | { | ||
3618 | for (i=10000;i>0;i--) | ||
3619 | { | ||
3620 | if (inb(port+1)&s_not_result_ready) continue; | ||
3621 | response[k]=inb(port+0); | ||
3622 | break; | ||
3623 | } | ||
3624 | } | ||
3625 | for (i=0;i<N_RESPO;i++) | ||
3626 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3627 | msgbuf[i*3]=0; | ||
3628 | msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf); | ||
3629 | OUT(port+0,CMD0_PATH_CHECK); | ||
3630 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3631 | for (k=0;k<N_RESPO;k++) response[k]=0xFF; | ||
3632 | for (k=0;k<N_RESPO;k++) | ||
3633 | { | ||
3634 | for (i=10000;i>0;i--) | ||
3635 | { | ||
3636 | if (inb(port+1)&s_not_result_ready) continue; | ||
3637 | response[k]=inb(port+0); | ||
3638 | break; | ||
3639 | } | ||
3640 | } | ||
3641 | for (i=0;i<N_RESPO;i++) | ||
3642 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3643 | msgbuf[i*3]=0; | ||
3644 | msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf); | ||
3645 | |||
3646 | if (response[0]==0xAA) | ||
3647 | if (response[1]==0x55) | ||
3648 | return (0); | ||
3649 | } | ||
3650 | for (j=0;j<NR_SBPCD;j++) | ||
3651 | { | ||
3652 | OUT(port+3,j) ; /* enable drive #j */ | ||
3653 | OUT(port+0,CMD2_READ_VER); | ||
3654 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3655 | for (k=0;k<N_RESPO;k++) response[k]=0; | ||
3656 | for (k=0;k<N_RESPO;k++) | ||
3657 | { | ||
3658 | for (i=1000000;i>0;i--) | ||
3659 | { | ||
3660 | if (inb(port+1)&s_not_result_ready) continue; | ||
3661 | response[k]=inb(port+0); | ||
3662 | break; | ||
3663 | } | ||
3664 | } | ||
3665 | for (i=0;i<N_RESPO;i++) | ||
3666 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3667 | msgbuf[i*3]=0; | ||
3668 | msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf); | ||
3669 | |||
3670 | OUT(port+0,CMD2_READ_VER); | ||
3671 | for (i=10;i>0;i--) OUT(port+0,0); | ||
3672 | for (k=0;k<N_RESPO;k++) response[k]=0xFF; | ||
3673 | for (k=0;k<N_RESPO;k++) | ||
3674 | { | ||
3675 | for (i=1000000;i>0;i--) | ||
3676 | { | ||
3677 | if (inb(port+1)&s_not_result_ready) continue; | ||
3678 | response[k]=inb(port+0); | ||
3679 | break; | ||
3680 | } | ||
3681 | } | ||
3682 | for (i=0;i<N_RESPO;i++) | ||
3683 | sprintf(&msgbuf[i*3], " %02X", response[i]); | ||
3684 | msgbuf[i*3]=0; | ||
3685 | msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf); | ||
3686 | |||
3687 | if (response[0]==0xAA) | ||
3688 | if (response[1]==0x55) | ||
3689 | return (0); | ||
3690 | } | ||
3691 | OUT(port+0,save_port0); | ||
3692 | OUT(port+3,save_port3); | ||
3693 | return (0); /* in any case - no real "function" at time */ | ||
3694 | } | ||
3695 | #endif /* PATH_CHECK */ | ||
3696 | /*==========================================================================*/ | ||
3697 | /*==========================================================================*/ | ||
3698 | /* | ||
3699 | * probe for the presence of drives on the selected controller | ||
3700 | */ | ||
3701 | static int __init check_drives(void) | ||
3702 | { | ||
3703 | int i, j; | ||
3704 | |||
3705 | msg(DBG_INI,"check_drives entered.\n"); | ||
3706 | ndrives=0; | ||
3707 | for (j=0;j<max_drives;j++) | ||
3708 | { | ||
3709 | struct sbpcd_drive *p = D_S + ndrives; | ||
3710 | p->drv_id=j; | ||
3711 | if (sbpro_type==1) p->drv_sel=(j&0x01)<<1|(j&0x02)>>1; | ||
3712 | else p->drv_sel=j; | ||
3713 | switch_drive(p); | ||
3714 | msg(DBG_INI,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j); | ||
3715 | msg(DBG_000,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j); | ||
3716 | i=check_version(); | ||
3717 | if (i<0) msg(DBG_INI,"check_version returns %d.\n",i); | ||
3718 | else | ||
3719 | { | ||
3720 | current_drive->drv_options=drv_pattern[j]; | ||
3721 | if (fam0L_drive) current_drive->drv_options&=~(speed_auto|speed_300|speed_150); | ||
3722 | msg(DBG_INF, "Drive %d (ID=%d): %.9s (%.4s) at 0x%03X (type %d)\n", | ||
3723 | current_drive - D_S, | ||
3724 | current_drive->drv_id, | ||
3725 | current_drive->drive_model, | ||
3726 | current_drive->firmware_version, | ||
3727 | CDo_command, | ||
3728 | sbpro_type); | ||
3729 | ndrives++; | ||
3730 | } | ||
3731 | } | ||
3732 | for (j=ndrives;j<NR_SBPCD;j++) D_S[j].drv_id=-1; | ||
3733 | if (ndrives==0) return (-1); | ||
3734 | return (0); | ||
3735 | } | ||
3736 | /*==========================================================================*/ | ||
3737 | #ifdef FUTURE | ||
3738 | /* | ||
3739 | * obtain if requested service disturbs current audio state | ||
3740 | */ | ||
3741 | static int obey_audio_state(u_char audio_state, u_char func,u_char subfunc) | ||
3742 | { | ||
3743 | switch (audio_state) /* audio status from controller */ | ||
3744 | { | ||
3745 | case aud_11: /* "audio play in progress" */ | ||
3746 | case audx11: | ||
3747 | switch (func) /* DOS command code */ | ||
3748 | { | ||
3749 | case cmd_07: /* input flush */ | ||
3750 | case cmd_0d: /* open device */ | ||
3751 | case cmd_0e: /* close device */ | ||
3752 | case cmd_0c: /* ioctl output */ | ||
3753 | return (1); | ||
3754 | case cmd_03: /* ioctl input */ | ||
3755 | switch (subfunc) | ||
3756 | /* DOS ioctl input subfunction */ | ||
3757 | { | ||
3758 | case cxi_00: | ||
3759 | case cxi_06: | ||
3760 | case cxi_09: | ||
3761 | return (1); | ||
3762 | default: | ||
3763 | return (ERROR15); | ||
3764 | } | ||
3765 | return (1); | ||
3766 | default: | ||
3767 | return (ERROR15); | ||
3768 | } | ||
3769 | return (1); | ||
3770 | case aud_12: /* "audio play paused" */ | ||
3771 | case audx12: | ||
3772 | return (1); | ||
3773 | default: | ||
3774 | return (2); | ||
3775 | } | ||
3776 | } | ||
3777 | /*==========================================================================*/ | ||
3778 | /* allowed is only | ||
3779 | * ioctl_o, flush_input, open_device, close_device, | ||
3780 | * tell_address, tell_volume, tell_capabiliti, | ||
3781 | * tell_framesize, tell_CD_changed, tell_audio_posi | ||
3782 | */ | ||
3783 | static int check_allowed1(u_char func1, u_char func2) | ||
3784 | { | ||
3785 | #if 000 | ||
3786 | if (func1==ioctl_o) return (0); | ||
3787 | if (func1==read_long) return (-1); | ||
3788 | if (func1==read_long_prefetch) return (-1); | ||
3789 | if (func1==seek) return (-1); | ||
3790 | if (func1==audio_play) return (-1); | ||
3791 | if (func1==audio_pause) return (-1); | ||
3792 | if (func1==audio_resume) return (-1); | ||
3793 | if (func1!=ioctl_i) return (0); | ||
3794 | if (func2==tell_SubQ_run_tot) return (-1); | ||
3795 | if (func2==tell_cdsize) return (-1); | ||
3796 | if (func2==tell_TocDescrip) return (-1); | ||
3797 | if (func2==tell_TocEntry) return (-1); | ||
3798 | if (func2==tell_subQ_info) return (-1); | ||
3799 | if (fam1_drive) if (func2==tell_SubChanInfo) return (-1); | ||
3800 | if (func2==tell_UPC) return (-1); | ||
3801 | #else | ||
3802 | return (0); | ||
3803 | #endif | ||
3804 | } | ||
3805 | /*==========================================================================*/ | ||
3806 | static int check_allowed2(u_char func1, u_char func2) | ||
3807 | { | ||
3808 | #if 000 | ||
3809 | if (func1==read_long) return (-1); | ||
3810 | if (func1==read_long_prefetch) return (-1); | ||
3811 | if (func1==seek) return (-1); | ||
3812 | if (func1==audio_play) return (-1); | ||
3813 | if (func1!=ioctl_o) return (0); | ||
3814 | if (fam1_drive) | ||
3815 | { | ||
3816 | if (func2==EjectDisk) return (-1); | ||
3817 | if (func2==CloseTray) return (-1); | ||
3818 | } | ||
3819 | #else | ||
3820 | return (0); | ||
3821 | #endif | ||
3822 | } | ||
3823 | /*==========================================================================*/ | ||
3824 | static int check_allowed3(u_char func1, u_char func2) | ||
3825 | { | ||
3826 | #if 000 | ||
3827 | if (func1==ioctl_i) | ||
3828 | { | ||
3829 | if (func2==tell_address) return (0); | ||
3830 | if (func2==tell_capabiliti) return (0); | ||
3831 | if (func2==tell_CD_changed) return (0); | ||
3832 | if (fam0L_drive) if (func2==tell_SubChanInfo) return (0); | ||
3833 | return (-1); | ||
3834 | } | ||
3835 | if (func1==ioctl_o) | ||
3836 | { | ||
3837 | if (func2==DriveReset) return (0); | ||
3838 | if (fam0L_drive) | ||
3839 | { | ||
3840 | if (func2==EjectDisk) return (0); | ||
3841 | if (func2==LockDoor) return (0); | ||
3842 | if (func2==CloseTray) return (0); | ||
3843 | } | ||
3844 | return (-1); | ||
3845 | } | ||
3846 | if (func1==flush_input) return (-1); | ||
3847 | if (func1==read_long) return (-1); | ||
3848 | if (func1==read_long_prefetch) return (-1); | ||
3849 | if (func1==seek) return (-1); | ||
3850 | if (func1==audio_play) return (-1); | ||
3851 | if (func1==audio_pause) return (-1); | ||
3852 | if (func1==audio_resume) return (-1); | ||
3853 | #else | ||
3854 | return (0); | ||
3855 | #endif | ||
3856 | } | ||
3857 | /*==========================================================================*/ | ||
3858 | static int seek_pos_audio_end(void) | ||
3859 | { | ||
3860 | int i; | ||
3861 | |||
3862 | i=msf2blk(current_drive->pos_audio_end)-1; | ||
3863 | if (i<0) return (-1); | ||
3864 | i=cc_Seek(i,0); | ||
3865 | return (i); | ||
3866 | } | ||
3867 | #endif /* FUTURE */ | ||
3868 | /*==========================================================================*/ | ||
3869 | static int ReadToC(void) | ||
3870 | { | ||
3871 | int i, j; | ||
3872 | current_drive->diskstate_flags &= ~toc_bit; | ||
3873 | current_drive->ored_ctl_adr=0; | ||
3874 | /* special handling of CD-I HE */ | ||
3875 | if ((current_drive->n_first_track == 2 && current_drive->n_last_track == 2) || | ||
3876 | current_drive->xa_byte == 0x10) | ||
3877 | { | ||
3878 | current_drive->TocBuffer[1].nixbyte=0; | ||
3879 | current_drive->TocBuffer[1].ctl_adr=0x40; | ||
3880 | current_drive->TocBuffer[1].number=1; | ||
3881 | current_drive->TocBuffer[1].format=0; | ||
3882 | current_drive->TocBuffer[1].address=blk2msf(0); | ||
3883 | current_drive->ored_ctl_adr |= 0x40; | ||
3884 | current_drive->n_first_track = 1; | ||
3885 | current_drive->n_last_track = 1; | ||
3886 | current_drive->xa_byte = 0x10; | ||
3887 | j = 2; | ||
3888 | } else | ||
3889 | for (j=current_drive->n_first_track;j<=current_drive->n_last_track;j++) | ||
3890 | { | ||
3891 | i=cc_ReadTocEntry(j); | ||
3892 | if (i<0) | ||
3893 | { | ||
3894 | msg(DBG_INF,"cc_ReadTocEntry(%d) returns %d.\n",j,i); | ||
3895 | return (i); | ||
3896 | } | ||
3897 | current_drive->TocBuffer[j].nixbyte=current_drive->TocEnt_nixbyte; | ||
3898 | current_drive->TocBuffer[j].ctl_adr=current_drive->TocEnt_ctl_adr; | ||
3899 | current_drive->TocBuffer[j].number=current_drive->TocEnt_number; | ||
3900 | current_drive->TocBuffer[j].format=current_drive->TocEnt_format; | ||
3901 | current_drive->TocBuffer[j].address=current_drive->TocEnt_address; | ||
3902 | current_drive->ored_ctl_adr |= current_drive->TocEnt_ctl_adr; | ||
3903 | } | ||
3904 | /* fake entry for LeadOut Track */ | ||
3905 | current_drive->TocBuffer[j].nixbyte=0; | ||
3906 | current_drive->TocBuffer[j].ctl_adr=0; | ||
3907 | current_drive->TocBuffer[j].number=CDROM_LEADOUT; | ||
3908 | current_drive->TocBuffer[j].format=0; | ||
3909 | current_drive->TocBuffer[j].address=current_drive->size_msf; | ||
3910 | |||
3911 | current_drive->diskstate_flags |= toc_bit; | ||
3912 | return (0); | ||
3913 | } | ||
3914 | /*==========================================================================*/ | ||
3915 | static int DiskInfo(void) | ||
3916 | { | ||
3917 | int i, j; | ||
3918 | |||
3919 | current_drive->mode=READ_M1; | ||
3920 | |||
3921 | #undef LOOP_COUNT | ||
3922 | #define LOOP_COUNT 10 /* needed for some "old" drives */ | ||
3923 | |||
3924 | msg(DBG_000,"DiskInfo entered.\n"); | ||
3925 | for (j=1;j<LOOP_COUNT;j++) | ||
3926 | { | ||
3927 | #if 0 | ||
3928 | i=SetSpeed(); | ||
3929 | if (i<0) | ||
3930 | { | ||
3931 | msg(DBG_INF,"DiskInfo: SetSpeed returns %d\n", i); | ||
3932 | continue; | ||
3933 | } | ||
3934 | i=cc_ModeSense(); | ||
3935 | if (i<0) | ||
3936 | { | ||
3937 | msg(DBG_INF,"DiskInfo: cc_ModeSense returns %d\n", i); | ||
3938 | continue; | ||
3939 | } | ||
3940 | #endif | ||
3941 | i=cc_ReadCapacity(); | ||
3942 | if (i>=0) break; | ||
3943 | msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i); | ||
3944 | #if 0 | ||
3945 | i=cc_DriveReset(); | ||
3946 | #endif | ||
3947 | if (!fam0_drive && j == 2) break; | ||
3948 | } | ||
3949 | if (j==LOOP_COUNT) return (-33); /* give up */ | ||
3950 | |||
3951 | i=cc_ReadTocDescr(); | ||
3952 | if (i<0) | ||
3953 | { | ||
3954 | msg(DBG_INF,"DiskInfo: ReadTocDescr returns %d\n", i); | ||
3955 | return (i); | ||
3956 | } | ||
3957 | i=ReadToC(); | ||
3958 | if (i<0) | ||
3959 | { | ||
3960 | msg(DBG_INF,"DiskInfo: ReadToC returns %d\n", i); | ||
3961 | return (i); | ||
3962 | } | ||
3963 | i=cc_CheckMultiSession(); | ||
3964 | if (i<0) | ||
3965 | { | ||
3966 | msg(DBG_INF,"DiskInfo: cc_CheckMultiSession returns %d\n", i); | ||
3967 | return (i); | ||
3968 | } | ||
3969 | if (current_drive->f_multisession) current_drive->sbp_bufsiz=1; /* possibly a weird PhotoCD */ | ||
3970 | else current_drive->sbp_bufsiz=buffers; | ||
3971 | i=cc_ReadTocEntry(current_drive->n_first_track); | ||
3972 | if (i<0) | ||
3973 | { | ||
3974 | msg(DBG_INF,"DiskInfo: cc_ReadTocEntry(1) returns %d\n", i); | ||
3975 | return (i); | ||
3976 | } | ||
3977 | i=cc_ReadUPC(); | ||
3978 | if (i<0) msg(DBG_INF,"DiskInfo: cc_ReadUPC returns %d\n", i); | ||
3979 | if ((fam0L_drive) && (current_drive->xa_byte==0x20 || current_drive->xa_byte == 0x10)) | ||
3980 | { | ||
3981 | /* XA disk with old drive */ | ||
3982 | cc_ModeSelect(CD_FRAMESIZE_RAW1); | ||
3983 | cc_ModeSense(); | ||
3984 | } | ||
3985 | if (famT_drive) cc_prep_mode_T(); | ||
3986 | msg(DBG_000,"DiskInfo done.\n"); | ||
3987 | return (0); | ||
3988 | } | ||
3989 | |||
3990 | static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr) | ||
3991 | { | ||
3992 | struct sbpcd_drive *p = cdi->handle; | ||
3993 | int st; | ||
3994 | |||
3995 | if (CDSL_CURRENT != slot_nr) { | ||
3996 | /* we have no changer support */ | ||
3997 | return -EINVAL; | ||
3998 | } | ||
3999 | |||
4000 | cc_ReadStatus(); | ||
4001 | st=ResponseStatus(); | ||
4002 | if (st<0) | ||
4003 | { | ||
4004 | msg(DBG_INF,"sbpcd_drive_status: timeout.\n"); | ||
4005 | return (0); | ||
4006 | } | ||
4007 | msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); | ||
4008 | msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); | ||
4009 | msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); | ||
4010 | msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); | ||
4011 | msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); | ||
4012 | msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); | ||
4013 | |||
4014 | #if 0 | ||
4015 | if (!(p->status_bits & p_door_closed)) return CDS_TRAY_OPEN; | ||
4016 | if (p->status_bits & p_disk_ok) return CDS_DISC_OK; | ||
4017 | if (p->status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; | ||
4018 | |||
4019 | return CDS_NO_DISC; | ||
4020 | #else | ||
4021 | if (p->status_bits & p_spinning) return CDS_DISC_OK; | ||
4022 | /* return CDS_TRAY_OPEN; */ | ||
4023 | return CDS_NO_DISC; | ||
4024 | |||
4025 | #endif | ||
4026 | |||
4027 | } | ||
4028 | |||
4029 | |||
4030 | /*==========================================================================*/ | ||
4031 | #ifdef FUTURE | ||
4032 | /* | ||
4033 | * called always if driver gets entered | ||
4034 | * returns 0 or ERROR2 or ERROR15 | ||
4035 | */ | ||
4036 | static int prepare(u_char func, u_char subfunc) | ||
4037 | { | ||
4038 | int i; | ||
4039 | |||
4040 | if (fam0L_drive) | ||
4041 | { | ||
4042 | i=inb(CDi_status); | ||
4043 | if (i&s_attention) GetStatus(); | ||
4044 | } | ||
4045 | else if (fam1_drive) GetStatus(); | ||
4046 | else if (fam2_drive) GetStatus(); | ||
4047 | else if (famT_drive) GetStatus(); | ||
4048 | if (current_drive->CD_changed==0xFF) | ||
4049 | { | ||
4050 | current_drive->diskstate_flags=0; | ||
4051 | current_drive->audio_state=0; | ||
4052 | if (!st_diskok) | ||
4053 | { | ||
4054 | i=check_allowed1(func,subfunc); | ||
4055 | if (i<0) return (-2); | ||
4056 | } | ||
4057 | else | ||
4058 | { | ||
4059 | i=check_allowed3(func,subfunc); | ||
4060 | if (i<0) | ||
4061 | { | ||
4062 | current_drive->CD_changed=1; | ||
4063 | return (-15); | ||
4064 | } | ||
4065 | } | ||
4066 | } | ||
4067 | else | ||
4068 | { | ||
4069 | if (!st_diskok) | ||
4070 | { | ||
4071 | current_drive->diskstate_flags=0; | ||
4072 | current_drive->audio_state=0; | ||
4073 | i=check_allowed1(func,subfunc); | ||
4074 | if (i<0) return (-2); | ||
4075 | } | ||
4076 | else | ||
4077 | { | ||
4078 | if (st_busy) | ||
4079 | { | ||
4080 | if (current_drive->audio_state!=audio_pausing) | ||
4081 | { | ||
4082 | i=check_allowed2(func,subfunc); | ||
4083 | if (i<0) return (-2); | ||
4084 | } | ||
4085 | } | ||
4086 | else | ||
4087 | { | ||
4088 | if (current_drive->audio_state==audio_playing) seek_pos_audio_end(); | ||
4089 | current_drive->audio_state=0; | ||
4090 | } | ||
4091 | if (!frame_size_valid) | ||
4092 | { | ||
4093 | i=DiskInfo(); | ||
4094 | if (i<0) | ||
4095 | { | ||
4096 | current_drive->diskstate_flags=0; | ||
4097 | current_drive->audio_state=0; | ||
4098 | i=check_allowed1(func,subfunc); | ||
4099 | if (i<0) return (-2); | ||
4100 | } | ||
4101 | } | ||
4102 | } | ||
4103 | } | ||
4104 | return (0); | ||
4105 | } | ||
4106 | #endif /* FUTURE */ | ||
4107 | /*==========================================================================*/ | ||
4108 | /*==========================================================================*/ | ||
4109 | /* | ||
4110 | * Check the results of the "get status" command. | ||
4111 | */ | ||
4112 | static int sbp_status(void) | ||
4113 | { | ||
4114 | int st; | ||
4115 | |||
4116 | st=ResponseStatus(); | ||
4117 | if (st<0) | ||
4118 | { | ||
4119 | msg(DBG_INF,"sbp_status: timeout.\n"); | ||
4120 | return (0); | ||
4121 | } | ||
4122 | |||
4123 | if (!st_spinning) msg(DBG_SPI,"motor got off - ignoring.\n"); | ||
4124 | |||
4125 | if (st_check) | ||
4126 | { | ||
4127 | msg(DBG_INF,"st_check detected - retrying.\n"); | ||
4128 | return (0); | ||
4129 | } | ||
4130 | if (!st_door_closed) | ||
4131 | { | ||
4132 | msg(DBG_INF,"door is open - retrying.\n"); | ||
4133 | return (0); | ||
4134 | } | ||
4135 | if (!st_caddy_in) | ||
4136 | { | ||
4137 | msg(DBG_INF,"disk removed - retrying.\n"); | ||
4138 | return (0); | ||
4139 | } | ||
4140 | if (!st_diskok) | ||
4141 | { | ||
4142 | msg(DBG_INF,"!st_diskok detected - retrying.\n"); | ||
4143 | return (0); | ||
4144 | } | ||
4145 | if (st_busy) | ||
4146 | { | ||
4147 | msg(DBG_INF,"st_busy detected - retrying.\n"); | ||
4148 | return (0); | ||
4149 | } | ||
4150 | return (1); | ||
4151 | } | ||
4152 | /*==========================================================================*/ | ||
4153 | |||
4154 | static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp) | ||
4155 | { | ||
4156 | struct sbpcd_drive *p = cdi->handle; | ||
4157 | ms_infp->addr_format = CDROM_LBA; | ||
4158 | ms_infp->addr.lba = p->lba_multi; | ||
4159 | if (p->f_multisession) | ||
4160 | ms_infp->xa_flag=1; /* valid redirection address */ | ||
4161 | else | ||
4162 | ms_infp->xa_flag=0; /* invalid redirection address */ | ||
4163 | |||
4164 | return 0; | ||
4165 | } | ||
4166 | |||
4167 | /*==========================================================================*/ | ||
4168 | /*==========================================================================*/ | ||
4169 | /* | ||
4170 | * ioctl support | ||
4171 | */ | ||
4172 | static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, | ||
4173 | u_long arg) | ||
4174 | { | ||
4175 | struct sbpcd_drive *p = cdi->handle; | ||
4176 | int i; | ||
4177 | |||
4178 | msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08lX)\n", cdi->name, cmd, arg); | ||
4179 | if (p->drv_id==-1) { | ||
4180 | msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name); | ||
4181 | return (-ENXIO); /* no such drive */ | ||
4182 | } | ||
4183 | down(&ioctl_read_sem); | ||
4184 | if (p != current_drive) | ||
4185 | switch_drive(p); | ||
4186 | |||
4187 | msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd); | ||
4188 | switch (cmd) /* Sun-compatible */ | ||
4189 | { | ||
4190 | case DDIOCSDBG: /* DDI Debug */ | ||
4191 | if (!capable(CAP_SYS_ADMIN)) RETURN_UP(-EPERM); | ||
4192 | i=sbpcd_dbg_ioctl(arg,1); | ||
4193 | RETURN_UP(i); | ||
4194 | case CDROMRESET: /* hard reset the drive */ | ||
4195 | msg(DBG_IOC,"ioctl: CDROMRESET entered.\n"); | ||
4196 | i=DriveReset(); | ||
4197 | current_drive->audio_state=0; | ||
4198 | RETURN_UP(i); | ||
4199 | |||
4200 | case CDROMREADMODE1: | ||
4201 | msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); | ||
4202 | #ifdef SAFE_MIXED | ||
4203 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4204 | #endif /* SAFE_MIXED */ | ||
4205 | cc_ModeSelect(CD_FRAMESIZE); | ||
4206 | cc_ModeSense(); | ||
4207 | current_drive->mode=READ_M1; | ||
4208 | RETURN_UP(0); | ||
4209 | |||
4210 | case CDROMREADMODE2: /* not usable at the moment */ | ||
4211 | msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); | ||
4212 | #ifdef SAFE_MIXED | ||
4213 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4214 | #endif /* SAFE_MIXED */ | ||
4215 | cc_ModeSelect(CD_FRAMESIZE_RAW1); | ||
4216 | cc_ModeSense(); | ||
4217 | current_drive->mode=READ_M2; | ||
4218 | RETURN_UP(0); | ||
4219 | |||
4220 | case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */ | ||
4221 | msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n"); | ||
4222 | if (current_drive->sbp_audsiz>0) vfree(current_drive->aud_buf); | ||
4223 | current_drive->aud_buf=NULL; | ||
4224 | current_drive->sbp_audsiz=arg; | ||
4225 | |||
4226 | if (current_drive->sbp_audsiz>16) | ||
4227 | { | ||
4228 | current_drive->sbp_audsiz = 0; | ||
4229 | RETURN_UP(current_drive->sbp_audsiz); | ||
4230 | } | ||
4231 | |||
4232 | if (current_drive->sbp_audsiz>0) | ||
4233 | { | ||
4234 | current_drive->aud_buf=(u_char *) vmalloc(current_drive->sbp_audsiz*CD_FRAMESIZE_RAW); | ||
4235 | if (current_drive->aud_buf==NULL) | ||
4236 | { | ||
4237 | msg(DBG_INF,"audio buffer (%d frames) not available.\n",current_drive->sbp_audsiz); | ||
4238 | current_drive->sbp_audsiz=0; | ||
4239 | } | ||
4240 | else msg(DBG_INF,"audio buffer size: %d frames.\n",current_drive->sbp_audsiz); | ||
4241 | } | ||
4242 | RETURN_UP(current_drive->sbp_audsiz); | ||
4243 | |||
4244 | case CDROMREADAUDIO: | ||
4245 | { /* start of CDROMREADAUDIO */ | ||
4246 | int i=0, j=0, frame, block=0; | ||
4247 | u_int try=0; | ||
4248 | u_long timeout; | ||
4249 | u_char *p; | ||
4250 | u_int data_tries = 0; | ||
4251 | u_int data_waits = 0; | ||
4252 | u_int data_retrying = 0; | ||
4253 | int status_tries; | ||
4254 | int error_flag; | ||
4255 | |||
4256 | msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n"); | ||
4257 | if (fam0_drive) RETURN_UP(-EINVAL); | ||
4258 | if (famL_drive) RETURN_UP(-EINVAL); | ||
4259 | if (famV_drive) RETURN_UP(-EINVAL); | ||
4260 | if (famT_drive) RETURN_UP(-EINVAL); | ||
4261 | #ifdef SAFE_MIXED | ||
4262 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4263 | #endif /* SAFE_MIXED */ | ||
4264 | if (current_drive->aud_buf==NULL) RETURN_UP(-EINVAL); | ||
4265 | if (copy_from_user(&read_audio, (void __user *)arg, | ||
4266 | sizeof(struct cdrom_read_audio))) | ||
4267 | RETURN_UP(-EFAULT); | ||
4268 | if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL); | ||
4269 | if (!access_ok(VERIFY_WRITE, read_audio.buf, | ||
4270 | read_audio.nframes*CD_FRAMESIZE_RAW)) | ||
4271 | RETURN_UP(-EFAULT); | ||
4272 | |||
4273 | if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */ | ||
4274 | block=msf2lba(&read_audio.addr.msf.minute); | ||
4275 | else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */ | ||
4276 | block=read_audio.addr.lba; | ||
4277 | else RETURN_UP(-EINVAL); | ||
4278 | #if 000 | ||
4279 | i=cc_SetSpeed(speed_150,0,0); | ||
4280 | if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i); | ||
4281 | #endif | ||
4282 | msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n", | ||
4283 | block, blk2msf(block)); | ||
4284 | msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n"); | ||
4285 | #if OLD_BUSY | ||
4286 | while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ | ||
4287 | busy_audio=1; | ||
4288 | #endif /* OLD_BUSY */ | ||
4289 | error_flag=0; | ||
4290 | for (data_tries=5; data_tries>0; data_tries--) | ||
4291 | { | ||
4292 | msg(DBG_AUD,"data_tries=%d ...\n", data_tries); | ||
4293 | current_drive->mode=READ_AU; | ||
4294 | cc_ModeSelect(CD_FRAMESIZE_RAW); | ||
4295 | cc_ModeSense(); | ||
4296 | for (status_tries=3; status_tries > 0; status_tries--) | ||
4297 | { | ||
4298 | flags_cmd_out |= f_respo3; | ||
4299 | cc_ReadStatus(); | ||
4300 | if (sbp_status() != 0) break; | ||
4301 | if (st_check) cc_ReadError(); | ||
4302 | sbp_sleep(1); /* wait a bit, try again */ | ||
4303 | } | ||
4304 | if (status_tries == 0) | ||
4305 | { | ||
4306 | msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__); | ||
4307 | continue; | ||
4308 | } | ||
4309 | msg(DBG_AUD,"read_audio: sbp_status: ok.\n"); | ||
4310 | |||
4311 | flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check; | ||
4312 | if (fam0L_drive) | ||
4313 | { | ||
4314 | flags_cmd_out |= f_lopsta | f_getsta | f_bit1; | ||
4315 | cmd_type=READ_M2; | ||
4316 | drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */ | ||
4317 | drvcmd[1]=(block>>16)&0x000000ff; | ||
4318 | drvcmd[2]=(block>>8)&0x000000ff; | ||
4319 | drvcmd[3]=block&0x000000ff; | ||
4320 | drvcmd[4]=0; | ||
4321 | drvcmd[5]=read_audio.nframes; /* # of frames */ | ||
4322 | drvcmd[6]=0; | ||
4323 | } | ||
4324 | else if (fam1_drive) | ||
4325 | { | ||
4326 | drvcmd[0]=CMD1_READ; /* "read frames", new drives */ | ||
4327 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
4328 | drvcmd[4]=0; | ||
4329 | drvcmd[5]=0; | ||
4330 | drvcmd[6]=read_audio.nframes; /* # of frames */ | ||
4331 | } | ||
4332 | else if (fam2_drive) | ||
4333 | { | ||
4334 | drvcmd[0]=CMD2_READ_XA2; | ||
4335 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
4336 | drvcmd[4]=0; | ||
4337 | drvcmd[5]=read_audio.nframes; /* # of frames */ | ||
4338 | drvcmd[6]=0x11; /* raw mode */ | ||
4339 | } | ||
4340 | else if (famT_drive) /* CD-55A: not tested yet */ | ||
4341 | { | ||
4342 | } | ||
4343 | msg(DBG_AUD,"read_audio: before giving \"read\" command.\n"); | ||
4344 | flags_cmd_out=f_putcmd; | ||
4345 | response_count=0; | ||
4346 | i=cmd_out(); | ||
4347 | if (i<0) msg(DBG_INF,"error giving READ AUDIO command: %0d\n", i); | ||
4348 | sbp_sleep(0); | ||
4349 | msg(DBG_AUD,"read_audio: after giving \"read\" command.\n"); | ||
4350 | for (frame=1;frame<2 && !error_flag; frame++) | ||
4351 | { | ||
4352 | try=maxtim_data; | ||
4353 | for (timeout=jiffies+9*HZ; ; ) | ||
4354 | { | ||
4355 | for ( ; try!=0;try--) | ||
4356 | { | ||
4357 | j=inb(CDi_status); | ||
4358 | if (!(j&s_not_data_ready)) break; | ||
4359 | if (!(j&s_not_result_ready)) break; | ||
4360 | if (fam0L_drive) if (j&s_attention) break; | ||
4361 | } | ||
4362 | if (try != 0 || time_after_eq(jiffies, timeout)) break; | ||
4363 | if (data_retrying == 0) data_waits++; | ||
4364 | data_retrying = 1; | ||
4365 | sbp_sleep(1); | ||
4366 | try = 1; | ||
4367 | } | ||
4368 | if (try==0) | ||
4369 | { | ||
4370 | msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n"); | ||
4371 | error_flag++; | ||
4372 | break; | ||
4373 | } | ||
4374 | msg(DBG_AUD,"read_audio: sbp_data: CDi_status ok.\n"); | ||
4375 | if (j&s_not_data_ready) | ||
4376 | { | ||
4377 | msg(DBG_INF, "read_audio: sbp_data: DATA_READY timeout.\n"); | ||
4378 | error_flag++; | ||
4379 | break; | ||
4380 | } | ||
4381 | msg(DBG_AUD,"read_audio: before reading data.\n"); | ||
4382 | error_flag=0; | ||
4383 | p = current_drive->aud_buf; | ||
4384 | if (sbpro_type==1) OUT(CDo_sel_i_d,1); | ||
4385 | if (do_16bit) | ||
4386 | { | ||
4387 | u_short *p2 = (u_short *) p; | ||
4388 | |||
4389 | for (; (u_char *) p2 < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) | ||
4390 | { | ||
4391 | if ((inb_p(CDi_status)&s_not_data_ready)) continue; | ||
4392 | |||
4393 | /* get one sample */ | ||
4394 | *p2++ = inw_p(CDi_data); | ||
4395 | *p2++ = inw_p(CDi_data); | ||
4396 | } | ||
4397 | } else { | ||
4398 | for (; p < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) | ||
4399 | { | ||
4400 | if ((inb_p(CDi_status)&s_not_data_ready)) continue; | ||
4401 | |||
4402 | /* get one sample */ | ||
4403 | *p++ = inb_p(CDi_data); | ||
4404 | *p++ = inb_p(CDi_data); | ||
4405 | *p++ = inb_p(CDi_data); | ||
4406 | *p++ = inb_p(CDi_data); | ||
4407 | } | ||
4408 | } | ||
4409 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
4410 | data_retrying = 0; | ||
4411 | } | ||
4412 | msg(DBG_AUD,"read_audio: after reading data.\n"); | ||
4413 | if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ | ||
4414 | { | ||
4415 | msg(DBG_AUD,"read_audio: read aborted by drive\n"); | ||
4416 | #if 0000 | ||
4417 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
4418 | #else | ||
4419 | i=cc_ReadError(); | ||
4420 | #endif | ||
4421 | continue; | ||
4422 | } | ||
4423 | if (fam0L_drive) | ||
4424 | { | ||
4425 | i=maxtim_data; | ||
4426 | for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); timeout--) | ||
4427 | { | ||
4428 | for ( ;i!=0;i--) | ||
4429 | { | ||
4430 | j=inb(CDi_status); | ||
4431 | if (!(j&s_not_data_ready)) break; | ||
4432 | if (!(j&s_not_result_ready)) break; | ||
4433 | if (j&s_attention) break; | ||
4434 | } | ||
4435 | if (i != 0 || time_after_eq(jiffies, timeout)) break; | ||
4436 | sbp_sleep(0); | ||
4437 | i = 1; | ||
4438 | } | ||
4439 | if (i==0) msg(DBG_AUD,"read_audio: STATUS TIMEOUT AFTER READ"); | ||
4440 | if (!(j&s_attention)) | ||
4441 | { | ||
4442 | msg(DBG_AUD,"read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"); | ||
4443 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
4444 | continue; | ||
4445 | } | ||
4446 | } | ||
4447 | do | ||
4448 | { | ||
4449 | if (fam0L_drive) cc_ReadStatus(); | ||
4450 | i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ | ||
4451 | if (i<0) { msg(DBG_AUD, | ||
4452 | "read_audio: cc_ReadStatus error after read: %02X\n", | ||
4453 | current_drive->status_bits); | ||
4454 | continue; /* FIXME */ | ||
4455 | } | ||
4456 | } | ||
4457 | while ((fam0L_drive)&&(!st_check)&&(!(i&p_success))); | ||
4458 | if (st_check) | ||
4459 | { | ||
4460 | i=cc_ReadError(); | ||
4461 | msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i); | ||
4462 | continue; | ||
4463 | } | ||
4464 | if (copy_to_user(read_audio.buf, | ||
4465 | current_drive->aud_buf, | ||
4466 | read_audio.nframes * CD_FRAMESIZE_RAW)) | ||
4467 | RETURN_UP(-EFAULT); | ||
4468 | msg(DBG_AUD,"read_audio: copy_to_user done.\n"); | ||
4469 | break; | ||
4470 | } | ||
4471 | cc_ModeSelect(CD_FRAMESIZE); | ||
4472 | cc_ModeSense(); | ||
4473 | current_drive->mode=READ_M1; | ||
4474 | #if OLD_BUSY | ||
4475 | busy_audio=0; | ||
4476 | #endif /* OLD_BUSY */ | ||
4477 | if (data_tries == 0) | ||
4478 | { | ||
4479 | msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); | ||
4480 | RETURN_UP(-EIO); | ||
4481 | } | ||
4482 | msg(DBG_AUD,"read_audio: successful return.\n"); | ||
4483 | RETURN_UP(0); | ||
4484 | } /* end of CDROMREADAUDIO */ | ||
4485 | |||
4486 | default: | ||
4487 | msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); | ||
4488 | RETURN_UP(-EINVAL); | ||
4489 | } /* end switch(cmd) */ | ||
4490 | } | ||
4491 | |||
4492 | static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd, | ||
4493 | void * arg) | ||
4494 | { | ||
4495 | struct sbpcd_drive *p = cdi->handle; | ||
4496 | int i, st, j; | ||
4497 | |||
4498 | msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08p)\n", cdi->name, cmd, arg); | ||
4499 | if (p->drv_id==-1) { | ||
4500 | msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name); | ||
4501 | return (-ENXIO); /* no such drive */ | ||
4502 | } | ||
4503 | down(&ioctl_read_sem); | ||
4504 | if (p != current_drive) | ||
4505 | switch_drive(p); | ||
4506 | |||
4507 | msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd); | ||
4508 | switch (cmd) /* Sun-compatible */ | ||
4509 | { | ||
4510 | |||
4511 | case CDROMPAUSE: /* Pause the drive */ | ||
4512 | msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n"); | ||
4513 | /* pause the drive unit when it is currently in PLAY mode, */ | ||
4514 | /* or reset the starting and ending locations when in PAUSED mode. */ | ||
4515 | /* If applicable, at the next stopping point it reaches */ | ||
4516 | /* the drive will discontinue playing. */ | ||
4517 | switch (current_drive->audio_state) | ||
4518 | { | ||
4519 | case audio_playing: | ||
4520 | if (famL_drive) i=cc_ReadSubQ(); | ||
4521 | else i=cc_Pause_Resume(1); | ||
4522 | if (i<0) RETURN_UP(-EIO); | ||
4523 | if (famL_drive) i=cc_Pause_Resume(1); | ||
4524 | else i=cc_ReadSubQ(); | ||
4525 | if (i<0) RETURN_UP(-EIO); | ||
4526 | current_drive->pos_audio_start=current_drive->SubQ_run_tot; | ||
4527 | current_drive->audio_state=audio_pausing; | ||
4528 | RETURN_UP(0); | ||
4529 | case audio_pausing: | ||
4530 | i=cc_Seek(current_drive->pos_audio_start,1); | ||
4531 | if (i<0) RETURN_UP(-EIO); | ||
4532 | RETURN_UP(0); | ||
4533 | default: | ||
4534 | RETURN_UP(-EINVAL); | ||
4535 | } | ||
4536 | |||
4537 | case CDROMRESUME: /* resume paused audio play */ | ||
4538 | msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n"); | ||
4539 | /* resume playing audio tracks when a previous PLAY AUDIO call has */ | ||
4540 | /* been paused with a PAUSE command. */ | ||
4541 | /* It will resume playing from the location saved in SubQ_run_tot. */ | ||
4542 | if (current_drive->audio_state!=audio_pausing) RETURN_UP(-EINVAL); | ||
4543 | if (famL_drive) | ||
4544 | i=cc_PlayAudio(current_drive->pos_audio_start, | ||
4545 | current_drive->pos_audio_end); | ||
4546 | else i=cc_Pause_Resume(3); | ||
4547 | if (i<0) RETURN_UP(-EIO); | ||
4548 | current_drive->audio_state=audio_playing; | ||
4549 | RETURN_UP(0); | ||
4550 | |||
4551 | case CDROMPLAYMSF: | ||
4552 | msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); | ||
4553 | #ifdef SAFE_MIXED | ||
4554 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4555 | #endif /* SAFE_MIXED */ | ||
4556 | if (current_drive->audio_state==audio_playing) | ||
4557 | { | ||
4558 | i=cc_Pause_Resume(1); | ||
4559 | if (i<0) RETURN_UP(-EIO); | ||
4560 | i=cc_ReadSubQ(); | ||
4561 | if (i<0) RETURN_UP(-EIO); | ||
4562 | current_drive->pos_audio_start=current_drive->SubQ_run_tot; | ||
4563 | i=cc_Seek(current_drive->pos_audio_start,1); | ||
4564 | } | ||
4565 | memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf)); | ||
4566 | /* values come as msf-bin */ | ||
4567 | current_drive->pos_audio_start = (msf.cdmsf_min0<<16) | | ||
4568 | (msf.cdmsf_sec0<<8) | | ||
4569 | msf.cdmsf_frame0; | ||
4570 | current_drive->pos_audio_end = (msf.cdmsf_min1<<16) | | ||
4571 | (msf.cdmsf_sec1<<8) | | ||
4572 | msf.cdmsf_frame1; | ||
4573 | msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n", | ||
4574 | current_drive->pos_audio_start,current_drive->pos_audio_end); | ||
4575 | i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end); | ||
4576 | if (i<0) | ||
4577 | { | ||
4578 | msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); | ||
4579 | DriveReset(); | ||
4580 | current_drive->audio_state=0; | ||
4581 | RETURN_UP(-EIO); | ||
4582 | } | ||
4583 | current_drive->audio_state=audio_playing; | ||
4584 | RETURN_UP(0); | ||
4585 | |||
4586 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
4587 | msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); | ||
4588 | #ifdef SAFE_MIXED | ||
4589 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4590 | #endif /* SAFE_MIXED */ | ||
4591 | if (current_drive->audio_state==audio_playing) | ||
4592 | { | ||
4593 | msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); | ||
4594 | #if 1 | ||
4595 | RETURN_UP(0); /* just let us play on */ | ||
4596 | #else | ||
4597 | RETURN_UP(-EINVAL); /* play on, but say "error" */ | ||
4598 | #endif | ||
4599 | } | ||
4600 | memcpy(&ti,(void *) arg,sizeof(struct cdrom_ti)); | ||
4601 | msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n", | ||
4602 | ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1); | ||
4603 | if (ti.cdti_trk0<current_drive->n_first_track) RETURN_UP(-EINVAL); | ||
4604 | if (ti.cdti_trk0>current_drive->n_last_track) RETURN_UP(-EINVAL); | ||
4605 | if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0; | ||
4606 | if (ti.cdti_trk1>current_drive->n_last_track) ti.cdti_trk1=current_drive->n_last_track; | ||
4607 | current_drive->pos_audio_start=current_drive->TocBuffer[ti.cdti_trk0].address; | ||
4608 | current_drive->pos_audio_end=current_drive->TocBuffer[ti.cdti_trk1+1].address; | ||
4609 | i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end); | ||
4610 | if (i<0) | ||
4611 | { | ||
4612 | msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); | ||
4613 | DriveReset(); | ||
4614 | current_drive->audio_state=0; | ||
4615 | RETURN_UP(-EIO); | ||
4616 | } | ||
4617 | current_drive->audio_state=audio_playing; | ||
4618 | RETURN_UP(0); | ||
4619 | |||
4620 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
4621 | msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n"); | ||
4622 | tochdr.cdth_trk0=current_drive->n_first_track; | ||
4623 | tochdr.cdth_trk1=current_drive->n_last_track; | ||
4624 | memcpy((void *) arg, &tochdr, sizeof(struct cdrom_tochdr)); | ||
4625 | RETURN_UP(0); | ||
4626 | |||
4627 | case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ | ||
4628 | msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n"); | ||
4629 | memcpy(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry)); | ||
4630 | i=tocentry.cdte_track; | ||
4631 | if (i==CDROM_LEADOUT) i=current_drive->n_last_track+1; | ||
4632 | else if (i<current_drive->n_first_track||i>current_drive->n_last_track) | ||
4633 | RETURN_UP(-EINVAL); | ||
4634 | tocentry.cdte_adr=current_drive->TocBuffer[i].ctl_adr&0x0F; | ||
4635 | tocentry.cdte_ctrl=(current_drive->TocBuffer[i].ctl_adr>>4)&0x0F; | ||
4636 | tocentry.cdte_datamode=current_drive->TocBuffer[i].format; | ||
4637 | if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */ | ||
4638 | { | ||
4639 | tocentry.cdte_addr.msf.minute=(current_drive->TocBuffer[i].address>>16)&0x00FF; | ||
4640 | tocentry.cdte_addr.msf.second=(current_drive->TocBuffer[i].address>>8)&0x00FF; | ||
4641 | tocentry.cdte_addr.msf.frame=current_drive->TocBuffer[i].address&0x00FF; | ||
4642 | } | ||
4643 | else if (tocentry.cdte_format==CDROM_LBA) /* blk required */ | ||
4644 | tocentry.cdte_addr.lba=msf2blk(current_drive->TocBuffer[i].address); | ||
4645 | else RETURN_UP(-EINVAL); | ||
4646 | memcpy((void *) arg, &tocentry, sizeof(struct cdrom_tocentry)); | ||
4647 | RETURN_UP(0); | ||
4648 | |||
4649 | case CDROMSTOP: /* Spin down the drive */ | ||
4650 | msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); | ||
4651 | #ifdef SAFE_MIXED | ||
4652 | if (current_drive->has_data>1) RETURN_UP(-EBUSY); | ||
4653 | #endif /* SAFE_MIXED */ | ||
4654 | i=cc_Pause_Resume(1); | ||
4655 | current_drive->audio_state=0; | ||
4656 | #if 0 | ||
4657 | cc_DriveReset(); | ||
4658 | #endif | ||
4659 | RETURN_UP(i); | ||
4660 | |||
4661 | case CDROMSTART: /* Spin up the drive */ | ||
4662 | msg(DBG_IOC,"ioctl: CDROMSTART entered.\n"); | ||
4663 | cc_SpinUp(); | ||
4664 | current_drive->audio_state=0; | ||
4665 | RETURN_UP(0); | ||
4666 | |||
4667 | case CDROMVOLCTRL: /* Volume control */ | ||
4668 | msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n"); | ||
4669 | memcpy(&volctrl,(char *) arg,sizeof(volctrl)); | ||
4670 | current_drive->vol_chan0=0; | ||
4671 | current_drive->vol_ctrl0=volctrl.channel0; | ||
4672 | current_drive->vol_chan1=1; | ||
4673 | current_drive->vol_ctrl1=volctrl.channel1; | ||
4674 | i=cc_SetVolume(); | ||
4675 | RETURN_UP(0); | ||
4676 | |||
4677 | case CDROMVOLREAD: /* read Volume settings from drive */ | ||
4678 | msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n"); | ||
4679 | st=cc_GetVolume(); | ||
4680 | if (st<0) RETURN_UP(st); | ||
4681 | volctrl.channel0=current_drive->vol_ctrl0; | ||
4682 | volctrl.channel1=current_drive->vol_ctrl1; | ||
4683 | volctrl.channel2=0; | ||
4684 | volctrl.channel2=0; | ||
4685 | memcpy((void *)arg,&volctrl,sizeof(volctrl)); | ||
4686 | RETURN_UP(0); | ||
4687 | |||
4688 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
4689 | msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n"); | ||
4690 | /* Bogus, I can do better than this! --AJK | ||
4691 | if ((st_spinning)||(!subq_valid)) { | ||
4692 | i=cc_ReadSubQ(); | ||
4693 | if (i<0) RETURN_UP(-EIO); | ||
4694 | } | ||
4695 | */ | ||
4696 | i=cc_ReadSubQ(); | ||
4697 | if (i<0) { | ||
4698 | j=cc_ReadError(); /* clear out error status from drive */ | ||
4699 | current_drive->audio_state=CDROM_AUDIO_NO_STATUS; | ||
4700 | /* get and set the disk state here, | ||
4701 | probably not the right place, but who cares! | ||
4702 | It makes it work properly! --AJK */ | ||
4703 | if (current_drive->CD_changed==0xFF) { | ||
4704 | msg(DBG_000,"Disk changed detect\n"); | ||
4705 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
4706 | } | ||
4707 | RETURN_UP(-EIO); | ||
4708 | } | ||
4709 | if (current_drive->CD_changed==0xFF) { | ||
4710 | /* reread the TOC because the disk has changed! --AJK */ | ||
4711 | msg(DBG_000,"Disk changed STILL detected, rereading TOC!\n"); | ||
4712 | i=DiskInfo(); | ||
4713 | if(i==0) { | ||
4714 | current_drive->CD_changed=0x00; /* cd has changed, procede, */ | ||
4715 | RETURN_UP(-EIO); /* and get TOC, etc on next try! --AJK */ | ||
4716 | } else { | ||
4717 | RETURN_UP(-EIO); /* we weren't ready yet! --AJK */ | ||
4718 | } | ||
4719 | } | ||
4720 | memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); | ||
4721 | /* | ||
4722 | This virtual crap is very bogus! | ||
4723 | It doesn't detect when the cd is done playing audio! | ||
4724 | Lets do this right with proper hardware register reading! | ||
4725 | */ | ||
4726 | cc_ReadStatus(); | ||
4727 | i=ResponseStatus(); | ||
4728 | msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); | ||
4729 | msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); | ||
4730 | msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); | ||
4731 | msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); | ||
4732 | msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); | ||
4733 | msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); | ||
4734 | /* st_busy indicates if it's _ACTUALLY_ playing audio */ | ||
4735 | switch (current_drive->audio_state) | ||
4736 | { | ||
4737 | case audio_playing: | ||
4738 | if(st_busy==0) { | ||
4739 | /* CD has stopped playing audio --AJK */ | ||
4740 | current_drive->audio_state=audio_completed; | ||
4741 | SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; | ||
4742 | } else { | ||
4743 | SC.cdsc_audiostatus=CDROM_AUDIO_PLAY; | ||
4744 | } | ||
4745 | break; | ||
4746 | case audio_pausing: | ||
4747 | SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED; | ||
4748 | break; | ||
4749 | case audio_completed: | ||
4750 | SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; | ||
4751 | break; | ||
4752 | default: | ||
4753 | SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS; | ||
4754 | break; | ||
4755 | } | ||
4756 | SC.cdsc_adr=current_drive->SubQ_ctl_adr; | ||
4757 | SC.cdsc_ctrl=current_drive->SubQ_ctl_adr>>4; | ||
4758 | SC.cdsc_trk=bcd2bin(current_drive->SubQ_trk); | ||
4759 | SC.cdsc_ind=bcd2bin(current_drive->SubQ_pnt_idx); | ||
4760 | if (SC.cdsc_format==CDROM_LBA) | ||
4761 | { | ||
4762 | SC.cdsc_absaddr.lba=msf2blk(current_drive->SubQ_run_tot); | ||
4763 | SC.cdsc_reladdr.lba=msf2blk(current_drive->SubQ_run_trk); | ||
4764 | } | ||
4765 | else /* not only if (SC.cdsc_format==CDROM_MSF) */ | ||
4766 | { | ||
4767 | SC.cdsc_absaddr.msf.minute=(current_drive->SubQ_run_tot>>16)&0x00FF; | ||
4768 | SC.cdsc_absaddr.msf.second=(current_drive->SubQ_run_tot>>8)&0x00FF; | ||
4769 | SC.cdsc_absaddr.msf.frame=current_drive->SubQ_run_tot&0x00FF; | ||
4770 | SC.cdsc_reladdr.msf.minute=(current_drive->SubQ_run_trk>>16)&0x00FF; | ||
4771 | SC.cdsc_reladdr.msf.second=(current_drive->SubQ_run_trk>>8)&0x00FF; | ||
4772 | SC.cdsc_reladdr.msf.frame=current_drive->SubQ_run_trk&0x00FF; | ||
4773 | } | ||
4774 | memcpy((void *) arg, &SC, sizeof(struct cdrom_subchnl)); | ||
4775 | msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n", | ||
4776 | SC.cdsc_format,SC.cdsc_audiostatus, | ||
4777 | SC.cdsc_adr,SC.cdsc_ctrl, | ||
4778 | SC.cdsc_trk,SC.cdsc_ind, | ||
4779 | SC.cdsc_absaddr,SC.cdsc_reladdr); | ||
4780 | RETURN_UP(0); | ||
4781 | |||
4782 | default: | ||
4783 | msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); | ||
4784 | RETURN_UP(-EINVAL); | ||
4785 | } /* end switch(cmd) */ | ||
4786 | } | ||
4787 | /*==========================================================================*/ | ||
4788 | /* | ||
4789 | * Take care of the different block sizes between cdrom and Linux. | ||
4790 | */ | ||
4791 | static void sbp_transfer(struct request *req) | ||
4792 | { | ||
4793 | long offs; | ||
4794 | |||
4795 | while ( (req->nr_sectors > 0) && | ||
4796 | (req->sector/4 >= current_drive->sbp_first_frame) && | ||
4797 | (req->sector/4 <= current_drive->sbp_last_frame) ) | ||
4798 | { | ||
4799 | offs = (req->sector - current_drive->sbp_first_frame * 4) * 512; | ||
4800 | memcpy(req->buffer, current_drive->sbp_buf + offs, 512); | ||
4801 | req->nr_sectors--; | ||
4802 | req->sector++; | ||
4803 | req->buffer += 512; | ||
4804 | } | ||
4805 | } | ||
4806 | /*==========================================================================*/ | ||
4807 | /* | ||
4808 | * special end_request for sbpcd to solve CURRENT==NULL bug. (GTL) | ||
4809 | * GTL = Gonzalo Tornaria <tornaria@cmat.edu.uy> | ||
4810 | * | ||
4811 | * This is a kludge so we don't need to modify end_request. | ||
4812 | * We put the req we take out after INIT_REQUEST in the requests list, | ||
4813 | * so that end_request will discard it. | ||
4814 | * | ||
4815 | * The bug could be present in other block devices, perhaps we | ||
4816 | * should modify INIT_REQUEST and end_request instead, and | ||
4817 | * change every block device.. | ||
4818 | * | ||
4819 | * Could be a race here?? Could e.g. a timer interrupt schedule() us? | ||
4820 | * If so, we should copy end_request here, and do it right.. (or | ||
4821 | * modify end_request and the block devices). | ||
4822 | * | ||
4823 | * In any case, the race here would be much small than it was, and | ||
4824 | * I couldn't reproduce.. | ||
4825 | * | ||
4826 | * The race could be: suppose CURRENT==NULL. We put our req in the list, | ||
4827 | * and we are scheduled. Other process takes over, and gets into | ||
4828 | * do_sbpcd_request. It sees CURRENT!=NULL (it is == to our req), so | ||
4829 | * proceeds. It ends, so CURRENT is now NULL.. Now we awake somewhere in | ||
4830 | * end_request, but now CURRENT==NULL... oops! | ||
4831 | * | ||
4832 | */ | ||
4833 | #undef DEBUG_GTL | ||
4834 | |||
4835 | /*==========================================================================*/ | ||
4836 | /* | ||
4837 | * I/O request routine, called from Linux kernel. | ||
4838 | */ | ||
4839 | static void do_sbpcd_request(request_queue_t * q) | ||
4840 | { | ||
4841 | u_int block; | ||
4842 | u_int nsect; | ||
4843 | int status_tries, data_tries; | ||
4844 | struct request *req; | ||
4845 | struct sbpcd_drive *p; | ||
4846 | #ifdef DEBUG_GTL | ||
4847 | static int xx_nr=0; | ||
4848 | int xnr; | ||
4849 | #endif | ||
4850 | |||
4851 | request_loop: | ||
4852 | #ifdef DEBUG_GTL | ||
4853 | xnr=++xx_nr; | ||
4854 | |||
4855 | req = elv_next_request(q); | ||
4856 | |||
4857 | if (!req) | ||
4858 | { | ||
4859 | printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n", | ||
4860 | xnr, current->pid, jiffies); | ||
4861 | printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n", | ||
4862 | xnr, jiffies); | ||
4863 | return; | ||
4864 | } | ||
4865 | |||
4866 | printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", | ||
4867 | xnr, req, req->sector, req->nr_sectors, current->pid, jiffies); | ||
4868 | #endif | ||
4869 | |||
4870 | req = elv_next_request(q); /* take out our request so no other */ | ||
4871 | if (!req) | ||
4872 | return; | ||
4873 | |||
4874 | if (req -> sector == -1) | ||
4875 | end_request(req, 0); | ||
4876 | spin_unlock_irq(q->queue_lock); | ||
4877 | |||
4878 | down(&ioctl_read_sem); | ||
4879 | if (rq_data_dir(elv_next_request(q)) != READ) | ||
4880 | { | ||
4881 | msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); | ||
4882 | goto err_done; | ||
4883 | } | ||
4884 | p = req->rq_disk->private_data; | ||
4885 | #if OLD_BUSY | ||
4886 | while (busy_audio) sbp_sleep(HZ); /* wait a bit */ | ||
4887 | busy_data=1; | ||
4888 | #endif /* OLD_BUSY */ | ||
4889 | |||
4890 | if (p->audio_state==audio_playing) goto err_done; | ||
4891 | if (p != current_drive) | ||
4892 | switch_drive(p); | ||
4893 | |||
4894 | block = req->sector; /* always numbered as 512-byte-pieces */ | ||
4895 | nsect = req->nr_sectors; /* always counted as 512-byte-pieces */ | ||
4896 | |||
4897 | msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect); | ||
4898 | #if 0 | ||
4899 | msg(DBG_MUL,"read LBA %d\n", block/4); | ||
4900 | #endif | ||
4901 | |||
4902 | sbp_transfer(req); | ||
4903 | /* if we satisfied the request from the buffer, we're done. */ | ||
4904 | if (req->nr_sectors == 0) | ||
4905 | { | ||
4906 | #ifdef DEBUG_GTL | ||
4907 | printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n", | ||
4908 | xnr, req, req->sector, req->nr_sectors, jiffies); | ||
4909 | #endif | ||
4910 | up(&ioctl_read_sem); | ||
4911 | spin_lock_irq(q->queue_lock); | ||
4912 | end_request(req, 1); | ||
4913 | goto request_loop; | ||
4914 | } | ||
4915 | |||
4916 | #ifdef FUTURE | ||
4917 | i=prepare(0,0); /* at moment not really a hassle check, but ... */ | ||
4918 | if (i!=0) | ||
4919 | msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i); | ||
4920 | #endif /* FUTURE */ | ||
4921 | |||
4922 | if (!st_spinning) cc_SpinUp(); | ||
4923 | |||
4924 | for (data_tries=n_retries; data_tries > 0; data_tries--) | ||
4925 | { | ||
4926 | for (status_tries=3; status_tries > 0; status_tries--) | ||
4927 | { | ||
4928 | flags_cmd_out |= f_respo3; | ||
4929 | cc_ReadStatus(); | ||
4930 | if (sbp_status() != 0) break; | ||
4931 | if (st_check) cc_ReadError(); | ||
4932 | sbp_sleep(1); /* wait a bit, try again */ | ||
4933 | } | ||
4934 | if (status_tries == 0) | ||
4935 | { | ||
4936 | msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__); | ||
4937 | break; | ||
4938 | } | ||
4939 | |||
4940 | sbp_read_cmd(req); | ||
4941 | sbp_sleep(0); | ||
4942 | if (sbp_data(req) != 0) | ||
4943 | { | ||
4944 | #ifdef SAFE_MIXED | ||
4945 | current_drive->has_data=2; /* is really a data disk */ | ||
4946 | #endif /* SAFE_MIXED */ | ||
4947 | #ifdef DEBUG_GTL | ||
4948 | printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", | ||
4949 | xnr, req, req->sector, req->nr_sectors, jiffies); | ||
4950 | #endif | ||
4951 | up(&ioctl_read_sem); | ||
4952 | spin_lock_irq(q->queue_lock); | ||
4953 | end_request(req, 1); | ||
4954 | goto request_loop; | ||
4955 | } | ||
4956 | } | ||
4957 | |||
4958 | err_done: | ||
4959 | #if OLD_BUSY | ||
4960 | busy_data=0; | ||
4961 | #endif /* OLD_BUSY */ | ||
4962 | #ifdef DEBUG_GTL | ||
4963 | printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", | ||
4964 | xnr, req, req->sector, req->nr_sectors, jiffies); | ||
4965 | #endif | ||
4966 | up(&ioctl_read_sem); | ||
4967 | sbp_sleep(0); /* wait a bit, try again */ | ||
4968 | spin_lock_irq(q->queue_lock); | ||
4969 | end_request(req, 0); | ||
4970 | goto request_loop; | ||
4971 | } | ||
4972 | /*==========================================================================*/ | ||
4973 | /* | ||
4974 | * build and send the READ command. | ||
4975 | */ | ||
4976 | static void sbp_read_cmd(struct request *req) | ||
4977 | { | ||
4978 | #undef OLD | ||
4979 | |||
4980 | int i; | ||
4981 | int block; | ||
4982 | |||
4983 | current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */ | ||
4984 | current_drive->sbp_current = 0; | ||
4985 | block=req->sector/4; | ||
4986 | if (block+current_drive->sbp_bufsiz <= current_drive->CDsize_frm) | ||
4987 | current_drive->sbp_read_frames = current_drive->sbp_bufsiz; | ||
4988 | else | ||
4989 | { | ||
4990 | current_drive->sbp_read_frames=current_drive->CDsize_frm-block; | ||
4991 | /* avoid reading past end of data */ | ||
4992 | if (current_drive->sbp_read_frames < 1) | ||
4993 | { | ||
4994 | msg(DBG_INF,"requested frame %d, CD size %d ???\n", | ||
4995 | block, current_drive->CDsize_frm); | ||
4996 | current_drive->sbp_read_frames=1; | ||
4997 | } | ||
4998 | } | ||
4999 | |||
5000 | flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check; | ||
5001 | clr_cmdbuf(); | ||
5002 | if (famV_drive) | ||
5003 | { | ||
5004 | drvcmd[0]=CMDV_READ; | ||
5005 | lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ | ||
5006 | bin2bcdx(&drvcmd[1]); | ||
5007 | bin2bcdx(&drvcmd[2]); | ||
5008 | bin2bcdx(&drvcmd[3]); | ||
5009 | drvcmd[4]=current_drive->sbp_read_frames>>8; | ||
5010 | drvcmd[5]=current_drive->sbp_read_frames&0xff; | ||
5011 | drvcmd[6]=0x02; /* flag "msf-bcd" */ | ||
5012 | } | ||
5013 | else if (fam0L_drive) | ||
5014 | { | ||
5015 | flags_cmd_out |= f_lopsta | f_getsta | f_bit1; | ||
5016 | if (current_drive->xa_byte==0x20) | ||
5017 | { | ||
5018 | cmd_type=READ_M2; | ||
5019 | drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */ | ||
5020 | drvcmd[1]=(block>>16)&0x0ff; | ||
5021 | drvcmd[2]=(block>>8)&0x0ff; | ||
5022 | drvcmd[3]=block&0x0ff; | ||
5023 | drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
5024 | drvcmd[5]=current_drive->sbp_read_frames&0x0ff; | ||
5025 | } | ||
5026 | else | ||
5027 | { | ||
5028 | drvcmd[0]=CMD0_READ; /* "read frames", old drives */ | ||
5029 | if (current_drive->drv_type>=drv_201) | ||
5030 | { | ||
5031 | lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ | ||
5032 | bin2bcdx(&drvcmd[1]); | ||
5033 | bin2bcdx(&drvcmd[2]); | ||
5034 | bin2bcdx(&drvcmd[3]); | ||
5035 | } | ||
5036 | else | ||
5037 | { | ||
5038 | drvcmd[1]=(block>>16)&0x0ff; | ||
5039 | drvcmd[2]=(block>>8)&0x0ff; | ||
5040 | drvcmd[3]=block&0x0ff; | ||
5041 | } | ||
5042 | drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
5043 | drvcmd[5]=current_drive->sbp_read_frames&0x0ff; | ||
5044 | drvcmd[6]=(current_drive->drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */ | ||
5045 | } | ||
5046 | } | ||
5047 | else if (fam1_drive) | ||
5048 | { | ||
5049 | drvcmd[0]=CMD1_READ; | ||
5050 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
5051 | drvcmd[5]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
5052 | drvcmd[6]=current_drive->sbp_read_frames&0x0ff; | ||
5053 | } | ||
5054 | else if (fam2_drive) | ||
5055 | { | ||
5056 | drvcmd[0]=CMD2_READ; | ||
5057 | lba2msf(block,&drvcmd[1]); /* msf-bin format required */ | ||
5058 | drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
5059 | drvcmd[5]=current_drive->sbp_read_frames&0x0ff; | ||
5060 | drvcmd[6]=0x02; | ||
5061 | } | ||
5062 | else if (famT_drive) | ||
5063 | { | ||
5064 | drvcmd[0]=CMDT_READ; | ||
5065 | drvcmd[2]=(block>>24)&0x0ff; | ||
5066 | drvcmd[3]=(block>>16)&0x0ff; | ||
5067 | drvcmd[4]=(block>>8)&0x0ff; | ||
5068 | drvcmd[5]=block&0x0ff; | ||
5069 | drvcmd[7]=(current_drive->sbp_read_frames>>8)&0x0ff; | ||
5070 | drvcmd[8]=current_drive->sbp_read_frames&0x0ff; | ||
5071 | } | ||
5072 | flags_cmd_out=f_putcmd; | ||
5073 | response_count=0; | ||
5074 | i=cmd_out(); | ||
5075 | if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i); | ||
5076 | return; | ||
5077 | } | ||
5078 | /*==========================================================================*/ | ||
5079 | /* | ||
5080 | * Check the completion of the read-data command. On success, read | ||
5081 | * the current_drive->sbp_bufsiz * 2048 bytes of data from the disk into buffer. | ||
5082 | */ | ||
5083 | static int sbp_data(struct request *req) | ||
5084 | { | ||
5085 | int i=0, j=0, l, frame; | ||
5086 | u_int try=0; | ||
5087 | u_long timeout; | ||
5088 | u_char *p; | ||
5089 | u_int data_tries = 0; | ||
5090 | u_int data_waits = 0; | ||
5091 | u_int data_retrying = 0; | ||
5092 | int error_flag; | ||
5093 | int xa_count; | ||
5094 | int max_latency; | ||
5095 | int success; | ||
5096 | int wait; | ||
5097 | int duration; | ||
5098 | |||
5099 | error_flag=0; | ||
5100 | success=0; | ||
5101 | #if LONG_TIMING | ||
5102 | max_latency=9*HZ; | ||
5103 | #else | ||
5104 | if (current_drive->f_multisession) max_latency=15*HZ; | ||
5105 | else max_latency=5*HZ; | ||
5106 | #endif | ||
5107 | duration=jiffies; | ||
5108 | for (frame=0;frame<current_drive->sbp_read_frames&&!error_flag; frame++) | ||
5109 | { | ||
5110 | SBPCD_CLI; | ||
5111 | |||
5112 | del_timer(&data_timer); | ||
5113 | data_timer.expires=jiffies+max_latency; | ||
5114 | timed_out_data=0; | ||
5115 | add_timer(&data_timer); | ||
5116 | while (!timed_out_data) | ||
5117 | { | ||
5118 | if (current_drive->f_multisession) try=maxtim_data*4; | ||
5119 | else try=maxtim_data; | ||
5120 | msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try); | ||
5121 | for ( ; try!=0;try--) | ||
5122 | { | ||
5123 | j=inb(CDi_status); | ||
5124 | if (!(j&s_not_data_ready)) break; | ||
5125 | if (!(j&s_not_result_ready)) break; | ||
5126 | if (fam0LV_drive) if (j&s_attention) break; | ||
5127 | } | ||
5128 | if (!(j&s_not_data_ready)) goto data_ready; | ||
5129 | if (try==0) | ||
5130 | { | ||
5131 | if (data_retrying == 0) data_waits++; | ||
5132 | data_retrying = 1; | ||
5133 | msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n"); | ||
5134 | sbp_sleep(1); | ||
5135 | try = 1; | ||
5136 | } | ||
5137 | } | ||
5138 | msg(DBG_INF,"sbp_data: CDi_status loop expired.\n"); | ||
5139 | data_ready: | ||
5140 | del_timer(&data_timer); | ||
5141 | |||
5142 | if (timed_out_data) | ||
5143 | { | ||
5144 | msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j); | ||
5145 | error_flag++; | ||
5146 | } | ||
5147 | if (try==0) | ||
5148 | { | ||
5149 | msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j); | ||
5150 | error_flag++; | ||
5151 | } | ||
5152 | if (!(j&s_not_result_ready)) | ||
5153 | { | ||
5154 | msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j); | ||
5155 | response_count=20; | ||
5156 | j=ResponseInfo(); | ||
5157 | j=inb(CDi_status); | ||
5158 | } | ||
5159 | if (j&s_not_data_ready) | ||
5160 | { | ||
5161 | if ((current_drive->ored_ctl_adr&0x40)==0) | ||
5162 | msg(DBG_INF, "CD contains no data tracks.\n"); | ||
5163 | else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j); | ||
5164 | error_flag++; | ||
5165 | } | ||
5166 | SBPCD_STI; | ||
5167 | if (error_flag) break; | ||
5168 | |||
5169 | msg(DBG_000, "sbp_data: beginning to read.\n"); | ||
5170 | p = current_drive->sbp_buf + frame * CD_FRAMESIZE; | ||
5171 | if (sbpro_type==1) OUT(CDo_sel_i_d,1); | ||
5172 | if (cmd_type==READ_M2) { | ||
5173 | if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1); | ||
5174 | else insb(CDi_data, xa_head_buf, CD_XA_HEAD); | ||
5175 | } | ||
5176 | if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1); | ||
5177 | else insb(CDi_data, p, CD_FRAMESIZE); | ||
5178 | if (cmd_type==READ_M2) { | ||
5179 | if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1); | ||
5180 | else insb(CDi_data, xa_tail_buf, CD_XA_TAIL); | ||
5181 | } | ||
5182 | current_drive->sbp_current++; | ||
5183 | if (sbpro_type==1) OUT(CDo_sel_i_d,0); | ||
5184 | if (cmd_type==READ_M2) | ||
5185 | { | ||
5186 | for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++) | ||
5187 | sprintf(&msgbuf[xa_count*3], " %02X", xa_head_buf[xa_count]); | ||
5188 | msgbuf[xa_count*3]=0; | ||
5189 | msg(DBG_XA1,"xa head:%s\n", msgbuf); | ||
5190 | } | ||
5191 | data_retrying = 0; | ||
5192 | data_tries++; | ||
5193 | if (data_tries >= 1000) | ||
5194 | { | ||
5195 | msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries); | ||
5196 | data_waits = data_tries = 0; | ||
5197 | } | ||
5198 | } | ||
5199 | duration=jiffies-duration; | ||
5200 | msg(DBG_TEA,"time to read %d frames: %d jiffies .\n",frame,duration); | ||
5201 | if (famT_drive) | ||
5202 | { | ||
5203 | wait=8; | ||
5204 | do | ||
5205 | { | ||
5206 | if (teac==2) | ||
5207 | { | ||
5208 | if ((i=CDi_stat_loop_T()) == -1) break; | ||
5209 | } | ||
5210 | else | ||
5211 | { | ||
5212 | sbp_sleep(1); | ||
5213 | OUT(CDo_sel_i_d,0); | ||
5214 | i=inb(CDi_status); | ||
5215 | } | ||
5216 | if (!(i&s_not_data_ready)) | ||
5217 | { | ||
5218 | OUT(CDo_sel_i_d,1); | ||
5219 | j=0; | ||
5220 | do | ||
5221 | { | ||
5222 | if (do_16bit) i=inw(CDi_data); | ||
5223 | else i=inb(CDi_data); | ||
5224 | j++; | ||
5225 | i=inb(CDi_status); | ||
5226 | } | ||
5227 | while (!(i&s_not_data_ready)); | ||
5228 | msg(DBG_TEA, "==========too much data (%d bytes/words)==============.\n", j); | ||
5229 | } | ||
5230 | if (!(i&s_not_result_ready)) | ||
5231 | { | ||
5232 | OUT(CDo_sel_i_d,0); | ||
5233 | l=0; | ||
5234 | do | ||
5235 | { | ||
5236 | infobuf[l++]=inb(CDi_info); | ||
5237 | i=inb(CDi_status); | ||
5238 | } | ||
5239 | while (!(i&s_not_result_ready)); | ||
5240 | if (infobuf[0]==0x00) success=1; | ||
5241 | #if 1 | ||
5242 | for (j=0;j<l;j++) sprintf(&msgbuf[j*3], " %02X", infobuf[j]); | ||
5243 | msgbuf[j*3]=0; | ||
5244 | msg(DBG_TEA,"sbp_data info response:%s\n", msgbuf); | ||
5245 | #endif | ||
5246 | if (infobuf[0]==0x02) | ||
5247 | { | ||
5248 | error_flag++; | ||
5249 | do | ||
5250 | { | ||
5251 | ++recursion; | ||
5252 | if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion); | ||
5253 | else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n"); | ||
5254 | clr_cmdbuf(); | ||
5255 | drvcmd[0]=CMDT_READ_ERR; | ||
5256 | j=cmd_out_T(); /* !!! recursive here !!! */ | ||
5257 | --recursion; | ||
5258 | sbp_sleep(1); | ||
5259 | } | ||
5260 | while (j<0); | ||
5261 | current_drive->error_state=infobuf[2]; | ||
5262 | current_drive->b3=infobuf[3]; | ||
5263 | current_drive->b4=infobuf[4]; | ||
5264 | } | ||
5265 | break; | ||
5266 | } | ||
5267 | else | ||
5268 | { | ||
5269 | #if 0 | ||
5270 | msg(DBG_TEA, "============= waiting for result=================.\n"); | ||
5271 | sbp_sleep(1); | ||
5272 | #endif | ||
5273 | } | ||
5274 | } | ||
5275 | while (wait--); | ||
5276 | } | ||
5277 | |||
5278 | if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ | ||
5279 | { | ||
5280 | msg(DBG_TEA, "================error flag: %d=================.\n", error_flag); | ||
5281 | msg(DBG_INF,"sbp_data: read aborted by drive.\n"); | ||
5282 | #if 1 | ||
5283 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
5284 | #else | ||
5285 | i=cc_ReadError(); | ||
5286 | #endif | ||
5287 | return (0); | ||
5288 | } | ||
5289 | |||
5290 | if (fam0LV_drive) | ||
5291 | { | ||
5292 | SBPCD_CLI; | ||
5293 | i=maxtim_data; | ||
5294 | for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--) | ||
5295 | { | ||
5296 | for ( ;i!=0;i--) | ||
5297 | { | ||
5298 | j=inb(CDi_status); | ||
5299 | if (!(j&s_not_data_ready)) break; | ||
5300 | if (!(j&s_not_result_ready)) break; | ||
5301 | if (j&s_attention) break; | ||
5302 | } | ||
5303 | if (i != 0 || time_after_eq(jiffies, timeout)) break; | ||
5304 | sbp_sleep(0); | ||
5305 | i = 1; | ||
5306 | } | ||
5307 | if (i==0) msg(DBG_INF,"status timeout after READ.\n"); | ||
5308 | if (!(j&s_attention)) | ||
5309 | { | ||
5310 | msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n"); | ||
5311 | i=cc_DriveReset(); /* ugly fix to prevent a hang */ | ||
5312 | SBPCD_STI; | ||
5313 | return (0); | ||
5314 | } | ||
5315 | SBPCD_STI; | ||
5316 | } | ||
5317 | |||
5318 | #if 0 | ||
5319 | if (!success) | ||
5320 | #endif | ||
5321 | do | ||
5322 | { | ||
5323 | if (fam0LV_drive) cc_ReadStatus(); | ||
5324 | #if 1 | ||
5325 | if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i); | ||
5326 | #endif | ||
5327 | i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ | ||
5328 | #if 1 | ||
5329 | if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i); | ||
5330 | #endif | ||
5331 | if (i<0) | ||
5332 | { | ||
5333 | msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", current_drive->status_bits); | ||
5334 | return (0); | ||
5335 | } | ||
5336 | } | ||
5337 | while ((fam0LV_drive)&&(!st_check)&&(!(i&p_success))); | ||
5338 | if (st_check) | ||
5339 | { | ||
5340 | i=cc_ReadError(); | ||
5341 | msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i); | ||
5342 | return (0); | ||
5343 | } | ||
5344 | if (fatal_err) | ||
5345 | { | ||
5346 | fatal_err=0; | ||
5347 | current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */ | ||
5348 | current_drive->sbp_current = 0; | ||
5349 | msg(DBG_INF,"sbp_data: fatal_err - retrying.\n"); | ||
5350 | return (0); | ||
5351 | } | ||
5352 | |||
5353 | current_drive->sbp_first_frame = req -> sector / 4; | ||
5354 | current_drive->sbp_last_frame = current_drive->sbp_first_frame + current_drive->sbp_read_frames - 1; | ||
5355 | sbp_transfer(req); | ||
5356 | return (1); | ||
5357 | } | ||
5358 | /*==========================================================================*/ | ||
5359 | |||
5360 | static int sbpcd_block_open(struct inode *inode, struct file *file) | ||
5361 | { | ||
5362 | struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; | ||
5363 | return cdrom_open(p->sbpcd_infop, inode, file); | ||
5364 | } | ||
5365 | |||
5366 | static int sbpcd_block_release(struct inode *inode, struct file *file) | ||
5367 | { | ||
5368 | struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; | ||
5369 | return cdrom_release(p->sbpcd_infop, file); | ||
5370 | } | ||
5371 | |||
5372 | static int sbpcd_block_ioctl(struct inode *inode, struct file *file, | ||
5373 | unsigned cmd, unsigned long arg) | ||
5374 | { | ||
5375 | struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; | ||
5376 | return cdrom_ioctl(file, p->sbpcd_infop, inode, cmd, arg); | ||
5377 | } | ||
5378 | |||
5379 | static int sbpcd_block_media_changed(struct gendisk *disk) | ||
5380 | { | ||
5381 | struct sbpcd_drive *p = disk->private_data; | ||
5382 | return cdrom_media_changed(p->sbpcd_infop); | ||
5383 | } | ||
5384 | |||
5385 | static struct block_device_operations sbpcd_bdops = | ||
5386 | { | ||
5387 | .owner = THIS_MODULE, | ||
5388 | .open = sbpcd_block_open, | ||
5389 | .release = sbpcd_block_release, | ||
5390 | .ioctl = sbpcd_block_ioctl, | ||
5391 | .media_changed = sbpcd_block_media_changed, | ||
5392 | }; | ||
5393 | /*==========================================================================*/ | ||
5394 | /* | ||
5395 | * Open the device special file. Check that a disk is in. Read TOC. | ||
5396 | */ | ||
5397 | static int sbpcd_open(struct cdrom_device_info *cdi, int purpose) | ||
5398 | { | ||
5399 | struct sbpcd_drive *p = cdi->handle; | ||
5400 | |||
5401 | down(&ioctl_read_sem); | ||
5402 | switch_drive(p); | ||
5403 | |||
5404 | /* | ||
5405 | * try to keep an "open" counter here and lock the door if 0->1. | ||
5406 | */ | ||
5407 | msg(DBG_LCK,"open_count: %d -> %d\n", | ||
5408 | current_drive->open_count,current_drive->open_count+1); | ||
5409 | if (++current_drive->open_count<=1) | ||
5410 | { | ||
5411 | int i; | ||
5412 | i=LockDoor(); | ||
5413 | current_drive->open_count=1; | ||
5414 | if (famT_drive) msg(DBG_TEA,"sbpcd_open: before i=DiskInfo();.\n"); | ||
5415 | i=DiskInfo(); | ||
5416 | if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n"); | ||
5417 | if ((current_drive->ored_ctl_adr&0x40)==0) | ||
5418 | { | ||
5419 | msg(DBG_INF,"CD contains no data tracks.\n"); | ||
5420 | #ifdef SAFE_MIXED | ||
5421 | current_drive->has_data=0; | ||
5422 | #endif /* SAFE_MIXED */ | ||
5423 | } | ||
5424 | #ifdef SAFE_MIXED | ||
5425 | else if (current_drive->has_data<1) current_drive->has_data=1; | ||
5426 | #endif /* SAFE_MIXED */ | ||
5427 | } | ||
5428 | if (!st_spinning) cc_SpinUp(); | ||
5429 | RETURN_UP(0); | ||
5430 | } | ||
5431 | /*==========================================================================*/ | ||
5432 | /* | ||
5433 | * On close, we flush all sbp blocks from the buffer cache. | ||
5434 | */ | ||
5435 | static void sbpcd_release(struct cdrom_device_info * cdi) | ||
5436 | { | ||
5437 | struct sbpcd_drive *p = cdi->handle; | ||
5438 | |||
5439 | if (p->drv_id==-1) { | ||
5440 | msg(DBG_INF, "release: bad device: %s\n", cdi->name); | ||
5441 | return; | ||
5442 | } | ||
5443 | down(&ioctl_read_sem); | ||
5444 | switch_drive(p); | ||
5445 | /* | ||
5446 | * try to keep an "open" counter here and unlock the door if 1->0. | ||
5447 | */ | ||
5448 | msg(DBG_LCK,"open_count: %d -> %d\n", | ||
5449 | p->open_count,p->open_count-1); | ||
5450 | if (p->open_count>-2) /* CDROMEJECT may have been done */ | ||
5451 | { | ||
5452 | if (--p->open_count<=0) | ||
5453 | { | ||
5454 | p->sbp_first_frame=p->sbp_last_frame=-1; | ||
5455 | if (p->audio_state!=audio_playing) | ||
5456 | if (p->f_eject) cc_SpinDown(); | ||
5457 | p->diskstate_flags &= ~cd_size_bit; | ||
5458 | p->open_count=0; | ||
5459 | #ifdef SAFE_MIXED | ||
5460 | p->has_data=0; | ||
5461 | #endif /* SAFE_MIXED */ | ||
5462 | } | ||
5463 | } | ||
5464 | up(&ioctl_read_sem); | ||
5465 | return ; | ||
5466 | } | ||
5467 | /*==========================================================================*/ | ||
5468 | /* | ||
5469 | * | ||
5470 | */ | ||
5471 | static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr); | ||
5472 | static struct cdrom_device_ops sbpcd_dops = { | ||
5473 | .open = sbpcd_open, | ||
5474 | .release = sbpcd_release, | ||
5475 | .drive_status = sbpcd_drive_status, | ||
5476 | .media_changed = sbpcd_media_changed, | ||
5477 | .tray_move = sbpcd_tray_move, | ||
5478 | .lock_door = sbpcd_lock_door, | ||
5479 | .select_speed = sbpcd_select_speed, | ||
5480 | .get_last_session = sbpcd_get_last_session, | ||
5481 | .get_mcn = sbpcd_get_mcn, | ||
5482 | .reset = sbpcd_reset, | ||
5483 | .audio_ioctl = sbpcd_audio_ioctl, | ||
5484 | .dev_ioctl = sbpcd_dev_ioctl, | ||
5485 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | | ||
5486 | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | | ||
5487 | CDC_MCN | CDC_PLAY_AUDIO | CDC_IOCTLS, | ||
5488 | .n_minors = 1, | ||
5489 | }; | ||
5490 | |||
5491 | /*==========================================================================*/ | ||
5492 | /* | ||
5493 | * accept "kernel command line" parameters | ||
5494 | * (suggested by Peter MacDonald with SLS 1.03) | ||
5495 | * | ||
5496 | * This is only implemented for the first controller. Should be enough to | ||
5497 | * allow installing with a "strange" distribution kernel. | ||
5498 | * | ||
5499 | * use: tell LILO: | ||
5500 | * sbpcd=0x230,SoundBlaster | ||
5501 | * or | ||
5502 | * sbpcd=0x300,LaserMate | ||
5503 | * or | ||
5504 | * sbpcd=0x338,SoundScape | ||
5505 | * or | ||
5506 | * sbpcd=0x2C0,Teac16bit | ||
5507 | * | ||
5508 | * (upper/lower case sensitive here - but all-lowercase is ok!!!). | ||
5509 | * | ||
5510 | * the address value has to be the CDROM PORT ADDRESS - | ||
5511 | * not the soundcard base address. | ||
5512 | * For the SPEA/SoundScape setup, DO NOT specify the "configuration port" | ||
5513 | * address, but the address which is really used for the CDROM (usually 8 | ||
5514 | * bytes above). | ||
5515 | * | ||
5516 | */ | ||
5517 | |||
5518 | int sbpcd_setup(char *s) | ||
5519 | { | ||
5520 | #ifndef MODULE | ||
5521 | int p[4]; | ||
5522 | (void)get_options(s, ARRAY_SIZE(p), p); | ||
5523 | setup_done++; | ||
5524 | msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s); | ||
5525 | sbpro_type=0; /* default: "LaserMate" */ | ||
5526 | if (p[0]>1) sbpro_type=p[2]; | ||
5527 | else if (!strcmp(s,str_sb)) sbpro_type=1; | ||
5528 | else if (!strcmp(s,str_sb_l)) sbpro_type=1; | ||
5529 | else if (!strcmp(s,str_sp)) sbpro_type=2; | ||
5530 | else if (!strcmp(s,str_sp_l)) sbpro_type=2; | ||
5531 | else if (!strcmp(s,str_ss)) sbpro_type=2; | ||
5532 | else if (!strcmp(s,str_ss_l)) sbpro_type=2; | ||
5533 | else if (!strcmp(s,str_t16)) sbpro_type=3; | ||
5534 | else if (!strcmp(s,str_t16_l)) sbpro_type=3; | ||
5535 | if (p[0]>0) sbpcd_ioaddr=p[1]; | ||
5536 | if (p[0]>2) max_drives=p[3]; | ||
5537 | #else | ||
5538 | sbpcd_ioaddr = sbpcd[0]; | ||
5539 | sbpro_type = sbpcd[1]; | ||
5540 | #endif | ||
5541 | |||
5542 | CDo_command=sbpcd_ioaddr; | ||
5543 | CDi_info=sbpcd_ioaddr; | ||
5544 | CDi_status=sbpcd_ioaddr+1; | ||
5545 | CDo_sel_i_d=sbpcd_ioaddr+1; | ||
5546 | CDo_reset=sbpcd_ioaddr+2; | ||
5547 | CDo_enable=sbpcd_ioaddr+3; | ||
5548 | f_16bit=0; | ||
5549 | if ((sbpro_type==1)||(sbpro_type==3)) | ||
5550 | { | ||
5551 | CDi_data=sbpcd_ioaddr; | ||
5552 | if (sbpro_type==3) | ||
5553 | { | ||
5554 | f_16bit=1; | ||
5555 | sbpro_type=1; | ||
5556 | } | ||
5557 | } | ||
5558 | else CDi_data=sbpcd_ioaddr+2; | ||
5559 | |||
5560 | return 1; | ||
5561 | } | ||
5562 | |||
5563 | __setup("sbpcd=", sbpcd_setup); | ||
5564 | |||
5565 | |||
5566 | /*==========================================================================*/ | ||
5567 | /* | ||
5568 | * Sequoia S-1000 CD-ROM Interface Configuration | ||
5569 | * as used within SPEA Media FX, Ensonic SoundScape and some Reveal cards | ||
5570 | * The soundcard has to get jumpered for the interface type "Panasonic" | ||
5571 | * (not Sony or Mitsumi) and to get soft-configured for | ||
5572 | * -> configuration port address | ||
5573 | * -> CDROM port offset (num_ports): has to be 8 here. Possibly this | ||
5574 | * offset value determines the interface type (none, Panasonic, | ||
5575 | * Mitsumi, Sony). | ||
5576 | * The interface uses a configuration port (0x320, 0x330, 0x340, 0x350) | ||
5577 | * some bytes below the real CDROM address. | ||
5578 | * | ||
5579 | * For the Panasonic style (LaserMate) interface and the configuration | ||
5580 | * port 0x330, we have to use an offset of 8; so, the real CDROM port | ||
5581 | * address is 0x338. | ||
5582 | */ | ||
5583 | static int __init config_spea(void) | ||
5584 | { | ||
5585 | /* | ||
5586 | * base address offset between configuration port and CDROM port, | ||
5587 | * this probably defines the interface type | ||
5588 | * 2 (type=??): 0x00 | ||
5589 | * 8 (type=LaserMate):0x10 | ||
5590 | * 16 (type=??):0x20 | ||
5591 | * 32 (type=??):0x30 | ||
5592 | */ | ||
5593 | int n_ports=0x10; | ||
5594 | |||
5595 | int irq_number=0; /* off:0x00, 2/9:0x01, 7:0x03, 12:0x05, 15:0x07 */ | ||
5596 | int dma_channel=0; /* off: 0x00, 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68 */ | ||
5597 | int dack_polarity=0; /* L:0x00, H:0x80 */ | ||
5598 | int drq_polarity=0x40; /* L:0x00, H:0x40 */ | ||
5599 | int i; | ||
5600 | |||
5601 | #define SPEA_REG_1 sbpcd_ioaddr-0x08+4 | ||
5602 | #define SPEA_REG_2 sbpcd_ioaddr-0x08+5 | ||
5603 | |||
5604 | OUT(SPEA_REG_1,0xFF); | ||
5605 | i=inb(SPEA_REG_1); | ||
5606 | if (i!=0x0F) | ||
5607 | { | ||
5608 | msg(DBG_SEQ,"no SPEA interface at %04X present.\n", sbpcd_ioaddr); | ||
5609 | return (-1); /* no interface found */ | ||
5610 | } | ||
5611 | OUT(SPEA_REG_1,0x04); | ||
5612 | OUT(SPEA_REG_2,0xC0); | ||
5613 | |||
5614 | OUT(SPEA_REG_1,0x05); | ||
5615 | OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity); | ||
5616 | |||
5617 | #if 1 | ||
5618 | #define SPEA_PATTERN 0x80 | ||
5619 | #else | ||
5620 | #define SPEA_PATTERN 0x00 | ||
5621 | #endif | ||
5622 | OUT(SPEA_REG_1,0x06); | ||
5623 | OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); | ||
5624 | OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); | ||
5625 | |||
5626 | OUT(SPEA_REG_1,0x09); | ||
5627 | i=(inb(SPEA_REG_2)&0xCF)|n_ports; | ||
5628 | OUT(SPEA_REG_2,i); | ||
5629 | |||
5630 | sbpro_type = 0; /* acts like a LaserMate interface now */ | ||
5631 | msg(DBG_SEQ,"found SoundScape interface at %04X.\n", sbpcd_ioaddr); | ||
5632 | return (0); | ||
5633 | } | ||
5634 | |||
5635 | /*==========================================================================*/ | ||
5636 | /* | ||
5637 | * Test for presence of drive and initialize it. | ||
5638 | * Called once at boot or load time. | ||
5639 | */ | ||
5640 | |||
5641 | /* FIXME: cleanups after failed allocations are too ugly for words */ | ||
5642 | #ifdef MODULE | ||
5643 | int __init __sbpcd_init(void) | ||
5644 | #else | ||
5645 | int __init sbpcd_init(void) | ||
5646 | #endif | ||
5647 | { | ||
5648 | int i=0, j=0; | ||
5649 | int addr[2]={1, CDROM_PORT}; | ||
5650 | int port_index; | ||
5651 | |||
5652 | sti(); | ||
5653 | |||
5654 | msg(DBG_INF,"sbpcd.c %s\n", VERSION); | ||
5655 | #ifndef MODULE | ||
5656 | #if DISTRIBUTION | ||
5657 | if (!setup_done) | ||
5658 | { | ||
5659 | msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, Longshine, TEAC CD-ROM drives\n"); | ||
5660 | msg(DBG_INF,"= = = = = = = = = = W A R N I N G = = = = = = = = = =\n"); | ||
5661 | msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an NE2000 card).\n"); | ||
5662 | msg(DBG_INF,"If that happens, you have to reboot and use the\n"); | ||
5663 | msg(DBG_INF,"LILO (kernel) command line feature like:\n"); | ||
5664 | msg(DBG_INF," LILO boot: ... sbpcd=0x230,SoundBlaster\n"); | ||
5665 | msg(DBG_INF,"or like:\n"); | ||
5666 | msg(DBG_INF," LILO boot: ... sbpcd=0x300,LaserMate\n"); | ||
5667 | msg(DBG_INF,"or like:\n"); | ||
5668 | msg(DBG_INF," LILO boot: ... sbpcd=0x338,SoundScape\n"); | ||
5669 | msg(DBG_INF,"with your REAL address.\n"); | ||
5670 | msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n"); | ||
5671 | } | ||
5672 | #endif /* DISTRIBUTION */ | ||
5673 | sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ | ||
5674 | sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */ | ||
5675 | #endif /* MODULE */ | ||
5676 | |||
5677 | for (port_index=0;port_index<NUM_PROBE;port_index+=2) | ||
5678 | { | ||
5679 | addr[1]=sbpcd[port_index]; | ||
5680 | if (addr[1]==0) break; | ||
5681 | if (check_region(addr[1],4)) | ||
5682 | { | ||
5683 | msg(DBG_INF,"check_region: %03X is not free.\n",addr[1]); | ||
5684 | continue; | ||
5685 | } | ||
5686 | if (sbpcd[port_index+1]==2) type=str_sp; | ||
5687 | else if (sbpcd[port_index+1]==1) type=str_sb; | ||
5688 | else if (sbpcd[port_index+1]==3) type=str_t16; | ||
5689 | else type=str_lm; | ||
5690 | sbpcd_setup((char *)type); | ||
5691 | #if DISTRIBUTION | ||
5692 | msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type); | ||
5693 | #endif /* DISTRIBUTION */ | ||
5694 | if (sbpcd[port_index+1]==2) | ||
5695 | { | ||
5696 | i=config_spea(); | ||
5697 | if (i<0) continue; | ||
5698 | } | ||
5699 | #ifdef PATH_CHECK | ||
5700 | if (check_card(addr[1])) continue; | ||
5701 | #endif /* PATH_CHECK */ | ||
5702 | i=check_drives(); | ||
5703 | msg(DBG_INI,"check_drives done.\n"); | ||
5704 | if (i>=0) break; /* drive found */ | ||
5705 | } /* end of cycling through the set of possible I/O port addresses */ | ||
5706 | |||
5707 | if (ndrives==0) | ||
5708 | { | ||
5709 | msg(DBG_INF, "No drive found.\n"); | ||
5710 | #ifdef MODULE | ||
5711 | return -EIO; | ||
5712 | #else | ||
5713 | goto init_done; | ||
5714 | #endif /* MODULE */ | ||
5715 | } | ||
5716 | |||
5717 | if (port_index>0) | ||
5718 | { | ||
5719 | msg(DBG_INF, "You should read Documentation/cdrom/sbpcd\n"); | ||
5720 | msg(DBG_INF, "and then configure sbpcd.h for your hardware.\n"); | ||
5721 | } | ||
5722 | check_datarate(); | ||
5723 | msg(DBG_INI,"check_datarate done.\n"); | ||
5724 | |||
5725 | for (j=0;j<NR_SBPCD;j++) | ||
5726 | { | ||
5727 | struct sbpcd_drive *p = D_S + j; | ||
5728 | if (p->drv_id==-1) | ||
5729 | continue; | ||
5730 | switch_drive(p); | ||
5731 | #if 1 | ||
5732 | if (!famL_drive) cc_DriveReset(); | ||
5733 | #endif | ||
5734 | if (!st_spinning) cc_SpinUp(); | ||
5735 | p->sbp_first_frame = -1; /* First frame in buffer */ | ||
5736 | p->sbp_last_frame = -1; /* Last frame in buffer */ | ||
5737 | p->sbp_read_frames = 0; /* Number of frames being read to buffer */ | ||
5738 | p->sbp_current = 0; /* Frame being currently read */ | ||
5739 | p->CD_changed=1; | ||
5740 | p->frame_size=CD_FRAMESIZE; | ||
5741 | p->f_eject=0; | ||
5742 | #if EJECT | ||
5743 | if (!fam0_drive) p->f_eject=1; | ||
5744 | #endif /* EJECT */ | ||
5745 | cc_ReadStatus(); | ||
5746 | i=ResponseStatus(); /* returns orig. status or p_busy_new */ | ||
5747 | if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */ | ||
5748 | if (i<0) | ||
5749 | { | ||
5750 | if (i!=-402) | ||
5751 | msg(DBG_INF,"init: ResponseStatus returns %d.\n",i); | ||
5752 | } | ||
5753 | else | ||
5754 | { | ||
5755 | if (st_check) | ||
5756 | { | ||
5757 | i=cc_ReadError(); | ||
5758 | msg(DBG_INI,"init: cc_ReadError returns %d\n",i); | ||
5759 | } | ||
5760 | } | ||
5761 | msg(DBG_INI,"init: first GetStatus: %d\n",i); | ||
5762 | msg(DBG_LCS,"init: first GetStatus: error_byte=%d\n", | ||
5763 | p->error_byte); | ||
5764 | if (p->error_byte==aud_12) | ||
5765 | { | ||
5766 | timeout=jiffies+2*HZ; | ||
5767 | do | ||
5768 | { | ||
5769 | i=GetStatus(); | ||
5770 | msg(DBG_INI,"init: second GetStatus: %02X\n",i); | ||
5771 | msg(DBG_LCS, | ||
5772 | "init: second GetStatus: error_byte=%d\n", | ||
5773 | p->error_byte); | ||
5774 | if (i<0) break; | ||
5775 | if (!st_caddy_in) break; | ||
5776 | } | ||
5777 | while ((!st_diskok)||time_after(jiffies, timeout)); | ||
5778 | } | ||
5779 | i=SetSpeed(); | ||
5780 | if (i>=0) p->CD_changed=1; | ||
5781 | } | ||
5782 | |||
5783 | if (!request_region(CDo_command,4,major_name)) | ||
5784 | { | ||
5785 | printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command); | ||
5786 | return -EIO; | ||
5787 | } | ||
5788 | |||
5789 | /* | ||
5790 | * Turn on the CD audio channels. | ||
5791 | * The addresses are obtained from SOUND_BASE (see sbpcd.h). | ||
5792 | */ | ||
5793 | #if SOUND_BASE | ||
5794 | OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */ | ||
5795 | OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */ | ||
5796 | #endif /* SOUND_BASE */ | ||
5797 | |||
5798 | if (register_blkdev(MAJOR_NR, major_name)) { | ||
5799 | #ifdef MODULE | ||
5800 | return -EIO; | ||
5801 | #else | ||
5802 | goto init_done; | ||
5803 | #endif /* MODULE */ | ||
5804 | } | ||
5805 | |||
5806 | /* | ||
5807 | * init error handling is broken beyond belief in this driver... | ||
5808 | */ | ||
5809 | sbpcd_queue = blk_init_queue(do_sbpcd_request, &sbpcd_lock); | ||
5810 | if (!sbpcd_queue) { | ||
5811 | release_region(CDo_command,4); | ||
5812 | unregister_blkdev(MAJOR_NR, major_name); | ||
5813 | return -ENOMEM; | ||
5814 | } | ||
5815 | |||
5816 | devfs_mk_dir("sbp"); | ||
5817 | |||
5818 | for (j=0;j<NR_SBPCD;j++) | ||
5819 | { | ||
5820 | struct cdrom_device_info * sbpcd_infop; | ||
5821 | struct gendisk *disk; | ||
5822 | struct sbpcd_drive *p = D_S + j; | ||
5823 | |||
5824 | if (p->drv_id==-1) continue; | ||
5825 | switch_drive(p); | ||
5826 | #ifdef SAFE_MIXED | ||
5827 | p->has_data=0; | ||
5828 | #endif /* SAFE_MIXED */ | ||
5829 | /* | ||
5830 | * allocate memory for the frame buffers | ||
5831 | */ | ||
5832 | p->aud_buf=NULL; | ||
5833 | p->sbp_audsiz=0; | ||
5834 | p->sbp_bufsiz=buffers; | ||
5835 | if (p->drv_type&drv_fam1) | ||
5836 | if (READ_AUDIO>0) | ||
5837 | p->sbp_audsiz = READ_AUDIO; | ||
5838 | p->sbp_buf=(u_char *) vmalloc(buffers*CD_FRAMESIZE); | ||
5839 | if (!p->sbp_buf) { | ||
5840 | msg(DBG_INF,"data buffer (%d frames) not available.\n", | ||
5841 | buffers); | ||
5842 | if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) | ||
5843 | { | ||
5844 | printk("Can't unregister %s\n", major_name); | ||
5845 | } | ||
5846 | release_region(CDo_command,4); | ||
5847 | blk_cleanup_queue(sbpcd_queue); | ||
5848 | return -EIO; | ||
5849 | } | ||
5850 | #ifdef MODULE | ||
5851 | msg(DBG_INF,"data buffer size: %d frames.\n",buffers); | ||
5852 | #endif /* MODULE */ | ||
5853 | if (p->sbp_audsiz>0) | ||
5854 | { | ||
5855 | p->aud_buf=(u_char *) vmalloc(p->sbp_audsiz*CD_FRAMESIZE_RAW); | ||
5856 | if (p->aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",p->sbp_audsiz); | ||
5857 | else msg(DBG_INF,"audio buffer size: %d frames.\n",p->sbp_audsiz); | ||
5858 | } | ||
5859 | sbpcd_infop = vmalloc(sizeof (struct cdrom_device_info)); | ||
5860 | if (sbpcd_infop == NULL) | ||
5861 | { | ||
5862 | release_region(CDo_command,4); | ||
5863 | blk_cleanup_queue(sbpcd_queue); | ||
5864 | return -ENOMEM; | ||
5865 | } | ||
5866 | memset(sbpcd_infop, 0, sizeof(struct cdrom_device_info)); | ||
5867 | sbpcd_infop->ops = &sbpcd_dops; | ||
5868 | sbpcd_infop->speed = 2; | ||
5869 | sbpcd_infop->capacity = 1; | ||
5870 | sprintf(sbpcd_infop->name, "sbpcd%d", j); | ||
5871 | sbpcd_infop->handle = p; | ||
5872 | p->sbpcd_infop = sbpcd_infop; | ||
5873 | disk = alloc_disk(1); | ||
5874 | disk->major = MAJOR_NR; | ||
5875 | disk->first_minor = j; | ||
5876 | disk->fops = &sbpcd_bdops; | ||
5877 | strcpy(disk->disk_name, sbpcd_infop->name); | ||
5878 | disk->flags = GENHD_FL_CD; | ||
5879 | sprintf(disk->devfs_name, "sbp/c0t%d", p->drv_id); | ||
5880 | p->disk = disk; | ||
5881 | if (register_cdrom(sbpcd_infop)) | ||
5882 | { | ||
5883 | printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n"); | ||
5884 | } | ||
5885 | disk->private_data = p; | ||
5886 | disk->queue = sbpcd_queue; | ||
5887 | add_disk(disk); | ||
5888 | } | ||
5889 | blk_queue_hardsect_size(sbpcd_queue, CD_FRAMESIZE); | ||
5890 | |||
5891 | #ifndef MODULE | ||
5892 | init_done: | ||
5893 | #endif | ||
5894 | return 0; | ||
5895 | } | ||
5896 | /*==========================================================================*/ | ||
5897 | #ifdef MODULE | ||
5898 | void sbpcd_exit(void) | ||
5899 | { | ||
5900 | int j; | ||
5901 | |||
5902 | if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) | ||
5903 | { | ||
5904 | msg(DBG_INF, "What's that: can't unregister %s.\n", major_name); | ||
5905 | return; | ||
5906 | } | ||
5907 | release_region(CDo_command,4); | ||
5908 | blk_cleanup_queue(sbpcd_queue); | ||
5909 | for (j=0;j<NR_SBPCD;j++) | ||
5910 | { | ||
5911 | if (D_S[j].drv_id==-1) continue; | ||
5912 | del_gendisk(D_S[j].disk); | ||
5913 | put_disk(D_S[j].disk); | ||
5914 | devfs_remove("sbp/c0t%d", j); | ||
5915 | vfree(D_S[j].sbp_buf); | ||
5916 | if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf); | ||
5917 | if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL)) | ||
5918 | { | ||
5919 | msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name); | ||
5920 | return; | ||
5921 | } | ||
5922 | vfree(D_S[j].sbpcd_infop); | ||
5923 | } | ||
5924 | devfs_remove("sbp"); | ||
5925 | msg(DBG_INF, "%s module released.\n", major_name); | ||
5926 | } | ||
5927 | |||
5928 | |||
5929 | module_init(__sbpcd_init) /*HACK!*/; | ||
5930 | module_exit(sbpcd_exit); | ||
5931 | |||
5932 | |||
5933 | #endif /* MODULE */ | ||
5934 | static int sbpcd_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
5935 | { | ||
5936 | struct sbpcd_drive *p = cdi->handle; | ||
5937 | msg(DBG_CHK,"media_check (%s) called\n", cdi->name); | ||
5938 | |||
5939 | if (p->CD_changed==0xFF) | ||
5940 | { | ||
5941 | p->CD_changed=0; | ||
5942 | msg(DBG_CHK,"medium changed (drive %s)\n", cdi->name); | ||
5943 | current_drive->diskstate_flags &= ~toc_bit; | ||
5944 | /* we *don't* need invalidate here, it's done by caller */ | ||
5945 | current_drive->diskstate_flags &= ~cd_size_bit; | ||
5946 | #ifdef SAFE_MIXED | ||
5947 | current_drive->has_data=0; | ||
5948 | #endif /* SAFE_MIXED */ | ||
5949 | |||
5950 | return (1); | ||
5951 | } | ||
5952 | else | ||
5953 | return (0); | ||
5954 | } | ||
5955 | |||
5956 | MODULE_LICENSE("GPL"); | ||
5957 | /* FIXME: Old modules.conf claims MATSUSHITA_CDROM2_MAJOR and CDROM3, but | ||
5958 | AFAICT this doesn't support those majors, so why? --RR 30 Jul 2003 */ | ||
5959 | MODULE_ALIAS_BLOCKDEV_MAJOR(MATSUSHITA_CDROM_MAJOR); | ||
5960 | |||
5961 | /*==========================================================================*/ | ||
5962 | /* | ||
5963 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
5964 | * Emacs will notice this stuff at the end of the file and automatically | ||
5965 | * adjust the settings for this buffer only. This must remain at the end | ||
5966 | * of the file. | ||
5967 | * --------------------------------------------------------------------------- | ||
5968 | * Local variables: | ||
5969 | * c-indent-level: 8 | ||
5970 | * c-brace-imaginary-offset: 0 | ||
5971 | * c-brace-offset: -8 | ||
5972 | * c-argdecl-indent: 8 | ||
5973 | * c-label-offset: -8 | ||
5974 | * c-continued-statement-offset: 8 | ||
5975 | * c-continued-brace-offset: 0 | ||
5976 | * End: | ||
5977 | */ | ||
5978 | |||
diff --git a/drivers/cdrom/sbpcd.h b/drivers/cdrom/sbpcd.h new file mode 100644 index 000000000000..2f2225f13c6f --- /dev/null +++ b/drivers/cdrom/sbpcd.h | |||
@@ -0,0 +1,839 @@ | |||
1 | /* | ||
2 | * sbpcd.h Specify interface address and interface type here. | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * Attention! This file contains user-serviceable parts! | ||
7 | * I recommend to make use of it... | ||
8 | * If you feel helpless, look into Documentation/cdrom/sbpcd | ||
9 | * (good idea anyway, at least before mailing me). | ||
10 | * | ||
11 | * The definitions for the first controller can get overridden by | ||
12 | * the kernel command line ("lilo boot option"). | ||
13 | * Examples: | ||
14 | * sbpcd=0x300,LaserMate | ||
15 | * or | ||
16 | * sbpcd=0x230,SoundBlaster | ||
17 | * or | ||
18 | * sbpcd=0x338,SoundScape | ||
19 | * or | ||
20 | * sbpcd=0x2C0,Teac16bit | ||
21 | * | ||
22 | * If sbpcd gets used as a module, you can load it with | ||
23 | * insmod sbpcd.o sbpcd=0x300,0 | ||
24 | * or | ||
25 | * insmod sbpcd.o sbpcd=0x230,1 | ||
26 | * or | ||
27 | * insmod sbpcd.o sbpcd=0x338,2 | ||
28 | * or | ||
29 | * insmod sbpcd.o sbpcd=0x2C0,3 | ||
30 | * respective to override the configured address and type. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * define your CDROM port base address as CDROM_PORT | ||
35 | * and specify the type of your interface card as SBPRO. | ||
36 | * | ||
37 | * address: | ||
38 | * ======== | ||
39 | * SBPRO type addresses typically are 0x0230 (=0x220+0x10), 0x0250, ... | ||
40 | * LASERMATE type (CI-101P, WDH-7001C) addresses typically are 0x0300, ... | ||
41 | * SOUNDSCAPE addresses are from the LASERMATE type and range. You have to | ||
42 | * specify the REAL address here, not the configuration port address. Look | ||
43 | * at the CDROM driver's invoking line within your DOS CONFIG.SYS, or let | ||
44 | * sbpcd auto-probe, if you are not firm with the address. | ||
45 | * There are some soundcards on the market with 0x0630, 0x0650, ...; their | ||
46 | * type is not obvious (both types are possible). | ||
47 | * | ||
48 | * example: if your SBPRO audio address is 0x220, specify 0x230 and SBPRO 1. | ||
49 | * if your soundcard has its CDROM port above 0x300, specify | ||
50 | * that address and try SBPRO 0 first. | ||
51 | * if your SoundScape configuration port is at 0x330, specify | ||
52 | * 0x338 and SBPRO 2. | ||
53 | * | ||
54 | * interface type: | ||
55 | * =============== | ||
56 | * set SBPRO to 1 for "true" SoundBlaster card | ||
57 | * set SBPRO to 0 for "compatible" soundcards and | ||
58 | * for "poor" (no sound) interface cards. | ||
59 | * set SBPRO to 2 for Ensonic SoundScape or SPEA Media FX cards | ||
60 | * set SBPRO to 3 for Teac 16bit interface cards | ||
61 | * | ||
62 | * Almost all "compatible" sound boards need to set SBPRO to 0. | ||
63 | * If SBPRO is set wrong, the drives will get found - but any | ||
64 | * data access will give errors (audio access will work). | ||
65 | * The "OmniCD" no-sound interface card from CreativeLabs and most Teac | ||
66 | * interface cards need SBPRO 1. | ||
67 | * | ||
68 | * sound base: | ||
69 | * =========== | ||
70 | * The SOUND_BASE definition tells if we should try to turn the CD sound | ||
71 | * channels on. It will only be of use regarding soundcards with a SbPro | ||
72 | * compatible mixer. | ||
73 | * | ||
74 | * Example: #define SOUND_BASE 0x220 enables the sound card's CD channels | ||
75 | * #define SOUND_BASE 0 leaves the soundcard untouched | ||
76 | */ | ||
77 | #define CDROM_PORT 0x340 /* <-----------<< port address */ | ||
78 | #define SBPRO 0 /* <-----------<< interface type */ | ||
79 | #define MAX_DRIVES 4 /* set to 1 if the card does not use "drive select" */ | ||
80 | #define SOUND_BASE 0x220 /* <-----------<< sound address of this card or 0 */ | ||
81 | |||
82 | /* | ||
83 | * some more or less user dependent definitions - service them! | ||
84 | */ | ||
85 | |||
86 | /* Set this to 0 once you have configured your interface definitions right. */ | ||
87 | #define DISTRIBUTION 1 | ||
88 | |||
89 | /* | ||
90 | * Time to wait after giving a message. | ||
91 | * This gets important if you enable non-standard DBG_xxx flags. | ||
92 | * You will see what happens if you omit the pause or make it | ||
93 | * too short. Be warned! | ||
94 | */ | ||
95 | #define KLOGD_PAUSE 1 | ||
96 | |||
97 | /* tray control: eject tray if no disk is in */ | ||
98 | #if DISTRIBUTION | ||
99 | #define JUKEBOX 0 | ||
100 | #else | ||
101 | #define JUKEBOX 1 | ||
102 | #endif /* DISTRIBUTION */ | ||
103 | |||
104 | /* tray control: eject tray after last use */ | ||
105 | #if DISTRIBUTION | ||
106 | #define EJECT 0 | ||
107 | #else | ||
108 | #define EJECT 1 | ||
109 | #endif /* DISTRIBUTION */ | ||
110 | |||
111 | /* max. number of audio frames to read with one */ | ||
112 | /* request (allocates n* 2352 bytes kernel memory!) */ | ||
113 | /* may be freely adjusted, f.e. 75 (= 1 sec.), at */ | ||
114 | /* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ | ||
115 | #define READ_AUDIO 0 | ||
116 | |||
117 | /* Optimizations for the Teac CD-55A drive read performance. | ||
118 | * SBP_TEAC_SPEED can be changed here, or one can set the | ||
119 | * variable "teac" when loading as a module. | ||
120 | * Valid settings are: | ||
121 | * 0 - very slow - the recommended "DISTRIBUTION 1" setup. | ||
122 | * 1 - 2x performance with little overhead. No busy waiting. | ||
123 | * 2 - 4x performance with 5ms overhead per read. Busy wait. | ||
124 | * | ||
125 | * Setting SBP_TEAC_SPEED or the variable 'teac' to anything | ||
126 | * other than 0 may cause problems. If you run into them, first | ||
127 | * change SBP_TEAC_SPEED back to 0 and see if your drive responds | ||
128 | * normally. If yes, you are "allowed" to report your case - to help | ||
129 | * me with the driver, not to solve your hassle. Don´t mail if you | ||
130 | * simply are stuck into your own "tuning" experiments, you know? | ||
131 | */ | ||
132 | #define SBP_TEAC_SPEED 1 | ||
133 | |||
134 | /*==========================================================================*/ | ||
135 | /*==========================================================================*/ | ||
136 | /* | ||
137 | * nothing to change below here if you are not fully aware what you're doing | ||
138 | */ | ||
139 | #ifndef _LINUX_SBPCD_H | ||
140 | |||
141 | #define _LINUX_SBPCD_H | ||
142 | /*==========================================================================*/ | ||
143 | /*==========================================================================*/ | ||
144 | /* | ||
145 | * driver's own read_ahead, data mode | ||
146 | */ | ||
147 | #define SBP_BUFFER_FRAMES 8 | ||
148 | |||
149 | #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ | ||
150 | #undef FUTURE | ||
151 | #undef SAFE_MIXED | ||
152 | |||
153 | #define TEST_UPC 0 | ||
154 | #define SPEA_TEST 0 | ||
155 | #define TEST_STI 0 | ||
156 | #define OLD_BUSY 0 | ||
157 | #undef PATH_CHECK | ||
158 | #ifndef SOUND_BASE | ||
159 | #define SOUND_BASE 0 | ||
160 | #endif | ||
161 | #if DISTRIBUTION | ||
162 | #undef SBP_TEAC_SPEED | ||
163 | #define SBP_TEAC_SPEED 0 | ||
164 | #endif | ||
165 | /*==========================================================================*/ | ||
166 | /* | ||
167 | * DDI interface definitions | ||
168 | * "invented" by Fred N. van Kempen.. | ||
169 | */ | ||
170 | #define DDIOCSDBG 0x9000 | ||
171 | |||
172 | /*==========================================================================*/ | ||
173 | /* | ||
174 | * "private" IOCTL functions | ||
175 | */ | ||
176 | #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ | ||
177 | |||
178 | /*==========================================================================*/ | ||
179 | /* | ||
180 | * Debug output levels | ||
181 | */ | ||
182 | #define DBG_INF 1 /* necessary information */ | ||
183 | #define DBG_BSZ 2 /* BLOCK_SIZE trace */ | ||
184 | #define DBG_REA 3 /* READ status trace */ | ||
185 | #define DBG_CHK 4 /* MEDIA CHECK trace */ | ||
186 | #define DBG_TIM 5 /* datarate timer test */ | ||
187 | #define DBG_INI 6 /* initialization trace */ | ||
188 | #define DBG_TOC 7 /* tell TocEntry values */ | ||
189 | #define DBG_IOC 8 /* ioctl trace */ | ||
190 | #define DBG_STA 9 /* ResponseStatus() trace */ | ||
191 | #define DBG_ERR 10 /* cc_ReadError() trace */ | ||
192 | #define DBG_CMD 11 /* cmd_out() trace */ | ||
193 | #define DBG_WRN 12 /* give explanation before auto-probing */ | ||
194 | #define DBG_MUL 13 /* multi session code test */ | ||
195 | #define DBG_IDX 14 /* test code for drive_id !=0 */ | ||
196 | #define DBG_IOX 15 /* some special information */ | ||
197 | #define DBG_DID 16 /* drive ID test */ | ||
198 | #define DBG_RES 17 /* drive reset info */ | ||
199 | #define DBG_SPI 18 /* SpinUp test */ | ||
200 | #define DBG_IOS 19 /* ioctl trace: subchannel functions */ | ||
201 | #define DBG_IO2 20 /* ioctl trace: general */ | ||
202 | #define DBG_UPC 21 /* show UPC information */ | ||
203 | #define DBG_XA1 22 /* XA mode debugging */ | ||
204 | #define DBG_LCK 23 /* door (un)lock info */ | ||
205 | #define DBG_SQ1 24 /* dump SubQ frame */ | ||
206 | #define DBG_AUD 25 /* READ AUDIO debugging */ | ||
207 | #define DBG_SEQ 26 /* Sequoia interface configuration trace */ | ||
208 | #define DBG_LCS 27 /* Longshine LCS-7260 debugging trace */ | ||
209 | #define DBG_CD2 28 /* MKE/Funai CD200 debugging trace */ | ||
210 | #define DBG_TEA 29 /* TEAC CD-55A debugging trace */ | ||
211 | #define DBG_ECS 30 /* ECS-AT (Vertos 100) debugging trace */ | ||
212 | #define DBG_000 31 /* unnecessary information */ | ||
213 | |||
214 | /*==========================================================================*/ | ||
215 | /*==========================================================================*/ | ||
216 | |||
217 | /* | ||
218 | * bits of flags_cmd_out: | ||
219 | */ | ||
220 | #define f_respo3 0x100 | ||
221 | #define f_putcmd 0x80 | ||
222 | #define f_respo2 0x40 | ||
223 | #define f_lopsta 0x20 | ||
224 | #define f_getsta 0x10 | ||
225 | #define f_ResponseStatus 0x08 | ||
226 | #define f_obey_p_check 0x04 | ||
227 | #define f_bit1 0x02 | ||
228 | #define f_wait_if_busy 0x01 | ||
229 | |||
230 | /* | ||
231 | * diskstate_flags: | ||
232 | */ | ||
233 | #define x80_bit 0x80 | ||
234 | #define upc_bit 0x40 | ||
235 | #define volume_bit 0x20 | ||
236 | #define toc_bit 0x10 | ||
237 | #define multisession_bit 0x08 | ||
238 | #define cd_size_bit 0x04 | ||
239 | #define subq_bit 0x02 | ||
240 | #define frame_size_bit 0x01 | ||
241 | |||
242 | /* | ||
243 | * disk states (bits of diskstate_flags): | ||
244 | */ | ||
245 | #define upc_valid (current_drive->diskstate_flags&upc_bit) | ||
246 | #define volume_valid (current_drive->diskstate_flags&volume_bit) | ||
247 | #define toc_valid (current_drive->diskstate_flags&toc_bit) | ||
248 | #define cd_size_valid (current_drive->diskstate_flags&cd_size_bit) | ||
249 | #define subq_valid (current_drive->diskstate_flags&subq_bit) | ||
250 | #define frame_size_valid (current_drive->diskstate_flags&frame_size_bit) | ||
251 | |||
252 | /* | ||
253 | * the status_bits variable | ||
254 | */ | ||
255 | #define p_success 0x100 | ||
256 | #define p_door_closed 0x80 | ||
257 | #define p_caddy_in 0x40 | ||
258 | #define p_spinning 0x20 | ||
259 | #define p_check 0x10 | ||
260 | #define p_busy_new 0x08 | ||
261 | #define p_door_locked 0x04 | ||
262 | #define p_disk_ok 0x01 | ||
263 | |||
264 | /* | ||
265 | * LCS-7260 special status result bits: | ||
266 | */ | ||
267 | #define p_lcs_door_locked 0x02 | ||
268 | #define p_lcs_door_closed 0x01 /* probably disk_in */ | ||
269 | |||
270 | /* | ||
271 | * CR-52x special status result bits: | ||
272 | */ | ||
273 | #define p_caddin_old 0x40 | ||
274 | #define p_success_old 0x08 | ||
275 | #define p_busy_old 0x04 | ||
276 | #define p_bit_1 0x02 /* hopefully unused now */ | ||
277 | |||
278 | /* | ||
279 | * "generation specific" defs of the status result bits: | ||
280 | */ | ||
281 | #define p0_door_closed 0x80 | ||
282 | #define p0_caddy_in 0x40 | ||
283 | #define p0_spinning 0x20 | ||
284 | #define p0_check 0x10 | ||
285 | #define p0_success 0x08 /* unused */ | ||
286 | #define p0_busy 0x04 | ||
287 | #define p0_bit_1 0x02 /* unused */ | ||
288 | #define p0_disk_ok 0x01 | ||
289 | |||
290 | #define pL_disk_in 0x40 | ||
291 | #define pL_spinning 0x20 | ||
292 | #define pL_check 0x10 | ||
293 | #define pL_success 0x08 /* unused ?? */ | ||
294 | #define pL_busy 0x04 | ||
295 | #define pL_door_locked 0x02 | ||
296 | #define pL_door_closed 0x01 | ||
297 | |||
298 | #define pV_door_closed 0x40 | ||
299 | #define pV_spinning 0x20 | ||
300 | #define pV_check 0x10 | ||
301 | #define pV_success 0x08 | ||
302 | #define pV_busy 0x04 | ||
303 | #define pV_door_locked 0x02 | ||
304 | #define pV_disk_ok 0x01 | ||
305 | |||
306 | #define p1_door_closed 0x80 | ||
307 | #define p1_disk_in 0x40 | ||
308 | #define p1_spinning 0x20 | ||
309 | #define p1_check 0x10 | ||
310 | #define p1_busy 0x08 | ||
311 | #define p1_door_locked 0x04 | ||
312 | #define p1_bit_1 0x02 /* unused */ | ||
313 | #define p1_disk_ok 0x01 | ||
314 | |||
315 | #define p2_disk_ok 0x80 | ||
316 | #define p2_door_locked 0x40 | ||
317 | #define p2_spinning 0x20 | ||
318 | #define p2_busy2 0x10 | ||
319 | #define p2_busy1 0x08 | ||
320 | #define p2_door_closed 0x04 | ||
321 | #define p2_disk_in 0x02 | ||
322 | #define p2_check 0x01 | ||
323 | |||
324 | /* | ||
325 | * used drive states: | ||
326 | */ | ||
327 | #define st_door_closed (current_drive->status_bits&p_door_closed) | ||
328 | #define st_caddy_in (current_drive->status_bits&p_caddy_in) | ||
329 | #define st_spinning (current_drive->status_bits&p_spinning) | ||
330 | #define st_check (current_drive->status_bits&p_check) | ||
331 | #define st_busy (current_drive->status_bits&p_busy_new) | ||
332 | #define st_door_locked (current_drive->status_bits&p_door_locked) | ||
333 | #define st_diskok (current_drive->status_bits&p_disk_ok) | ||
334 | |||
335 | /* | ||
336 | * bits of the CDi_status register: | ||
337 | */ | ||
338 | #define s_not_result_ready 0x04 /* 0: "result ready" */ | ||
339 | #define s_not_data_ready 0x02 /* 0: "data ready" */ | ||
340 | #define s_attention 0x01 /* 1: "attention required" */ | ||
341 | /* | ||
342 | * usable as: | ||
343 | */ | ||
344 | #define DRV_ATTN ((inb(CDi_status)&s_attention)!=0) | ||
345 | #define DATA_READY ((inb(CDi_status)&s_not_data_ready)==0) | ||
346 | #define RESULT_READY ((inb(CDi_status)&s_not_result_ready)==0) | ||
347 | |||
348 | /* | ||
349 | * drive families and types (firmware versions): | ||
350 | */ | ||
351 | #define drv_fam0 0x0100 /* CR-52x family */ | ||
352 | #define drv_199 (drv_fam0+0x01) /* <200 */ | ||
353 | #define drv_200 (drv_fam0+0x02) /* <201 */ | ||
354 | #define drv_201 (drv_fam0+0x03) /* <210 */ | ||
355 | #define drv_210 (drv_fam0+0x04) /* <211 */ | ||
356 | #define drv_211 (drv_fam0+0x05) /* <300 */ | ||
357 | #define drv_300 (drv_fam0+0x06) /* >=300 */ | ||
358 | |||
359 | #define drv_fam1 0x0200 /* CR-56x family */ | ||
360 | #define drv_099 (drv_fam1+0x01) /* <100 */ | ||
361 | #define drv_100 (drv_fam1+0x02) /* >=100, only 1.02 and 5.00 known */ | ||
362 | |||
363 | #define drv_fam2 0x0400 /* CD200 family */ | ||
364 | |||
365 | #define drv_famT 0x0800 /* TEAC CD-55A */ | ||
366 | |||
367 | #define drv_famL 0x1000 /* Longshine family */ | ||
368 | #define drv_260 (drv_famL+0x01) /* LCS-7260 */ | ||
369 | #define drv_e1 (drv_famL+0x01) /* LCS-7260, firmware "A E1" */ | ||
370 | #define drv_f4 (drv_famL+0x02) /* LCS-7260, firmware "A4F4" */ | ||
371 | |||
372 | #define drv_famV 0x2000 /* ECS-AT (vertos-100) family */ | ||
373 | #define drv_at (drv_famV+0x01) /* ECS-AT, firmware "1.00" */ | ||
374 | |||
375 | #define fam0_drive (current_drive->drv_type&drv_fam0) | ||
376 | #define famL_drive (current_drive->drv_type&drv_famL) | ||
377 | #define famV_drive (current_drive->drv_type&drv_famV) | ||
378 | #define fam1_drive (current_drive->drv_type&drv_fam1) | ||
379 | #define fam2_drive (current_drive->drv_type&drv_fam2) | ||
380 | #define famT_drive (current_drive->drv_type&drv_famT) | ||
381 | #define fam0L_drive (current_drive->drv_type&(drv_fam0|drv_famL)) | ||
382 | #define fam0V_drive (current_drive->drv_type&(drv_fam0|drv_famV)) | ||
383 | #define famLV_drive (current_drive->drv_type&(drv_famL|drv_famV)) | ||
384 | #define fam0LV_drive (current_drive->drv_type&(drv_fam0|drv_famL|drv_famV)) | ||
385 | #define fam1L_drive (current_drive->drv_type&(drv_fam1|drv_famL)) | ||
386 | #define fam1V_drive (current_drive->drv_type&(drv_fam1|drv_famV)) | ||
387 | #define fam1LV_drive (current_drive->drv_type&(drv_fam1|drv_famL|drv_famV)) | ||
388 | #define fam01_drive (current_drive->drv_type&(drv_fam0|drv_fam1)) | ||
389 | #define fam12_drive (current_drive->drv_type&(drv_fam1|drv_fam2)) | ||
390 | #define fam2T_drive (current_drive->drv_type&(drv_fam2|drv_famT)) | ||
391 | |||
392 | /* | ||
393 | * audio states: | ||
394 | */ | ||
395 | #define audio_completed 3 /* Forgot this one! --AJK */ | ||
396 | #define audio_playing 2 | ||
397 | #define audio_pausing 1 | ||
398 | |||
399 | /* | ||
400 | * drv_pattern, drv_options: | ||
401 | */ | ||
402 | #define speed_auto 0x80 | ||
403 | #define speed_300 0x40 | ||
404 | #define speed_150 0x20 | ||
405 | #define audio_mono 0x04 | ||
406 | |||
407 | /* | ||
408 | * values of cmd_type (0 else): | ||
409 | */ | ||
410 | #define READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */ | ||
411 | #define READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */ | ||
412 | #define READ_SC 0x04 /* "subchannel info": 96 bytes per frame */ | ||
413 | #define READ_AU 0x08 /* "audio frame": 2352 bytes per frame */ | ||
414 | |||
415 | /* | ||
416 | * sense_byte: | ||
417 | * | ||
418 | * values: 00 | ||
419 | * 01 | ||
420 | * 81 | ||
421 | * 82 "raw audio" mode | ||
422 | * xx from infobuf[0] after 85 00 00 00 00 00 00 | ||
423 | */ | ||
424 | |||
425 | /* audio status (bin) */ | ||
426 | #define aud_00 0x00 /* Audio status byte not supported or not valid */ | ||
427 | #define audx11 0x0b /* Audio play operation in progress */ | ||
428 | #define audx12 0x0c /* Audio play operation paused */ | ||
429 | #define audx13 0x0d /* Audio play operation successfully completed */ | ||
430 | #define audx14 0x0e /* Audio play operation stopped due to error */ | ||
431 | #define audx15 0x0f /* No current audio status to return */ | ||
432 | /* audio status (bcd) */ | ||
433 | #define aud_11 0x11 /* Audio play operation in progress */ | ||
434 | #define aud_12 0x12 /* Audio play operation paused */ | ||
435 | #define aud_13 0x13 /* Audio play operation successfully completed */ | ||
436 | #define aud_14 0x14 /* Audio play operation stopped due to error */ | ||
437 | #define aud_15 0x15 /* No current audio status to return */ | ||
438 | |||
439 | /* | ||
440 | * highest allowed drive number (MINOR+1) | ||
441 | */ | ||
442 | #define NR_SBPCD 4 | ||
443 | |||
444 | /* | ||
445 | * we try to never disable interrupts - seems to work | ||
446 | */ | ||
447 | #define SBPCD_DIS_IRQ 0 | ||
448 | |||
449 | /* | ||
450 | * "write byte to port" | ||
451 | */ | ||
452 | #define OUT(x,y) outb(y,x) | ||
453 | |||
454 | /*==========================================================================*/ | ||
455 | |||
456 | #define MIXER_addr SOUND_BASE+4 /* sound card's address register */ | ||
457 | #define MIXER_data SOUND_BASE+5 /* sound card's data register */ | ||
458 | #define MIXER_CD_Volume 0x28 /* internal SB Pro register address */ | ||
459 | |||
460 | /*==========================================================================*/ | ||
461 | |||
462 | #define MAX_TRACKS 99 | ||
463 | |||
464 | #define ERR_DISKCHANGE 615 | ||
465 | |||
466 | /*==========================================================================*/ | ||
467 | /* | ||
468 | * To make conversions easier (machine dependent!) | ||
469 | */ | ||
470 | typedef union _msf | ||
471 | { | ||
472 | u_int n; | ||
473 | u_char c[4]; | ||
474 | } MSF; | ||
475 | |||
476 | typedef union _blk | ||
477 | { | ||
478 | u_int n; | ||
479 | u_char c[4]; | ||
480 | } BLK; | ||
481 | |||
482 | /*==========================================================================*/ | ||
483 | |||
484 | /*============================================================================ | ||
485 | ============================================================================== | ||
486 | |||
487 | COMMAND SET of "old" drives like CR-521, CR-522 | ||
488 | (the CR-562 family is different): | ||
489 | |||
490 | No. Command Code | ||
491 | -------------------------------------------- | ||
492 | |||
493 | Drive Commands: | ||
494 | 1 Seek 01 | ||
495 | 2 Read Data 02 | ||
496 | 3 Read XA-Data 03 | ||
497 | 4 Read Header 04 | ||
498 | 5 Spin Up 05 | ||
499 | 6 Spin Down 06 | ||
500 | 7 Diagnostic 07 | ||
501 | 8 Read UPC 08 | ||
502 | 9 Read ISRC 09 | ||
503 | 10 Play Audio 0A | ||
504 | 11 Play Audio MSF 0B | ||
505 | 12 Play Audio Track/Index 0C | ||
506 | |||
507 | Status Commands: | ||
508 | 13 Read Status 81 | ||
509 | 14 Read Error 82 | ||
510 | 15 Read Drive Version 83 | ||
511 | 16 Mode Select 84 | ||
512 | 17 Mode Sense 85 | ||
513 | 18 Set XA Parameter 86 | ||
514 | 19 Read XA Parameter 87 | ||
515 | 20 Read Capacity 88 | ||
516 | 21 Read SUB_Q 89 | ||
517 | 22 Read Disc Code 8A | ||
518 | 23 Read Disc Information 8B | ||
519 | 24 Read TOC 8C | ||
520 | 25 Pause/Resume 8D | ||
521 | 26 Read Packet 8E | ||
522 | 27 Read Path Check 00 | ||
523 | |||
524 | |||
525 | all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first | ||
526 | |||
527 | mnemo 7-byte command #bytes response (r0...rn) | ||
528 | ________ ____________________ ____ | ||
529 | |||
530 | Read Status: | ||
531 | status: 81. (1) one-byte command, gives the main | ||
532 | status byte | ||
533 | Read Error: | ||
534 | check1: 82 00 00 00 00 00 00. (6) r1: audio status | ||
535 | |||
536 | Read Packet: | ||
537 | check2: 8e xx 00 00 00 00 00. (xx) gets xx bytes response, relating | ||
538 | to commands 01 04 05 07 08 09 | ||
539 | |||
540 | Play Audio: | ||
541 | play: 0a ll-bb-aa nn-nn-nn. (0) play audio, ll-bb-aa: starting block (lba), | ||
542 | nn-nn-nn: #blocks | ||
543 | Play Audio MSF: | ||
544 | 0b mm-ss-ff mm-ss-ff (0) play audio from/to | ||
545 | |||
546 | Play Audio Track/Index: | ||
547 | 0c ... | ||
548 | |||
549 | Pause/Resume: | ||
550 | pause: 8d pr 00 00 00 00 00. (0) pause (pr=00) | ||
551 | resume (pr=80) audio playing | ||
552 | |||
553 | Mode Select: | ||
554 | 84 00 nn-nn ??.?? 00 (0) nn-nn: 2048 or 2340 | ||
555 | possibly defines transfer size | ||
556 | |||
557 | set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1) | ||
558 | le(vel): min=0, max=FF, else half | ||
559 | (firmware 2.11) | ||
560 | |||
561 | Mode Sense: | ||
562 | get_vol: 85 03 00 00 00 00 00. (2) tell current audio volume setting | ||
563 | |||
564 | Read Disc Information: | ||
565 | tocdesc: 8b 00 00 00 00 00 00. (6) read the toc descriptor ("msf-bin"-format) | ||
566 | |||
567 | Read TOC: | ||
568 | tocent: 8c fl nn 00 00 00 00. (8) read toc entry #nn | ||
569 | (fl=0:"lba"-, =2:"msf-bin"-format) | ||
570 | |||
571 | Read Capacity: | ||
572 | capacit: 88 00 00 00 00 00 00. (5) "read CD-ROM capacity" | ||
573 | |||
574 | |||
575 | Read Path Check: | ||
576 | ping: 00 00 00 00 00 00 00. (2) r0=AA, r1=55 | ||
577 | ("ping" if the drive is connected) | ||
578 | |||
579 | Read Drive Version: | ||
580 | ident: 83 00 00 00 00 00 00. (12) gives "MATSHITAn.nn" | ||
581 | (n.nn = 2.01, 2.11., 3.00, ...) | ||
582 | |||
583 | Seek: | ||
584 | seek: 01 00 ll-bb-aa 00 00. (0) | ||
585 | seek: 01 02 mm-ss-ff 00 00. (0) | ||
586 | |||
587 | Read Data: | ||
588 | read: 02 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2048 bytes, | ||
589 | starting at block xx-xx-xx | ||
590 | fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx | ||
591 | |||
592 | Read XA-Data: | ||
593 | read: 03 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2340 bytes, | ||
594 | starting at block xx-xx-xx | ||
595 | fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx | ||
596 | |||
597 | Read SUB_Q: | ||
598 | 89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf, | ||
599 | fl=0: "lba", fl=2: "msf" | ||
600 | |||
601 | Read Disc Code: | ||
602 | 8a 00 00 00 00 00 00. (14) possibly extended "check condition"-info | ||
603 | |||
604 | Read Header: | ||
605 | 04 00 ll-bb-aa 00 00. (0) 4 bytes response with "check2" | ||
606 | 04 02 mm-ss-ff 00 00. (0) 4 bytes response with "check2" | ||
607 | |||
608 | Spin Up: | ||
609 | 05 00 ll-bb-aa 00 00. (0) possibly implies a "seek" | ||
610 | |||
611 | Spin Down: | ||
612 | 06 ... | ||
613 | |||
614 | Diagnostic: | ||
615 | 07 00 ll-bb-aa 00 00. (2) 2 bytes response with "check2" | ||
616 | 07 02 mm-ss-ff 00 00. (2) 2 bytes response with "check2" | ||
617 | |||
618 | Read UPC: | ||
619 | 08 00 ll-bb-aa 00 00. (16) | ||
620 | 08 02 mm-ss-ff 00 00. (16) | ||
621 | |||
622 | Read ISRC: | ||
623 | 09 00 ll-bb-aa 00 00. (15) 15 bytes response with "check2" | ||
624 | 09 02 mm-ss-ff 00 00. (15) 15 bytes response with "check2" | ||
625 | |||
626 | Set XA Parameter: | ||
627 | 86 ... | ||
628 | |||
629 | Read XA Parameter: | ||
630 | 87 ... | ||
631 | |||
632 | ============================================================================== | ||
633 | ============================================================================*/ | ||
634 | |||
635 | /* | ||
636 | * commands | ||
637 | * | ||
638 | * CR-52x: CMD0_ | ||
639 | * CR-56x: CMD1_ | ||
640 | * CD200: CMD2_ | ||
641 | * LCS-7260: CMDL_ | ||
642 | * TEAC CD-55A: CMDT_ | ||
643 | * ECS-AT: CMDV_ | ||
644 | */ | ||
645 | #define CMD1_RESET 0x0a | ||
646 | #define CMD2_RESET 0x01 | ||
647 | #define CMDT_RESET 0xc0 | ||
648 | |||
649 | #define CMD1_LOCK_CTL 0x0c | ||
650 | #define CMD2_LOCK_CTL 0x1e | ||
651 | #define CMDT_LOCK_CTL CMD2_LOCK_CTL | ||
652 | #define CMDL_LOCK_CTL 0x0e | ||
653 | #define CMDV_LOCK_CTL CMDL_LOCK_CTL | ||
654 | |||
655 | #define CMD1_TRAY_CTL 0x07 | ||
656 | #define CMD2_TRAY_CTL 0x1b | ||
657 | #define CMDT_TRAY_CTL CMD2_TRAY_CTL | ||
658 | #define CMDL_TRAY_CTL 0x0d | ||
659 | #define CMDV_TRAY_CTL CMDL_TRAY_CTL | ||
660 | |||
661 | #define CMD1_MULTISESS 0x8d | ||
662 | #define CMDL_MULTISESS 0x8c | ||
663 | #define CMDV_MULTISESS CMDL_MULTISESS | ||
664 | |||
665 | #define CMD1_SUBCHANINF 0x11 | ||
666 | #define CMD2_SUBCHANINF 0x?? | ||
667 | |||
668 | #define CMD1_ABORT 0x08 | ||
669 | #define CMD2_ABORT 0x08 | ||
670 | #define CMDT_ABORT 0x08 | ||
671 | |||
672 | #define CMD2_x02 0x02 | ||
673 | |||
674 | #define CMD2_SETSPEED 0xda | ||
675 | |||
676 | #define CMD0_PATH_CHECK 0x00 | ||
677 | #define CMD1_PATH_CHECK 0x??? | ||
678 | #define CMD2_PATH_CHECK 0x??? | ||
679 | #define CMDT_PATH_CHECK 0x??? | ||
680 | #define CMDL_PATH_CHECK CMD0_PATH_CHECK | ||
681 | #define CMDV_PATH_CHECK CMD0_PATH_CHECK | ||
682 | |||
683 | #define CMD0_SEEK 0x01 | ||
684 | #define CMD1_SEEK CMD0_SEEK | ||
685 | #define CMD2_SEEK 0x2b | ||
686 | #define CMDT_SEEK CMD2_SEEK | ||
687 | #define CMDL_SEEK CMD0_SEEK | ||
688 | #define CMDV_SEEK CMD0_SEEK | ||
689 | |||
690 | #define CMD0_READ 0x02 | ||
691 | #define CMD1_READ 0x10 | ||
692 | #define CMD2_READ 0x28 | ||
693 | #define CMDT_READ CMD2_READ | ||
694 | #define CMDL_READ CMD0_READ | ||
695 | #define CMDV_READ CMD0_READ | ||
696 | |||
697 | #define CMD0_READ_XA 0x03 | ||
698 | #define CMD2_READ_XA 0xd4 | ||
699 | #define CMD2_READ_XA2 0xd5 | ||
700 | #define CMDL_READ_XA CMD0_READ_XA /* really ?? */ | ||
701 | #define CMDV_READ_XA CMD0_READ_XA | ||
702 | |||
703 | #define CMD0_READ_HEAD 0x04 | ||
704 | |||
705 | #define CMD0_SPINUP 0x05 | ||
706 | #define CMD1_SPINUP 0x02 | ||
707 | #define CMD2_SPINUP CMD2_TRAY_CTL | ||
708 | #define CMDL_SPINUP CMD0_SPINUP | ||
709 | #define CMDV_SPINUP CMD0_SPINUP | ||
710 | |||
711 | #define CMD0_SPINDOWN 0x06 /* really??? */ | ||
712 | #define CMD1_SPINDOWN 0x06 | ||
713 | #define CMD2_SPINDOWN CMD2_TRAY_CTL | ||
714 | #define CMDL_SPINDOWN 0x0d | ||
715 | #define CMDV_SPINDOWN CMD0_SPINDOWN | ||
716 | |||
717 | #define CMD0_DIAG 0x07 | ||
718 | |||
719 | #define CMD0_READ_UPC 0x08 | ||
720 | #define CMD1_READ_UPC 0x88 | ||
721 | #define CMD2_READ_UPC 0x??? | ||
722 | #define CMDL_READ_UPC CMD0_READ_UPC | ||
723 | #define CMDV_READ_UPC 0x8f | ||
724 | |||
725 | #define CMD0_READ_ISRC 0x09 | ||
726 | |||
727 | #define CMD0_PLAY 0x0a | ||
728 | #define CMD1_PLAY 0x??? | ||
729 | #define CMD2_PLAY 0x??? | ||
730 | #define CMDL_PLAY CMD0_PLAY | ||
731 | #define CMDV_PLAY CMD0_PLAY | ||
732 | |||
733 | #define CMD0_PLAY_MSF 0x0b | ||
734 | #define CMD1_PLAY_MSF 0x0e | ||
735 | #define CMD2_PLAY_MSF 0x47 | ||
736 | #define CMDT_PLAY_MSF CMD2_PLAY_MSF | ||
737 | #define CMDL_PLAY_MSF 0x??? | ||
738 | |||
739 | #define CMD0_PLAY_TI 0x0c | ||
740 | #define CMD1_PLAY_TI 0x0f | ||
741 | |||
742 | #define CMD0_STATUS 0x81 | ||
743 | #define CMD1_STATUS 0x05 | ||
744 | #define CMD2_STATUS 0x00 | ||
745 | #define CMDT_STATUS CMD2_STATUS | ||
746 | #define CMDL_STATUS CMD0_STATUS | ||
747 | #define CMDV_STATUS CMD0_STATUS | ||
748 | #define CMD2_SEEK_LEADIN 0x00 | ||
749 | |||
750 | #define CMD0_READ_ERR 0x82 | ||
751 | #define CMD1_READ_ERR CMD0_READ_ERR | ||
752 | #define CMD2_READ_ERR 0x03 | ||
753 | #define CMDT_READ_ERR CMD2_READ_ERR /* get audio status */ | ||
754 | #define CMDL_READ_ERR CMD0_READ_ERR | ||
755 | #define CMDV_READ_ERR CMD0_READ_ERR | ||
756 | |||
757 | #define CMD0_READ_VER 0x83 | ||
758 | #define CMD1_READ_VER CMD0_READ_VER | ||
759 | #define CMD2_READ_VER 0x12 | ||
760 | #define CMDT_READ_VER CMD2_READ_VER /* really ?? */ | ||
761 | #define CMDL_READ_VER CMD0_READ_VER | ||
762 | #define CMDV_READ_VER CMD0_READ_VER | ||
763 | |||
764 | #define CMD0_SETMODE 0x84 | ||
765 | #define CMD1_SETMODE 0x09 | ||
766 | #define CMD2_SETMODE 0x55 | ||
767 | #define CMDT_SETMODE CMD2_SETMODE | ||
768 | #define CMDL_SETMODE CMD0_SETMODE | ||
769 | |||
770 | #define CMD0_GETMODE 0x85 | ||
771 | #define CMD1_GETMODE 0x84 | ||
772 | #define CMD2_GETMODE 0x5a | ||
773 | #define CMDT_GETMODE CMD2_GETMODE | ||
774 | #define CMDL_GETMODE CMD0_GETMODE | ||
775 | |||
776 | #define CMD0_SET_XA 0x86 | ||
777 | |||
778 | #define CMD0_GET_XA 0x87 | ||
779 | |||
780 | #define CMD0_CAPACITY 0x88 | ||
781 | #define CMD1_CAPACITY 0x85 | ||
782 | #define CMD2_CAPACITY 0x25 | ||
783 | #define CMDL_CAPACITY CMD0_CAPACITY /* missing in some firmware versions */ | ||
784 | |||
785 | #define CMD0_READSUBQ 0x89 | ||
786 | #define CMD1_READSUBQ 0x87 | ||
787 | #define CMD2_READSUBQ 0x42 | ||
788 | #define CMDT_READSUBQ CMD2_READSUBQ | ||
789 | #define CMDL_READSUBQ CMD0_READSUBQ | ||
790 | #define CMDV_READSUBQ CMD0_READSUBQ | ||
791 | |||
792 | #define CMD0_DISKCODE 0x8a | ||
793 | |||
794 | #define CMD0_DISKINFO 0x8b | ||
795 | #define CMD1_DISKINFO CMD0_DISKINFO | ||
796 | #define CMD2_DISKINFO 0x43 | ||
797 | #define CMDT_DISKINFO CMD2_DISKINFO | ||
798 | #define CMDL_DISKINFO CMD0_DISKINFO | ||
799 | #define CMDV_DISKINFO CMD0_DISKINFO | ||
800 | |||
801 | #define CMD0_READTOC 0x8c | ||
802 | #define CMD1_READTOC CMD0_READTOC | ||
803 | #define CMD2_READTOC 0x??? | ||
804 | #define CMDL_READTOC CMD0_READTOC | ||
805 | #define CMDV_READTOC CMD0_READTOC | ||
806 | |||
807 | #define CMD0_PAU_RES 0x8d | ||
808 | #define CMD1_PAU_RES 0x0d | ||
809 | #define CMD2_PAU_RES 0x4b | ||
810 | #define CMDT_PAUSE CMD2_PAU_RES | ||
811 | #define CMDL_PAU_RES CMD0_PAU_RES | ||
812 | #define CMDV_PAUSE CMD0_PAU_RES | ||
813 | |||
814 | #define CMD0_PACKET 0x8e | ||
815 | #define CMD1_PACKET CMD0_PACKET | ||
816 | #define CMD2_PACKET 0x??? | ||
817 | #define CMDL_PACKET CMD0_PACKET | ||
818 | #define CMDV_PACKET 0x??? | ||
819 | |||
820 | /*==========================================================================*/ | ||
821 | /*==========================================================================*/ | ||
822 | #endif /* _LINUX_SBPCD_H */ | ||
823 | /*==========================================================================*/ | ||
824 | /* | ||
825 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
826 | * Emacs will notice this stuff at the end of the file and automatically | ||
827 | * adjust the settings for this buffer only. This must remain at the end | ||
828 | * of the file. | ||
829 | * --------------------------------------------------------------------------- | ||
830 | * Local variables: | ||
831 | * c-indent-level: 8 | ||
832 | * c-brace-imaginary-offset: 0 | ||
833 | * c-brace-offset: -8 | ||
834 | * c-argdecl-indent: 8 | ||
835 | * c-label-offset: -8 | ||
836 | * c-continued-statement-offset: 8 | ||
837 | * c-continued-brace-offset: 0 | ||
838 | * End: | ||
839 | */ | ||
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c new file mode 100644 index 000000000000..4e7a342ec36f --- /dev/null +++ b/drivers/cdrom/sjcd.c | |||
@@ -0,0 +1,1817 @@ | |||
1 | /* -- sjcd.c | ||
2 | * | ||
3 | * Sanyo CD-ROM device driver implementation, Version 1.6 | ||
4 | * Copyright (C) 1995 Vadim V. Model | ||
5 | * | ||
6 | * model@cecmow.enet.dec.com | ||
7 | * vadim@rbrf.ru | ||
8 | * vadim@ipsun.ras.ru | ||
9 | * | ||
10 | * | ||
11 | * This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de); | ||
12 | * it was developed under use of mcd.c from Martin Harriss, with help of | ||
13 | * Eric van der Maarel (H.T.M.v.d.Maarel@marin.nl). | ||
14 | * | ||
15 | * It is planned to include these routines into sbpcd.c later - to make | ||
16 | * a "mixed use" on one cable possible for all kinds of drives which use | ||
17 | * the SoundBlaster/Panasonic style CDROM interface. But today, the | ||
18 | * ability to install directly from CDROM is more important than flexibility. | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2 of the License, or | ||
23 | * (at your option) any later version. | ||
24 | * | ||
25 | * This program is distributed in the hope that it will be useful, | ||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | * GNU General Public License for more details. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License | ||
31 | * along with this program; if not, write to the Free Software | ||
32 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
33 | * | ||
34 | * History: | ||
35 | * 1.1 First public release with kernel version 1.3.7. | ||
36 | * Written by Vadim Model. | ||
37 | * 1.2 Added detection and configuration of cdrom interface | ||
38 | * on ISP16 soundcard. | ||
39 | * Allow for command line options: sjcd=<io_base>,<irq>,<dma> | ||
40 | * 1.3 Some minor changes to README.sjcd. | ||
41 | * 1.4 MSS Sound support!! Listen to a CD through the speakers. | ||
42 | * 1.5 Module support and bugfixes. | ||
43 | * Tray locking. | ||
44 | * 1.6 Removed ISP16 code from this driver. | ||
45 | * Allow only to set io base address on command line: sjcd=<io_base> | ||
46 | * Changes to Documentation/cdrom/sjcd | ||
47 | * Added cleanup after any error in the initialisation. | ||
48 | * 1.7 Added code to set the sector size tables to prevent the bug present in | ||
49 | * the previous version of this driver. Coded added by Anthony Barbachan | ||
50 | * from bugfix tip originally suggested by Alan Cox. | ||
51 | * | ||
52 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
53 | * Removed init_module & cleanup_module in favor of | ||
54 | * module_init & module_exit. | ||
55 | * Torben Mathiasen <tmm@image.dk> | ||
56 | */ | ||
57 | |||
58 | #define SJCD_VERSION_MAJOR 1 | ||
59 | #define SJCD_VERSION_MINOR 7 | ||
60 | |||
61 | #include <linux/module.h> | ||
62 | #include <linux/errno.h> | ||
63 | #include <linux/sched.h> | ||
64 | #include <linux/mm.h> | ||
65 | #include <linux/timer.h> | ||
66 | #include <linux/fs.h> | ||
67 | #include <linux/kernel.h> | ||
68 | #include <linux/cdrom.h> | ||
69 | #include <linux/ioport.h> | ||
70 | #include <linux/string.h> | ||
71 | #include <linux/major.h> | ||
72 | #include <linux/init.h> | ||
73 | |||
74 | #include <asm/system.h> | ||
75 | #include <asm/io.h> | ||
76 | #include <asm/uaccess.h> | ||
77 | #include <linux/blkdev.h> | ||
78 | #include "sjcd.h" | ||
79 | |||
80 | static int sjcd_present = 0; | ||
81 | static struct request_queue *sjcd_queue; | ||
82 | |||
83 | #define MAJOR_NR SANYO_CDROM_MAJOR | ||
84 | #define QUEUE (sjcd_queue) | ||
85 | #define CURRENT elv_next_request(sjcd_queue) | ||
86 | |||
87 | #define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */ | ||
88 | |||
89 | /* | ||
90 | * buffer for block size conversion | ||
91 | */ | ||
92 | static char sjcd_buf[2048 * SJCD_BUF_SIZ]; | ||
93 | static volatile int sjcd_buf_bn[SJCD_BUF_SIZ], sjcd_next_bn; | ||
94 | static volatile int sjcd_buf_in, sjcd_buf_out = -1; | ||
95 | |||
96 | /* | ||
97 | * Status. | ||
98 | */ | ||
99 | static unsigned short sjcd_status_valid = 0; | ||
100 | static unsigned short sjcd_door_closed; | ||
101 | static unsigned short sjcd_door_was_open; | ||
102 | static unsigned short sjcd_media_is_available; | ||
103 | static unsigned short sjcd_media_is_changed; | ||
104 | static unsigned short sjcd_toc_uptodate = 0; | ||
105 | static unsigned short sjcd_command_failed; | ||
106 | static volatile unsigned char sjcd_completion_status = 0; | ||
107 | static volatile unsigned char sjcd_completion_error = 0; | ||
108 | static unsigned short sjcd_command_is_in_progress = 0; | ||
109 | static unsigned short sjcd_error_reported = 0; | ||
110 | static DEFINE_SPINLOCK(sjcd_lock); | ||
111 | |||
112 | static int sjcd_open_count; | ||
113 | |||
114 | static int sjcd_audio_status; | ||
115 | static struct sjcd_play_msf sjcd_playing; | ||
116 | |||
117 | static int sjcd_base = SJCD_BASE_ADDR; | ||
118 | |||
119 | module_param(sjcd_base, int, 0); | ||
120 | |||
121 | static DECLARE_WAIT_QUEUE_HEAD(sjcd_waitq); | ||
122 | |||
123 | /* | ||
124 | * Data transfer. | ||
125 | */ | ||
126 | static volatile unsigned short sjcd_transfer_is_active = 0; | ||
127 | |||
128 | enum sjcd_transfer_state { | ||
129 | SJCD_S_IDLE = 0, | ||
130 | SJCD_S_START = 1, | ||
131 | SJCD_S_MODE = 2, | ||
132 | SJCD_S_READ = 3, | ||
133 | SJCD_S_DATA = 4, | ||
134 | SJCD_S_STOP = 5, | ||
135 | SJCD_S_STOPPING = 6 | ||
136 | }; | ||
137 | static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE; | ||
138 | static long sjcd_transfer_timeout = 0; | ||
139 | static int sjcd_read_count = 0; | ||
140 | static unsigned char sjcd_mode = 0; | ||
141 | |||
142 | #define SJCD_READ_TIMEOUT 5000 | ||
143 | |||
144 | #if defined( SJCD_GATHER_STAT ) | ||
145 | /* | ||
146 | * Statistic. | ||
147 | */ | ||
148 | static struct sjcd_stat statistic; | ||
149 | #endif | ||
150 | |||
151 | /* | ||
152 | * Timer. | ||
153 | */ | ||
154 | static struct timer_list sjcd_delay_timer = TIMER_INITIALIZER(NULL, 0, 0); | ||
155 | |||
156 | #define SJCD_SET_TIMER( func, tmout ) \ | ||
157 | ( sjcd_delay_timer.expires = jiffies+tmout, \ | ||
158 | sjcd_delay_timer.function = ( void * )func, \ | ||
159 | add_timer( &sjcd_delay_timer ) ) | ||
160 | |||
161 | #define CLEAR_TIMER del_timer( &sjcd_delay_timer ) | ||
162 | |||
163 | /* | ||
164 | * Set up device, i.e., use command line data to set | ||
165 | * base address. | ||
166 | */ | ||
167 | #ifndef MODULE | ||
168 | static int __init sjcd_setup(char *str) | ||
169 | { | ||
170 | int ints[2]; | ||
171 | (void) get_options(str, ARRAY_SIZE(ints), ints); | ||
172 | if (ints[0] > 0) | ||
173 | sjcd_base = ints[1]; | ||
174 | |||
175 | return 1; | ||
176 | } | ||
177 | |||
178 | __setup("sjcd=", sjcd_setup); | ||
179 | |||
180 | #endif | ||
181 | |||
182 | /* | ||
183 | * Special converters. | ||
184 | */ | ||
185 | static unsigned char bin2bcd(int bin) | ||
186 | { | ||
187 | int u, v; | ||
188 | |||
189 | u = bin % 10; | ||
190 | v = bin / 10; | ||
191 | return (u | (v << 4)); | ||
192 | } | ||
193 | |||
194 | static int bcd2bin(unsigned char bcd) | ||
195 | { | ||
196 | return ((bcd >> 4) * 10 + (bcd & 0x0F)); | ||
197 | } | ||
198 | |||
199 | static long msf2hsg(struct msf *mp) | ||
200 | { | ||
201 | return (bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 | ||
202 | + bcd2bin(mp->min) * 4500 - 150); | ||
203 | } | ||
204 | |||
205 | static void hsg2msf(long hsg, struct msf *msf) | ||
206 | { | ||
207 | hsg += 150; | ||
208 | msf->min = hsg / 4500; | ||
209 | hsg %= 4500; | ||
210 | msf->sec = hsg / 75; | ||
211 | msf->frame = hsg % 75; | ||
212 | msf->min = bin2bcd(msf->min); /* convert to BCD */ | ||
213 | msf->sec = bin2bcd(msf->sec); | ||
214 | msf->frame = bin2bcd(msf->frame); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Send a command to cdrom. Invalidate status. | ||
219 | */ | ||
220 | static void sjcd_send_cmd(unsigned char cmd) | ||
221 | { | ||
222 | #if defined( SJCD_TRACE ) | ||
223 | printk("SJCD: send_cmd( 0x%x )\n", cmd); | ||
224 | #endif | ||
225 | outb(cmd, SJCDPORT(0)); | ||
226 | sjcd_command_is_in_progress = 1; | ||
227 | sjcd_status_valid = 0; | ||
228 | sjcd_command_failed = 0; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * Send a command with one arg to cdrom. Invalidate status. | ||
233 | */ | ||
234 | static void sjcd_send_1_cmd(unsigned char cmd, unsigned char a) | ||
235 | { | ||
236 | #if defined( SJCD_TRACE ) | ||
237 | printk("SJCD: send_1_cmd( 0x%x, 0x%x )\n", cmd, a); | ||
238 | #endif | ||
239 | outb(cmd, SJCDPORT(0)); | ||
240 | outb(a, SJCDPORT(0)); | ||
241 | sjcd_command_is_in_progress = 1; | ||
242 | sjcd_status_valid = 0; | ||
243 | sjcd_command_failed = 0; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Send a command with four args to cdrom. Invalidate status. | ||
248 | */ | ||
249 | static void sjcd_send_4_cmd(unsigned char cmd, unsigned char a, | ||
250 | unsigned char b, unsigned char c, | ||
251 | unsigned char d) | ||
252 | { | ||
253 | #if defined( SJCD_TRACE ) | ||
254 | printk("SJCD: send_4_cmd( 0x%x )\n", cmd); | ||
255 | #endif | ||
256 | outb(cmd, SJCDPORT(0)); | ||
257 | outb(a, SJCDPORT(0)); | ||
258 | outb(b, SJCDPORT(0)); | ||
259 | outb(c, SJCDPORT(0)); | ||
260 | outb(d, SJCDPORT(0)); | ||
261 | sjcd_command_is_in_progress = 1; | ||
262 | sjcd_status_valid = 0; | ||
263 | sjcd_command_failed = 0; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * Send a play or read command to cdrom. Invalidate Status. | ||
268 | */ | ||
269 | static void sjcd_send_6_cmd(unsigned char cmd, struct sjcd_play_msf *pms) | ||
270 | { | ||
271 | #if defined( SJCD_TRACE ) | ||
272 | printk("SJCD: send_long_cmd( 0x%x )\n", cmd); | ||
273 | #endif | ||
274 | outb(cmd, SJCDPORT(0)); | ||
275 | outb(pms->start.min, SJCDPORT(0)); | ||
276 | outb(pms->start.sec, SJCDPORT(0)); | ||
277 | outb(pms->start.frame, SJCDPORT(0)); | ||
278 | outb(pms->end.min, SJCDPORT(0)); | ||
279 | outb(pms->end.sec, SJCDPORT(0)); | ||
280 | outb(pms->end.frame, SJCDPORT(0)); | ||
281 | sjcd_command_is_in_progress = 1; | ||
282 | sjcd_status_valid = 0; | ||
283 | sjcd_command_failed = 0; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Get a value from the data port. Should not block, so we use a little | ||
288 | * wait for a while. Returns 0 if OK. | ||
289 | */ | ||
290 | static int sjcd_load_response(void *buf, int len) | ||
291 | { | ||
292 | unsigned char *resp = (unsigned char *) buf; | ||
293 | |||
294 | for (; len; --len) { | ||
295 | int i; | ||
296 | for (i = 200; | ||
297 | i-- && !SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)));); | ||
298 | if (i > 0) | ||
299 | *resp++ = (unsigned char) inb(SJCDPORT(0)); | ||
300 | else | ||
301 | break; | ||
302 | } | ||
303 | return (len); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Load and parse command completion status (drive info byte and maybe error). | ||
308 | * Sorry, no error classification yet. | ||
309 | */ | ||
310 | static void sjcd_load_status(void) | ||
311 | { | ||
312 | sjcd_media_is_changed = 0; | ||
313 | sjcd_completion_error = 0; | ||
314 | sjcd_completion_status = inb(SJCDPORT(0)); | ||
315 | if (sjcd_completion_status & SST_DOOR_OPENED) { | ||
316 | sjcd_door_closed = sjcd_media_is_available = 0; | ||
317 | } else { | ||
318 | sjcd_door_closed = 1; | ||
319 | if (sjcd_completion_status & SST_MEDIA_CHANGED) | ||
320 | sjcd_media_is_available = sjcd_media_is_changed = | ||
321 | 1; | ||
322 | else if (sjcd_completion_status & 0x0F) { | ||
323 | /* | ||
324 | * OK, we seem to catch an error ... | ||
325 | */ | ||
326 | while (!SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))); | ||
327 | sjcd_completion_error = inb(SJCDPORT(0)); | ||
328 | if ((sjcd_completion_status & 0x08) && | ||
329 | (sjcd_completion_error & 0x40)) | ||
330 | sjcd_media_is_available = 0; | ||
331 | else | ||
332 | sjcd_command_failed = 1; | ||
333 | } else | ||
334 | sjcd_media_is_available = 1; | ||
335 | } | ||
336 | /* | ||
337 | * Ok, status loaded successfully. | ||
338 | */ | ||
339 | sjcd_status_valid = 1, sjcd_error_reported = 0; | ||
340 | sjcd_command_is_in_progress = 0; | ||
341 | |||
342 | /* | ||
343 | * If the disk is changed, the TOC is not valid. | ||
344 | */ | ||
345 | if (sjcd_media_is_changed) | ||
346 | sjcd_toc_uptodate = 0; | ||
347 | #if defined( SJCD_TRACE ) | ||
348 | printk("SJCD: status %02x.%02x loaded.\n", | ||
349 | (int) sjcd_completion_status, (int) sjcd_completion_error); | ||
350 | #endif | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * Read status from cdrom. Check to see if the status is available. | ||
355 | */ | ||
356 | static int sjcd_check_status(void) | ||
357 | { | ||
358 | /* | ||
359 | * Try to load the response from cdrom into buffer. | ||
360 | */ | ||
361 | if (SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))) { | ||
362 | sjcd_load_status(); | ||
363 | return (1); | ||
364 | } else { | ||
365 | /* | ||
366 | * No status is available. | ||
367 | */ | ||
368 | return (0); | ||
369 | } | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * This is just timeout counter, and nothing more. Surprised ? :-) | ||
374 | */ | ||
375 | static volatile long sjcd_status_timeout; | ||
376 | |||
377 | /* | ||
378 | * We need about 10 seconds to wait. The longest command takes about 5 seconds | ||
379 | * to probe the disk (usually after tray closed or drive reset). Other values | ||
380 | * should be thought of for other commands. | ||
381 | */ | ||
382 | #define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000 | ||
383 | |||
384 | static void sjcd_status_timer(void) | ||
385 | { | ||
386 | if (sjcd_check_status()) { | ||
387 | /* | ||
388 | * The command completed and status is loaded, stop waiting. | ||
389 | */ | ||
390 | wake_up(&sjcd_waitq); | ||
391 | } else if (--sjcd_status_timeout <= 0) { | ||
392 | /* | ||
393 | * We are timed out. | ||
394 | */ | ||
395 | wake_up(&sjcd_waitq); | ||
396 | } else { | ||
397 | /* | ||
398 | * We have still some time to wait. Try again. | ||
399 | */ | ||
400 | SJCD_SET_TIMER(sjcd_status_timer, 1); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Wait for status for 10 sec approx. Returns non-positive when timed out. | ||
406 | * Should not be used while reading data CDs. | ||
407 | */ | ||
408 | static int sjcd_wait_for_status(void) | ||
409 | { | ||
410 | sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT; | ||
411 | SJCD_SET_TIMER(sjcd_status_timer, 1); | ||
412 | sleep_on(&sjcd_waitq); | ||
413 | #if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE ) | ||
414 | if (sjcd_status_timeout <= 0) | ||
415 | printk("SJCD: Error Wait For Status.\n"); | ||
416 | #endif | ||
417 | return (sjcd_status_timeout); | ||
418 | } | ||
419 | |||
420 | static int sjcd_receive_status(void) | ||
421 | { | ||
422 | int i; | ||
423 | #if defined( SJCD_TRACE ) | ||
424 | printk("SJCD: receive_status\n"); | ||
425 | #endif | ||
426 | /* | ||
427 | * Wait a bit for status available. | ||
428 | */ | ||
429 | for (i = 200; i-- && (sjcd_check_status() == 0);); | ||
430 | if (i < 0) { | ||
431 | #if defined( SJCD_TRACE ) | ||
432 | printk("SJCD: long wait for status\n"); | ||
433 | #endif | ||
434 | if (sjcd_wait_for_status() <= 0) | ||
435 | printk("SJCD: Timeout when read status.\n"); | ||
436 | else | ||
437 | i = 0; | ||
438 | } | ||
439 | return (i); | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * Load the status. Issue get status command and wait for status available. | ||
444 | */ | ||
445 | static void sjcd_get_status(void) | ||
446 | { | ||
447 | #if defined( SJCD_TRACE ) | ||
448 | printk("SJCD: get_status\n"); | ||
449 | #endif | ||
450 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
451 | sjcd_receive_status(); | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * Check the drive if the disk is changed. Should be revised. | ||
456 | */ | ||
457 | static int sjcd_disk_change(struct gendisk *disk) | ||
458 | { | ||
459 | #if 0 | ||
460 | printk("SJCD: sjcd_disk_change(%s)\n", disk->disk_name); | ||
461 | #endif | ||
462 | if (!sjcd_command_is_in_progress) | ||
463 | sjcd_get_status(); | ||
464 | return (sjcd_status_valid ? sjcd_media_is_changed : 0); | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * Read the table of contents (TOC) and TOC header if necessary. | ||
469 | * We assume that the drive contains no more than 99 toc entries. | ||
470 | */ | ||
471 | static struct sjcd_hw_disk_info sjcd_table_of_contents[SJCD_MAX_TRACKS]; | ||
472 | static unsigned char sjcd_first_track_no, sjcd_last_track_no; | ||
473 | #define sjcd_disk_length sjcd_table_of_contents[0].un.track_msf | ||
474 | |||
475 | static int sjcd_update_toc(void) | ||
476 | { | ||
477 | struct sjcd_hw_disk_info info; | ||
478 | int i; | ||
479 | #if defined( SJCD_TRACE ) | ||
480 | printk("SJCD: update toc:\n"); | ||
481 | #endif | ||
482 | /* | ||
483 | * check to see if we need to do anything | ||
484 | */ | ||
485 | if (sjcd_toc_uptodate) | ||
486 | return (0); | ||
487 | |||
488 | /* | ||
489 | * Get the TOC start information. | ||
490 | */ | ||
491 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK); | ||
492 | sjcd_receive_status(); | ||
493 | |||
494 | if (!sjcd_status_valid) { | ||
495 | printk("SJCD: cannot load status.\n"); | ||
496 | return (-1); | ||
497 | } | ||
498 | |||
499 | if (!sjcd_media_is_available) { | ||
500 | printk("SJCD: no disk in drive\n"); | ||
501 | return (-1); | ||
502 | } | ||
503 | |||
504 | if (!sjcd_command_failed) { | ||
505 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | ||
506 | printk | ||
507 | ("SJCD: cannot load response about TOC start.\n"); | ||
508 | return (-1); | ||
509 | } | ||
510 | sjcd_first_track_no = bcd2bin(info.un.track_no); | ||
511 | } else { | ||
512 | printk("SJCD: get first failed\n"); | ||
513 | return (-1); | ||
514 | } | ||
515 | #if defined( SJCD_TRACE ) | ||
516 | printk("SJCD: TOC start 0x%02x ", sjcd_first_track_no); | ||
517 | #endif | ||
518 | /* | ||
519 | * Get the TOC finish information. | ||
520 | */ | ||
521 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK); | ||
522 | sjcd_receive_status(); | ||
523 | |||
524 | if (!sjcd_status_valid) { | ||
525 | printk("SJCD: cannot load status.\n"); | ||
526 | return (-1); | ||
527 | } | ||
528 | |||
529 | if (!sjcd_media_is_available) { | ||
530 | printk("SJCD: no disk in drive\n"); | ||
531 | return (-1); | ||
532 | } | ||
533 | |||
534 | if (!sjcd_command_failed) { | ||
535 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | ||
536 | printk | ||
537 | ("SJCD: cannot load response about TOC finish.\n"); | ||
538 | return (-1); | ||
539 | } | ||
540 | sjcd_last_track_no = bcd2bin(info.un.track_no); | ||
541 | } else { | ||
542 | printk("SJCD: get last failed\n"); | ||
543 | return (-1); | ||
544 | } | ||
545 | #if defined( SJCD_TRACE ) | ||
546 | printk("SJCD: TOC finish 0x%02x ", sjcd_last_track_no); | ||
547 | #endif | ||
548 | for (i = sjcd_first_track_no; i <= sjcd_last_track_no; i++) { | ||
549 | /* | ||
550 | * Get the first track information. | ||
551 | */ | ||
552 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, bin2bcd(i)); | ||
553 | sjcd_receive_status(); | ||
554 | |||
555 | if (!sjcd_status_valid) { | ||
556 | printk("SJCD: cannot load status.\n"); | ||
557 | return (-1); | ||
558 | } | ||
559 | |||
560 | if (!sjcd_media_is_available) { | ||
561 | printk("SJCD: no disk in drive\n"); | ||
562 | return (-1); | ||
563 | } | ||
564 | |||
565 | if (!sjcd_command_failed) { | ||
566 | if (sjcd_load_response(&sjcd_table_of_contents[i], | ||
567 | sizeof(struct | ||
568 | sjcd_hw_disk_info)) | ||
569 | != 0) { | ||
570 | printk | ||
571 | ("SJCD: cannot load info for %d track\n", | ||
572 | i); | ||
573 | return (-1); | ||
574 | } | ||
575 | } else { | ||
576 | printk("SJCD: get info %d failed\n", i); | ||
577 | return (-1); | ||
578 | } | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * Get the disk length info. | ||
583 | */ | ||
584 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE); | ||
585 | sjcd_receive_status(); | ||
586 | |||
587 | if (!sjcd_status_valid) { | ||
588 | printk("SJCD: cannot load status.\n"); | ||
589 | return (-1); | ||
590 | } | ||
591 | |||
592 | if (!sjcd_media_is_available) { | ||
593 | printk("SJCD: no disk in drive\n"); | ||
594 | return (-1); | ||
595 | } | ||
596 | |||
597 | if (!sjcd_command_failed) { | ||
598 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | ||
599 | printk | ||
600 | ("SJCD: cannot load response about disk size.\n"); | ||
601 | return (-1); | ||
602 | } | ||
603 | sjcd_disk_length.min = info.un.track_msf.min; | ||
604 | sjcd_disk_length.sec = info.un.track_msf.sec; | ||
605 | sjcd_disk_length.frame = info.un.track_msf.frame; | ||
606 | } else { | ||
607 | printk("SJCD: get size failed\n"); | ||
608 | return (1); | ||
609 | } | ||
610 | #if defined( SJCD_TRACE ) | ||
611 | printk("SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min, | ||
612 | sjcd_disk_length.sec, sjcd_disk_length.frame); | ||
613 | #endif | ||
614 | return (0); | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | * Load subchannel information. | ||
619 | */ | ||
620 | static int sjcd_get_q_info(struct sjcd_hw_qinfo *qp) | ||
621 | { | ||
622 | int s; | ||
623 | #if defined( SJCD_TRACE ) | ||
624 | printk("SJCD: load sub q\n"); | ||
625 | #endif | ||
626 | sjcd_send_cmd(SCMD_GET_QINFO); | ||
627 | s = sjcd_receive_status(); | ||
628 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) { | ||
629 | sjcd_send_cmd(0xF2); | ||
630 | s = sjcd_receive_status(); | ||
631 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) | ||
632 | return (-1); | ||
633 | sjcd_send_cmd(SCMD_GET_QINFO); | ||
634 | s = sjcd_receive_status(); | ||
635 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) | ||
636 | return (-1); | ||
637 | } | ||
638 | if (sjcd_media_is_available) | ||
639 | if (sjcd_load_response(qp, sizeof(*qp)) == 0) | ||
640 | return (0); | ||
641 | return (-1); | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Start playing from the specified position. | ||
646 | */ | ||
647 | static int sjcd_play(struct sjcd_play_msf *mp) | ||
648 | { | ||
649 | struct sjcd_play_msf msf; | ||
650 | |||
651 | /* | ||
652 | * Turn the device to play mode. | ||
653 | */ | ||
654 | sjcd_send_1_cmd(SCMD_SET_MODE, SCMD_MODE_PLAY); | ||
655 | if (sjcd_receive_status() < 0) | ||
656 | return (-1); | ||
657 | |||
658 | /* | ||
659 | * Seek to the starting point. | ||
660 | */ | ||
661 | msf.start = mp->start; | ||
662 | msf.end.min = msf.end.sec = msf.end.frame = 0x00; | ||
663 | sjcd_send_6_cmd(SCMD_SEEK, &msf); | ||
664 | if (sjcd_receive_status() < 0) | ||
665 | return (-1); | ||
666 | |||
667 | /* | ||
668 | * Start playing. | ||
669 | */ | ||
670 | sjcd_send_6_cmd(SCMD_PLAY, mp); | ||
671 | return (sjcd_receive_status()); | ||
672 | } | ||
673 | |||
674 | /* | ||
675 | * Tray control functions. | ||
676 | */ | ||
677 | static int sjcd_tray_close(void) | ||
678 | { | ||
679 | #if defined( SJCD_TRACE ) | ||
680 | printk("SJCD: tray_close\n"); | ||
681 | #endif | ||
682 | sjcd_send_cmd(SCMD_CLOSE_TRAY); | ||
683 | return (sjcd_receive_status()); | ||
684 | } | ||
685 | |||
686 | static int sjcd_tray_lock(void) | ||
687 | { | ||
688 | #if defined( SJCD_TRACE ) | ||
689 | printk("SJCD: tray_lock\n"); | ||
690 | #endif | ||
691 | sjcd_send_cmd(SCMD_LOCK_TRAY); | ||
692 | return (sjcd_receive_status()); | ||
693 | } | ||
694 | |||
695 | static int sjcd_tray_unlock(void) | ||
696 | { | ||
697 | #if defined( SJCD_TRACE ) | ||
698 | printk("SJCD: tray_unlock\n"); | ||
699 | #endif | ||
700 | sjcd_send_cmd(SCMD_UNLOCK_TRAY); | ||
701 | return (sjcd_receive_status()); | ||
702 | } | ||
703 | |||
704 | static int sjcd_tray_open(void) | ||
705 | { | ||
706 | #if defined( SJCD_TRACE ) | ||
707 | printk("SJCD: tray_open\n"); | ||
708 | #endif | ||
709 | sjcd_send_cmd(SCMD_EJECT_TRAY); | ||
710 | return (sjcd_receive_status()); | ||
711 | } | ||
712 | |||
713 | /* | ||
714 | * Do some user commands. | ||
715 | */ | ||
716 | static int sjcd_ioctl(struct inode *ip, struct file *fp, | ||
717 | unsigned int cmd, unsigned long arg) | ||
718 | { | ||
719 | void __user *argp = (void __user *)arg; | ||
720 | #if defined( SJCD_TRACE ) | ||
721 | printk("SJCD:ioctl\n"); | ||
722 | #endif | ||
723 | |||
724 | sjcd_get_status(); | ||
725 | if (!sjcd_status_valid) | ||
726 | return (-EIO); | ||
727 | if (sjcd_update_toc() < 0) | ||
728 | return (-EIO); | ||
729 | |||
730 | switch (cmd) { | ||
731 | case CDROMSTART:{ | ||
732 | #if defined( SJCD_TRACE ) | ||
733 | printk("SJCD: ioctl: start\n"); | ||
734 | #endif | ||
735 | return (0); | ||
736 | } | ||
737 | |||
738 | case CDROMSTOP:{ | ||
739 | #if defined( SJCD_TRACE ) | ||
740 | printk("SJCD: ioctl: stop\n"); | ||
741 | #endif | ||
742 | sjcd_send_cmd(SCMD_PAUSE); | ||
743 | (void) sjcd_receive_status(); | ||
744 | sjcd_audio_status = CDROM_AUDIO_NO_STATUS; | ||
745 | return (0); | ||
746 | } | ||
747 | |||
748 | case CDROMPAUSE:{ | ||
749 | struct sjcd_hw_qinfo q_info; | ||
750 | #if defined( SJCD_TRACE ) | ||
751 | printk("SJCD: ioctl: pause\n"); | ||
752 | #endif | ||
753 | if (sjcd_audio_status == CDROM_AUDIO_PLAY) { | ||
754 | sjcd_send_cmd(SCMD_PAUSE); | ||
755 | (void) sjcd_receive_status(); | ||
756 | if (sjcd_get_q_info(&q_info) < 0) { | ||
757 | sjcd_audio_status = | ||
758 | CDROM_AUDIO_NO_STATUS; | ||
759 | } else { | ||
760 | sjcd_audio_status = | ||
761 | CDROM_AUDIO_PAUSED; | ||
762 | sjcd_playing.start = q_info.abs; | ||
763 | } | ||
764 | return (0); | ||
765 | } else | ||
766 | return (-EINVAL); | ||
767 | } | ||
768 | |||
769 | case CDROMRESUME:{ | ||
770 | #if defined( SJCD_TRACE ) | ||
771 | printk("SJCD: ioctl: resume\n"); | ||
772 | #endif | ||
773 | if (sjcd_audio_status == CDROM_AUDIO_PAUSED) { | ||
774 | /* | ||
775 | * continue play starting at saved location | ||
776 | */ | ||
777 | if (sjcd_play(&sjcd_playing) < 0) { | ||
778 | sjcd_audio_status = | ||
779 | CDROM_AUDIO_ERROR; | ||
780 | return (-EIO); | ||
781 | } else { | ||
782 | sjcd_audio_status = | ||
783 | CDROM_AUDIO_PLAY; | ||
784 | return (0); | ||
785 | } | ||
786 | } else | ||
787 | return (-EINVAL); | ||
788 | } | ||
789 | |||
790 | case CDROMPLAYTRKIND:{ | ||
791 | struct cdrom_ti ti; | ||
792 | int s = -EFAULT; | ||
793 | #if defined( SJCD_TRACE ) | ||
794 | printk("SJCD: ioctl: playtrkind\n"); | ||
795 | #endif | ||
796 | if (!copy_from_user(&ti, argp, sizeof(ti))) { | ||
797 | s = 0; | ||
798 | if (ti.cdti_trk0 < sjcd_first_track_no) | ||
799 | return (-EINVAL); | ||
800 | if (ti.cdti_trk1 > sjcd_last_track_no) | ||
801 | ti.cdti_trk1 = sjcd_last_track_no; | ||
802 | if (ti.cdti_trk0 > ti.cdti_trk1) | ||
803 | return (-EINVAL); | ||
804 | |||
805 | sjcd_playing.start = | ||
806 | sjcd_table_of_contents[ti.cdti_trk0]. | ||
807 | un.track_msf; | ||
808 | sjcd_playing.end = | ||
809 | (ti.cdti_trk1 < | ||
810 | sjcd_last_track_no) ? | ||
811 | sjcd_table_of_contents[ti.cdti_trk1 + | ||
812 | 1].un. | ||
813 | track_msf : sjcd_table_of_contents[0]. | ||
814 | un.track_msf; | ||
815 | |||
816 | if (sjcd_play(&sjcd_playing) < 0) { | ||
817 | sjcd_audio_status = | ||
818 | CDROM_AUDIO_ERROR; | ||
819 | return (-EIO); | ||
820 | } else | ||
821 | sjcd_audio_status = | ||
822 | CDROM_AUDIO_PLAY; | ||
823 | } | ||
824 | return (s); | ||
825 | } | ||
826 | |||
827 | case CDROMPLAYMSF:{ | ||
828 | struct cdrom_msf sjcd_msf; | ||
829 | int s; | ||
830 | #if defined( SJCD_TRACE ) | ||
831 | printk("SJCD: ioctl: playmsf\n"); | ||
832 | #endif | ||
833 | if ((s = | ||
834 | access_ok(VERIFY_READ, argp, sizeof(sjcd_msf)) | ||
835 | ? 0 : -EFAULT) == 0) { | ||
836 | if (sjcd_audio_status == CDROM_AUDIO_PLAY) { | ||
837 | sjcd_send_cmd(SCMD_PAUSE); | ||
838 | (void) sjcd_receive_status(); | ||
839 | sjcd_audio_status = | ||
840 | CDROM_AUDIO_NO_STATUS; | ||
841 | } | ||
842 | |||
843 | if (copy_from_user(&sjcd_msf, argp, | ||
844 | sizeof(sjcd_msf))) | ||
845 | return (-EFAULT); | ||
846 | |||
847 | sjcd_playing.start.min = | ||
848 | bin2bcd(sjcd_msf.cdmsf_min0); | ||
849 | sjcd_playing.start.sec = | ||
850 | bin2bcd(sjcd_msf.cdmsf_sec0); | ||
851 | sjcd_playing.start.frame = | ||
852 | bin2bcd(sjcd_msf.cdmsf_frame0); | ||
853 | sjcd_playing.end.min = | ||
854 | bin2bcd(sjcd_msf.cdmsf_min1); | ||
855 | sjcd_playing.end.sec = | ||
856 | bin2bcd(sjcd_msf.cdmsf_sec1); | ||
857 | sjcd_playing.end.frame = | ||
858 | bin2bcd(sjcd_msf.cdmsf_frame1); | ||
859 | |||
860 | if (sjcd_play(&sjcd_playing) < 0) { | ||
861 | sjcd_audio_status = | ||
862 | CDROM_AUDIO_ERROR; | ||
863 | return (-EIO); | ||
864 | } else | ||
865 | sjcd_audio_status = | ||
866 | CDROM_AUDIO_PLAY; | ||
867 | } | ||
868 | return (s); | ||
869 | } | ||
870 | |||
871 | case CDROMREADTOCHDR:{ | ||
872 | struct cdrom_tochdr toc_header; | ||
873 | #if defined (SJCD_TRACE ) | ||
874 | printk("SJCD: ioctl: readtocheader\n"); | ||
875 | #endif | ||
876 | toc_header.cdth_trk0 = sjcd_first_track_no; | ||
877 | toc_header.cdth_trk1 = sjcd_last_track_no; | ||
878 | if (copy_to_user(argp, &toc_header, | ||
879 | sizeof(toc_header))) | ||
880 | return -EFAULT; | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | case CDROMREADTOCENTRY:{ | ||
885 | struct cdrom_tocentry toc_entry; | ||
886 | int s; | ||
887 | #if defined( SJCD_TRACE ) | ||
888 | printk("SJCD: ioctl: readtocentry\n"); | ||
889 | #endif | ||
890 | if ((s = | ||
891 | access_ok(VERIFY_WRITE, argp, sizeof(toc_entry)) | ||
892 | ? 0 : -EFAULT) == 0) { | ||
893 | struct sjcd_hw_disk_info *tp; | ||
894 | |||
895 | if (copy_from_user(&toc_entry, argp, | ||
896 | sizeof(toc_entry))) | ||
897 | return (-EFAULT); | ||
898 | if (toc_entry.cdte_track == CDROM_LEADOUT) | ||
899 | tp = &sjcd_table_of_contents[0]; | ||
900 | else if (toc_entry.cdte_track < | ||
901 | sjcd_first_track_no) | ||
902 | return (-EINVAL); | ||
903 | else if (toc_entry.cdte_track > | ||
904 | sjcd_last_track_no) | ||
905 | return (-EINVAL); | ||
906 | else | ||
907 | tp = &sjcd_table_of_contents | ||
908 | [toc_entry.cdte_track]; | ||
909 | |||
910 | toc_entry.cdte_adr = | ||
911 | tp->track_control & 0x0F; | ||
912 | toc_entry.cdte_ctrl = | ||
913 | tp->track_control >> 4; | ||
914 | |||
915 | switch (toc_entry.cdte_format) { | ||
916 | case CDROM_LBA: | ||
917 | toc_entry.cdte_addr.lba = | ||
918 | msf2hsg(&(tp->un.track_msf)); | ||
919 | break; | ||
920 | case CDROM_MSF: | ||
921 | toc_entry.cdte_addr.msf.minute = | ||
922 | bcd2bin(tp->un.track_msf.min); | ||
923 | toc_entry.cdte_addr.msf.second = | ||
924 | bcd2bin(tp->un.track_msf.sec); | ||
925 | toc_entry.cdte_addr.msf.frame = | ||
926 | bcd2bin(tp->un.track_msf. | ||
927 | frame); | ||
928 | break; | ||
929 | default: | ||
930 | return (-EINVAL); | ||
931 | } | ||
932 | if (copy_to_user(argp, &toc_entry, | ||
933 | sizeof(toc_entry))) | ||
934 | s = -EFAULT; | ||
935 | } | ||
936 | return (s); | ||
937 | } | ||
938 | |||
939 | case CDROMSUBCHNL:{ | ||
940 | struct cdrom_subchnl subchnl; | ||
941 | int s; | ||
942 | #if defined( SJCD_TRACE ) | ||
943 | printk("SJCD: ioctl: subchnl\n"); | ||
944 | #endif | ||
945 | if ((s = | ||
946 | access_ok(VERIFY_WRITE, argp, sizeof(subchnl)) | ||
947 | ? 0 : -EFAULT) == 0) { | ||
948 | struct sjcd_hw_qinfo q_info; | ||
949 | |||
950 | if (copy_from_user(&subchnl, argp, | ||
951 | sizeof(subchnl))) | ||
952 | return (-EFAULT); | ||
953 | |||
954 | if (sjcd_get_q_info(&q_info) < 0) | ||
955 | return (-EIO); | ||
956 | |||
957 | subchnl.cdsc_audiostatus = | ||
958 | sjcd_audio_status; | ||
959 | subchnl.cdsc_adr = | ||
960 | q_info.track_control & 0x0F; | ||
961 | subchnl.cdsc_ctrl = | ||
962 | q_info.track_control >> 4; | ||
963 | subchnl.cdsc_trk = | ||
964 | bcd2bin(q_info.track_no); | ||
965 | subchnl.cdsc_ind = bcd2bin(q_info.x); | ||
966 | |||
967 | switch (subchnl.cdsc_format) { | ||
968 | case CDROM_LBA: | ||
969 | subchnl.cdsc_absaddr.lba = | ||
970 | msf2hsg(&(q_info.abs)); | ||
971 | subchnl.cdsc_reladdr.lba = | ||
972 | msf2hsg(&(q_info.rel)); | ||
973 | break; | ||
974 | case CDROM_MSF: | ||
975 | subchnl.cdsc_absaddr.msf.minute = | ||
976 | bcd2bin(q_info.abs.min); | ||
977 | subchnl.cdsc_absaddr.msf.second = | ||
978 | bcd2bin(q_info.abs.sec); | ||
979 | subchnl.cdsc_absaddr.msf.frame = | ||
980 | bcd2bin(q_info.abs.frame); | ||
981 | subchnl.cdsc_reladdr.msf.minute = | ||
982 | bcd2bin(q_info.rel.min); | ||
983 | subchnl.cdsc_reladdr.msf.second = | ||
984 | bcd2bin(q_info.rel.sec); | ||
985 | subchnl.cdsc_reladdr.msf.frame = | ||
986 | bcd2bin(q_info.rel.frame); | ||
987 | break; | ||
988 | default: | ||
989 | return (-EINVAL); | ||
990 | } | ||
991 | if (copy_to_user(argp, &subchnl, | ||
992 | sizeof(subchnl))) | ||
993 | s = -EFAULT; | ||
994 | } | ||
995 | return (s); | ||
996 | } | ||
997 | |||
998 | case CDROMVOLCTRL:{ | ||
999 | struct cdrom_volctrl vol_ctrl; | ||
1000 | int s; | ||
1001 | #if defined( SJCD_TRACE ) | ||
1002 | printk("SJCD: ioctl: volctrl\n"); | ||
1003 | #endif | ||
1004 | if ((s = | ||
1005 | access_ok(VERIFY_READ, argp, sizeof(vol_ctrl)) | ||
1006 | ? 0 : -EFAULT) == 0) { | ||
1007 | unsigned char dummy[4]; | ||
1008 | |||
1009 | if (copy_from_user(&vol_ctrl, argp, | ||
1010 | sizeof(vol_ctrl))) | ||
1011 | return (-EFAULT); | ||
1012 | sjcd_send_4_cmd(SCMD_SET_VOLUME, | ||
1013 | vol_ctrl.channel0, 0xFF, | ||
1014 | vol_ctrl.channel1, 0xFF); | ||
1015 | if (sjcd_receive_status() < 0) | ||
1016 | return (-EIO); | ||
1017 | (void) sjcd_load_response(dummy, 4); | ||
1018 | } | ||
1019 | return (s); | ||
1020 | } | ||
1021 | |||
1022 | case CDROMEJECT:{ | ||
1023 | #if defined( SJCD_TRACE ) | ||
1024 | printk("SJCD: ioctl: eject\n"); | ||
1025 | #endif | ||
1026 | if (!sjcd_command_is_in_progress) { | ||
1027 | sjcd_tray_unlock(); | ||
1028 | sjcd_send_cmd(SCMD_EJECT_TRAY); | ||
1029 | (void) sjcd_receive_status(); | ||
1030 | } | ||
1031 | return (0); | ||
1032 | } | ||
1033 | |||
1034 | #if defined( SJCD_GATHER_STAT ) | ||
1035 | case 0xABCD:{ | ||
1036 | #if defined( SJCD_TRACE ) | ||
1037 | printk("SJCD: ioctl: statistic\n"); | ||
1038 | #endif | ||
1039 | if (copy_to_user(argp, &statistic, sizeof(statistic))) | ||
1040 | return -EFAULT; | ||
1041 | return 0; | ||
1042 | } | ||
1043 | #endif | ||
1044 | |||
1045 | default: | ||
1046 | return (-EINVAL); | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | /* | ||
1051 | * Invalidate internal buffers of the driver. | ||
1052 | */ | ||
1053 | static void sjcd_invalidate_buffers(void) | ||
1054 | { | ||
1055 | int i; | ||
1056 | for (i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[i++] = -1); | ||
1057 | sjcd_buf_out = -1; | ||
1058 | } | ||
1059 | |||
1060 | /* | ||
1061 | * Take care of the different block sizes between cdrom and Linux. | ||
1062 | * When Linux gets variable block sizes this will probably go away. | ||
1063 | */ | ||
1064 | |||
1065 | static int current_valid(void) | ||
1066 | { | ||
1067 | return CURRENT && | ||
1068 | CURRENT->cmd == READ && | ||
1069 | CURRENT->sector != -1; | ||
1070 | } | ||
1071 | |||
1072 | static void sjcd_transfer(void) | ||
1073 | { | ||
1074 | #if defined( SJCD_TRACE ) | ||
1075 | printk("SJCD: transfer:\n"); | ||
1076 | #endif | ||
1077 | if (current_valid()) { | ||
1078 | while (CURRENT->nr_sectors) { | ||
1079 | int i, bn = CURRENT->sector / 4; | ||
1080 | for (i = 0; | ||
1081 | i < SJCD_BUF_SIZ && sjcd_buf_bn[i] != bn; | ||
1082 | i++); | ||
1083 | if (i < SJCD_BUF_SIZ) { | ||
1084 | int offs = | ||
1085 | (i * 4 + (CURRENT->sector & 3)) * 512; | ||
1086 | int nr_sectors = 4 - (CURRENT->sector & 3); | ||
1087 | if (sjcd_buf_out != i) { | ||
1088 | sjcd_buf_out = i; | ||
1089 | if (sjcd_buf_bn[i] != bn) { | ||
1090 | sjcd_buf_out = -1; | ||
1091 | continue; | ||
1092 | } | ||
1093 | } | ||
1094 | if (nr_sectors > CURRENT->nr_sectors) | ||
1095 | nr_sectors = CURRENT->nr_sectors; | ||
1096 | #if defined( SJCD_TRACE ) | ||
1097 | printk("SJCD: copy out\n"); | ||
1098 | #endif | ||
1099 | memcpy(CURRENT->buffer, sjcd_buf + offs, | ||
1100 | nr_sectors * 512); | ||
1101 | CURRENT->nr_sectors -= nr_sectors; | ||
1102 | CURRENT->sector += nr_sectors; | ||
1103 | CURRENT->buffer += nr_sectors * 512; | ||
1104 | } else { | ||
1105 | sjcd_buf_out = -1; | ||
1106 | break; | ||
1107 | } | ||
1108 | } | ||
1109 | } | ||
1110 | #if defined( SJCD_TRACE ) | ||
1111 | printk("SJCD: transfer: done\n"); | ||
1112 | #endif | ||
1113 | } | ||
1114 | |||
1115 | static void sjcd_poll(void) | ||
1116 | { | ||
1117 | #if defined( SJCD_GATHER_STAT ) | ||
1118 | /* | ||
1119 | * Update total number of ticks. | ||
1120 | */ | ||
1121 | statistic.ticks++; | ||
1122 | statistic.tticks[sjcd_transfer_state]++; | ||
1123 | #endif | ||
1124 | |||
1125 | ReSwitch:switch (sjcd_transfer_state) { | ||
1126 | |||
1127 | case SJCD_S_IDLE:{ | ||
1128 | #if defined( SJCD_GATHER_STAT ) | ||
1129 | statistic.idle_ticks++; | ||
1130 | #endif | ||
1131 | #if defined( SJCD_TRACE ) | ||
1132 | printk("SJCD_S_IDLE\n"); | ||
1133 | #endif | ||
1134 | return; | ||
1135 | } | ||
1136 | |||
1137 | case SJCD_S_START:{ | ||
1138 | #if defined( SJCD_GATHER_STAT ) | ||
1139 | statistic.start_ticks++; | ||
1140 | #endif | ||
1141 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
1142 | sjcd_transfer_state = | ||
1143 | sjcd_mode == | ||
1144 | SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE; | ||
1145 | sjcd_transfer_timeout = 500; | ||
1146 | #if defined( SJCD_TRACE ) | ||
1147 | printk("SJCD_S_START: goto SJCD_S_%s mode\n", | ||
1148 | sjcd_transfer_state == | ||
1149 | SJCD_S_READ ? "READ" : "MODE"); | ||
1150 | #endif | ||
1151 | break; | ||
1152 | } | ||
1153 | |||
1154 | case SJCD_S_MODE:{ | ||
1155 | if (sjcd_check_status()) { | ||
1156 | /* | ||
1157 | * Previous command is completed. | ||
1158 | */ | ||
1159 | if (!sjcd_status_valid | ||
1160 | || sjcd_command_failed) { | ||
1161 | #if defined( SJCD_TRACE ) | ||
1162 | printk | ||
1163 | ("SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n"); | ||
1164 | #endif | ||
1165 | sjcd_transfer_state = SJCD_S_STOP; | ||
1166 | goto ReSwitch; | ||
1167 | } | ||
1168 | |||
1169 | sjcd_mode = 0; /* unknown mode; should not be valid when failed */ | ||
1170 | sjcd_send_1_cmd(SCMD_SET_MODE, | ||
1171 | SCMD_MODE_COOKED); | ||
1172 | sjcd_transfer_state = SJCD_S_READ; | ||
1173 | sjcd_transfer_timeout = 1000; | ||
1174 | #if defined( SJCD_TRACE ) | ||
1175 | printk | ||
1176 | ("SJCD_S_MODE: goto SJCD_S_READ mode\n"); | ||
1177 | #endif | ||
1178 | } | ||
1179 | #if defined( SJCD_GATHER_STAT ) | ||
1180 | else | ||
1181 | statistic.mode_ticks++; | ||
1182 | #endif | ||
1183 | break; | ||
1184 | } | ||
1185 | |||
1186 | case SJCD_S_READ:{ | ||
1187 | if (sjcd_status_valid ? 1 : sjcd_check_status()) { | ||
1188 | /* | ||
1189 | * Previous command is completed. | ||
1190 | */ | ||
1191 | if (!sjcd_status_valid | ||
1192 | || sjcd_command_failed) { | ||
1193 | #if defined( SJCD_TRACE ) | ||
1194 | printk | ||
1195 | ("SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n"); | ||
1196 | #endif | ||
1197 | sjcd_transfer_state = SJCD_S_STOP; | ||
1198 | goto ReSwitch; | ||
1199 | } | ||
1200 | if (!sjcd_media_is_available) { | ||
1201 | #if defined( SJCD_TRACE ) | ||
1202 | printk | ||
1203 | ("SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n"); | ||
1204 | #endif | ||
1205 | sjcd_transfer_state = SJCD_S_STOP; | ||
1206 | goto ReSwitch; | ||
1207 | } | ||
1208 | if (sjcd_mode != SCMD_MODE_COOKED) { | ||
1209 | /* | ||
1210 | * We seem to come from set mode. So discard one byte of result. | ||
1211 | */ | ||
1212 | if (sjcd_load_response | ||
1213 | (&sjcd_mode, 1) != 0) { | ||
1214 | #if defined( SJCD_TRACE ) | ||
1215 | printk | ||
1216 | ("SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n"); | ||
1217 | #endif | ||
1218 | sjcd_transfer_state = | ||
1219 | SJCD_S_STOP; | ||
1220 | goto ReSwitch; | ||
1221 | } | ||
1222 | if (sjcd_mode != SCMD_MODE_COOKED) { | ||
1223 | #if defined( SJCD_TRACE ) | ||
1224 | printk | ||
1225 | ("SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n"); | ||
1226 | #endif | ||
1227 | sjcd_transfer_state = | ||
1228 | SJCD_S_STOP; | ||
1229 | goto ReSwitch; | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | if (current_valid()) { | ||
1234 | struct sjcd_play_msf msf; | ||
1235 | |||
1236 | sjcd_next_bn = CURRENT->sector / 4; | ||
1237 | hsg2msf(sjcd_next_bn, &msf.start); | ||
1238 | msf.end.min = 0; | ||
1239 | msf.end.sec = 0; | ||
1240 | msf.end.frame = sjcd_read_count = | ||
1241 | SJCD_BUF_SIZ; | ||
1242 | #if defined( SJCD_TRACE ) | ||
1243 | printk | ||
1244 | ("SJCD: ---reading msf-address %x:%x:%x %x:%x:%x\n", | ||
1245 | msf.start.min, msf.start.sec, | ||
1246 | msf.start.frame, msf.end.min, | ||
1247 | msf.end.sec, msf.end.frame); | ||
1248 | printk | ||
1249 | ("sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", | ||
1250 | sjcd_next_bn, sjcd_buf_in, | ||
1251 | sjcd_buf_out, | ||
1252 | sjcd_buf_bn[sjcd_buf_in]); | ||
1253 | #endif | ||
1254 | sjcd_send_6_cmd(SCMD_DATA_READ, | ||
1255 | &msf); | ||
1256 | sjcd_transfer_state = SJCD_S_DATA; | ||
1257 | sjcd_transfer_timeout = 500; | ||
1258 | #if defined( SJCD_TRACE ) | ||
1259 | printk | ||
1260 | ("SJCD_S_READ: go to SJCD_S_DATA mode\n"); | ||
1261 | #endif | ||
1262 | } else { | ||
1263 | #if defined( SJCD_TRACE ) | ||
1264 | printk | ||
1265 | ("SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n"); | ||
1266 | #endif | ||
1267 | sjcd_transfer_state = SJCD_S_STOP; | ||
1268 | goto ReSwitch; | ||
1269 | } | ||
1270 | } | ||
1271 | #if defined( SJCD_GATHER_STAT ) | ||
1272 | else | ||
1273 | statistic.read_ticks++; | ||
1274 | #endif | ||
1275 | break; | ||
1276 | } | ||
1277 | |||
1278 | case SJCD_S_DATA:{ | ||
1279 | unsigned char stat; | ||
1280 | |||
1281 | sjcd_s_data:stat = | ||
1282 | inb(SJCDPORT | ||
1283 | (1)); | ||
1284 | #if defined( SJCD_TRACE ) | ||
1285 | printk("SJCD_S_DATA: status = 0x%02x\n", stat); | ||
1286 | #endif | ||
1287 | if (SJCD_STATUS_AVAILABLE(stat)) { | ||
1288 | /* | ||
1289 | * No data is waiting for us in the drive buffer. Status of operation | ||
1290 | * completion is available. Read and parse it. | ||
1291 | */ | ||
1292 | sjcd_load_status(); | ||
1293 | |||
1294 | if (!sjcd_status_valid | ||
1295 | || sjcd_command_failed) { | ||
1296 | #if defined( SJCD_TRACE ) | ||
1297 | printk | ||
1298 | ("SJCD: read block %d failed, maybe audio disk? Giving up\n", | ||
1299 | sjcd_next_bn); | ||
1300 | #endif | ||
1301 | if (current_valid()) | ||
1302 | end_request(CURRENT, 0); | ||
1303 | #if defined( SJCD_TRACE ) | ||
1304 | printk | ||
1305 | ("SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n"); | ||
1306 | #endif | ||
1307 | sjcd_transfer_state = SJCD_S_STOP; | ||
1308 | goto ReSwitch; | ||
1309 | } | ||
1310 | |||
1311 | if (!sjcd_media_is_available) { | ||
1312 | printk | ||
1313 | ("SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n"); | ||
1314 | sjcd_transfer_state = SJCD_S_STOP; | ||
1315 | goto ReSwitch; | ||
1316 | } | ||
1317 | |||
1318 | sjcd_transfer_state = SJCD_S_READ; | ||
1319 | goto ReSwitch; | ||
1320 | } else if (SJCD_DATA_AVAILABLE(stat)) { | ||
1321 | /* | ||
1322 | * One frame is read into device buffer. We must copy it to our memory. | ||
1323 | * Otherwise cdrom hangs up. Check to see if we have something to copy | ||
1324 | * to. | ||
1325 | */ | ||
1326 | if (!current_valid() | ||
1327 | && sjcd_buf_in == sjcd_buf_out) { | ||
1328 | #if defined( SJCD_TRACE ) | ||
1329 | printk | ||
1330 | ("SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n"); | ||
1331 | printk | ||
1332 | (" ... all the date would be discarded\n"); | ||
1333 | #endif | ||
1334 | sjcd_transfer_state = SJCD_S_STOP; | ||
1335 | goto ReSwitch; | ||
1336 | } | ||
1337 | |||
1338 | /* | ||
1339 | * Everything seems to be OK. Just read the frame and recalculate | ||
1340 | * indices. | ||
1341 | */ | ||
1342 | sjcd_buf_bn[sjcd_buf_in] = -1; /* ??? */ | ||
1343 | insb(SJCDPORT(2), | ||
1344 | sjcd_buf + 2048 * sjcd_buf_in, 2048); | ||
1345 | #if defined( SJCD_TRACE ) | ||
1346 | printk | ||
1347 | ("SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n", | ||
1348 | sjcd_next_bn, sjcd_buf_in, | ||
1349 | sjcd_buf_out, | ||
1350 | sjcd_buf_bn[sjcd_buf_in]); | ||
1351 | #endif | ||
1352 | sjcd_buf_bn[sjcd_buf_in] = sjcd_next_bn++; | ||
1353 | if (sjcd_buf_out == -1) | ||
1354 | sjcd_buf_out = sjcd_buf_in; | ||
1355 | if (++sjcd_buf_in == SJCD_BUF_SIZ) | ||
1356 | sjcd_buf_in = 0; | ||
1357 | |||
1358 | /* | ||
1359 | * Only one frame is ready at time. So we should turn over to wait for | ||
1360 | * another frame. If we need that, of course. | ||
1361 | */ | ||
1362 | if (--sjcd_read_count == 0) { | ||
1363 | /* | ||
1364 | * OK, request seems to be precessed. Continue transferring... | ||
1365 | */ | ||
1366 | if (!sjcd_transfer_is_active) { | ||
1367 | while (current_valid()) { | ||
1368 | /* | ||
1369 | * Continue transferring. | ||
1370 | */ | ||
1371 | sjcd_transfer(); | ||
1372 | if (CURRENT-> | ||
1373 | nr_sectors == | ||
1374 | 0) | ||
1375 | end_request | ||
1376 | (CURRENT, 1); | ||
1377 | else | ||
1378 | break; | ||
1379 | } | ||
1380 | } | ||
1381 | if (current_valid() && | ||
1382 | (CURRENT->sector / 4 < | ||
1383 | sjcd_next_bn | ||
1384 | || CURRENT->sector / 4 > | ||
1385 | sjcd_next_bn + | ||
1386 | SJCD_BUF_SIZ)) { | ||
1387 | #if defined( SJCD_TRACE ) | ||
1388 | printk | ||
1389 | ("SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n"); | ||
1390 | #endif | ||
1391 | sjcd_transfer_state = | ||
1392 | SJCD_S_STOP; | ||
1393 | goto ReSwitch; | ||
1394 | } | ||
1395 | } | ||
1396 | /* | ||
1397 | * Now we should turn around rather than wait for while. | ||
1398 | */ | ||
1399 | goto sjcd_s_data; | ||
1400 | } | ||
1401 | #if defined( SJCD_GATHER_STAT ) | ||
1402 | else | ||
1403 | statistic.data_ticks++; | ||
1404 | #endif | ||
1405 | break; | ||
1406 | } | ||
1407 | |||
1408 | case SJCD_S_STOP:{ | ||
1409 | sjcd_read_count = 0; | ||
1410 | sjcd_send_cmd(SCMD_STOP); | ||
1411 | sjcd_transfer_state = SJCD_S_STOPPING; | ||
1412 | sjcd_transfer_timeout = 500; | ||
1413 | #if defined( SJCD_GATHER_STAT ) | ||
1414 | statistic.stop_ticks++; | ||
1415 | #endif | ||
1416 | break; | ||
1417 | } | ||
1418 | |||
1419 | case SJCD_S_STOPPING:{ | ||
1420 | unsigned char stat; | ||
1421 | |||
1422 | stat = inb(SJCDPORT(1)); | ||
1423 | #if defined( SJCD_TRACE ) | ||
1424 | printk("SJCD_S_STOP: status = 0x%02x\n", stat); | ||
1425 | #endif | ||
1426 | if (SJCD_DATA_AVAILABLE(stat)) { | ||
1427 | int i; | ||
1428 | #if defined( SJCD_TRACE ) | ||
1429 | printk("SJCD_S_STOP: discard data\n"); | ||
1430 | #endif | ||
1431 | /* | ||
1432 | * Discard all the data from the pipe. Foolish method. | ||
1433 | */ | ||
1434 | for (i = 2048; i--; | ||
1435 | (void) inb(SJCDPORT(2))); | ||
1436 | sjcd_transfer_timeout = 500; | ||
1437 | } else if (SJCD_STATUS_AVAILABLE(stat)) { | ||
1438 | sjcd_load_status(); | ||
1439 | if (sjcd_status_valid | ||
1440 | && sjcd_media_is_changed) { | ||
1441 | sjcd_toc_uptodate = 0; | ||
1442 | sjcd_invalidate_buffers(); | ||
1443 | } | ||
1444 | if (current_valid()) { | ||
1445 | if (sjcd_status_valid) | ||
1446 | sjcd_transfer_state = | ||
1447 | SJCD_S_READ; | ||
1448 | else | ||
1449 | sjcd_transfer_state = | ||
1450 | SJCD_S_START; | ||
1451 | } else | ||
1452 | sjcd_transfer_state = SJCD_S_IDLE; | ||
1453 | goto ReSwitch; | ||
1454 | } | ||
1455 | #if defined( SJCD_GATHER_STAT ) | ||
1456 | else | ||
1457 | statistic.stopping_ticks++; | ||
1458 | #endif | ||
1459 | break; | ||
1460 | } | ||
1461 | |||
1462 | default: | ||
1463 | printk("SJCD: poll: invalid state %d\n", | ||
1464 | sjcd_transfer_state); | ||
1465 | return; | ||
1466 | } | ||
1467 | |||
1468 | if (--sjcd_transfer_timeout == 0) { | ||
1469 | printk("SJCD: timeout in state %d\n", sjcd_transfer_state); | ||
1470 | while (current_valid()) | ||
1471 | end_request(CURRENT, 0); | ||
1472 | sjcd_send_cmd(SCMD_STOP); | ||
1473 | sjcd_transfer_state = SJCD_S_IDLE; | ||
1474 | goto ReSwitch; | ||
1475 | } | ||
1476 | |||
1477 | /* | ||
1478 | * Get back in some time. 1 should be replaced with count variable to | ||
1479 | * avoid unnecessary testings. | ||
1480 | */ | ||
1481 | SJCD_SET_TIMER(sjcd_poll, 1); | ||
1482 | } | ||
1483 | |||
1484 | static void do_sjcd_request(request_queue_t * q) | ||
1485 | { | ||
1486 | #if defined( SJCD_TRACE ) | ||
1487 | printk("SJCD: do_sjcd_request(%ld+%ld)\n", | ||
1488 | CURRENT->sector, CURRENT->nr_sectors); | ||
1489 | #endif | ||
1490 | sjcd_transfer_is_active = 1; | ||
1491 | while (current_valid()) { | ||
1492 | sjcd_transfer(); | ||
1493 | if (CURRENT->nr_sectors == 0) | ||
1494 | end_request(CURRENT, 1); | ||
1495 | else { | ||
1496 | sjcd_buf_out = -1; /* Want to read a block not in buffer */ | ||
1497 | if (sjcd_transfer_state == SJCD_S_IDLE) { | ||
1498 | if (!sjcd_toc_uptodate) { | ||
1499 | if (sjcd_update_toc() < 0) { | ||
1500 | printk | ||
1501 | ("SJCD: transfer: discard\n"); | ||
1502 | while (current_valid()) | ||
1503 | end_request(CURRENT, 0); | ||
1504 | break; | ||
1505 | } | ||
1506 | } | ||
1507 | sjcd_transfer_state = SJCD_S_START; | ||
1508 | SJCD_SET_TIMER(sjcd_poll, HZ / 100); | ||
1509 | } | ||
1510 | break; | ||
1511 | } | ||
1512 | } | ||
1513 | sjcd_transfer_is_active = 0; | ||
1514 | #if defined( SJCD_TRACE ) | ||
1515 | printk | ||
1516 | ("sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n", | ||
1517 | sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, | ||
1518 | sjcd_buf_bn[sjcd_buf_in]); | ||
1519 | printk("do_sjcd_request ends\n"); | ||
1520 | #endif | ||
1521 | } | ||
1522 | |||
1523 | /* | ||
1524 | * Open the device special file. Check disk is in. | ||
1525 | */ | ||
1526 | static int sjcd_open(struct inode *ip, struct file *fp) | ||
1527 | { | ||
1528 | /* | ||
1529 | * Check the presence of device. | ||
1530 | */ | ||
1531 | if (!sjcd_present) | ||
1532 | return (-ENXIO); | ||
1533 | |||
1534 | /* | ||
1535 | * Only read operations are allowed. Really? (:-) | ||
1536 | */ | ||
1537 | if (fp->f_mode & 2) | ||
1538 | return (-EROFS); | ||
1539 | |||
1540 | if (sjcd_open_count == 0) { | ||
1541 | int s, sjcd_open_tries; | ||
1542 | /* We don't know that, do we? */ | ||
1543 | /* | ||
1544 | sjcd_audio_status = CDROM_AUDIO_NO_STATUS; | ||
1545 | */ | ||
1546 | sjcd_mode = 0; | ||
1547 | sjcd_door_was_open = 0; | ||
1548 | sjcd_transfer_state = SJCD_S_IDLE; | ||
1549 | sjcd_invalidate_buffers(); | ||
1550 | sjcd_status_valid = 0; | ||
1551 | |||
1552 | /* | ||
1553 | * Strict status checking. | ||
1554 | */ | ||
1555 | for (sjcd_open_tries = 4; --sjcd_open_tries;) { | ||
1556 | if (!sjcd_status_valid) | ||
1557 | sjcd_get_status(); | ||
1558 | if (!sjcd_status_valid) { | ||
1559 | #if defined( SJCD_DIAGNOSTIC ) | ||
1560 | printk | ||
1561 | ("SJCD: open: timed out when check status.\n"); | ||
1562 | #endif | ||
1563 | goto err_out; | ||
1564 | } else if (!sjcd_media_is_available) { | ||
1565 | #if defined( SJCD_DIAGNOSTIC ) | ||
1566 | printk("SJCD: open: no disk in drive\n"); | ||
1567 | #endif | ||
1568 | if (!sjcd_door_closed) { | ||
1569 | sjcd_door_was_open = 1; | ||
1570 | #if defined( SJCD_TRACE ) | ||
1571 | printk | ||
1572 | ("SJCD: open: close the tray\n"); | ||
1573 | #endif | ||
1574 | s = sjcd_tray_close(); | ||
1575 | if (s < 0 || !sjcd_status_valid | ||
1576 | || sjcd_command_failed) { | ||
1577 | #if defined( SJCD_DIAGNOSTIC ) | ||
1578 | printk | ||
1579 | ("SJCD: open: tray close attempt failed\n"); | ||
1580 | #endif | ||
1581 | goto err_out; | ||
1582 | } | ||
1583 | continue; | ||
1584 | } else | ||
1585 | goto err_out; | ||
1586 | } | ||
1587 | break; | ||
1588 | } | ||
1589 | s = sjcd_tray_lock(); | ||
1590 | if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { | ||
1591 | #if defined( SJCD_DIAGNOSTIC ) | ||
1592 | printk("SJCD: open: tray lock attempt failed\n"); | ||
1593 | #endif | ||
1594 | goto err_out; | ||
1595 | } | ||
1596 | #if defined( SJCD_TRACE ) | ||
1597 | printk("SJCD: open: done\n"); | ||
1598 | #endif | ||
1599 | } | ||
1600 | |||
1601 | ++sjcd_open_count; | ||
1602 | return (0); | ||
1603 | |||
1604 | err_out: | ||
1605 | return (-EIO); | ||
1606 | } | ||
1607 | |||
1608 | /* | ||
1609 | * On close, we flush all sjcd blocks from the buffer cache. | ||
1610 | */ | ||
1611 | static int sjcd_release(struct inode *inode, struct file *file) | ||
1612 | { | ||
1613 | int s; | ||
1614 | |||
1615 | #if defined( SJCD_TRACE ) | ||
1616 | printk("SJCD: release\n"); | ||
1617 | #endif | ||
1618 | if (--sjcd_open_count == 0) { | ||
1619 | sjcd_invalidate_buffers(); | ||
1620 | s = sjcd_tray_unlock(); | ||
1621 | if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { | ||
1622 | #if defined( SJCD_DIAGNOSTIC ) | ||
1623 | printk | ||
1624 | ("SJCD: release: tray unlock attempt failed.\n"); | ||
1625 | #endif | ||
1626 | } | ||
1627 | if (sjcd_door_was_open) { | ||
1628 | s = sjcd_tray_open(); | ||
1629 | if (s < 0 || !sjcd_status_valid | ||
1630 | || sjcd_command_failed) { | ||
1631 | #if defined( SJCD_DIAGNOSTIC ) | ||
1632 | printk | ||
1633 | ("SJCD: release: tray unload attempt failed.\n"); | ||
1634 | #endif | ||
1635 | } | ||
1636 | } | ||
1637 | } | ||
1638 | return 0; | ||
1639 | } | ||
1640 | |||
1641 | /* | ||
1642 | * A list of file operations allowed for this cdrom. | ||
1643 | */ | ||
1644 | static struct block_device_operations sjcd_fops = { | ||
1645 | .owner = THIS_MODULE, | ||
1646 | .open = sjcd_open, | ||
1647 | .release = sjcd_release, | ||
1648 | .ioctl = sjcd_ioctl, | ||
1649 | .media_changed = sjcd_disk_change, | ||
1650 | }; | ||
1651 | |||
1652 | /* | ||
1653 | * Following stuff is intended for initialization of the cdrom. It | ||
1654 | * first looks for presence of device. If the device is present, it | ||
1655 | * will be reset. Then read the version of the drive and load status. | ||
1656 | * The version is two BCD-coded bytes. | ||
1657 | */ | ||
1658 | static struct { | ||
1659 | unsigned char major, minor; | ||
1660 | } sjcd_version; | ||
1661 | |||
1662 | static struct gendisk *sjcd_disk; | ||
1663 | |||
1664 | /* | ||
1665 | * Test for presence of drive and initialize it. Called at boot time. | ||
1666 | * Probe cdrom, find out version and status. | ||
1667 | */ | ||
1668 | static int __init sjcd_init(void) | ||
1669 | { | ||
1670 | int i; | ||
1671 | |||
1672 | printk(KERN_INFO | ||
1673 | "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", | ||
1674 | SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR); | ||
1675 | |||
1676 | #if defined( SJCD_TRACE ) | ||
1677 | printk("SJCD: sjcd=0x%x: ", sjcd_base); | ||
1678 | #endif | ||
1679 | |||
1680 | if (register_blkdev(MAJOR_NR, "sjcd")) | ||
1681 | return -EIO; | ||
1682 | |||
1683 | sjcd_queue = blk_init_queue(do_sjcd_request, &sjcd_lock); | ||
1684 | if (!sjcd_queue) | ||
1685 | goto out0; | ||
1686 | |||
1687 | blk_queue_hardsect_size(sjcd_queue, 2048); | ||
1688 | |||
1689 | sjcd_disk = alloc_disk(1); | ||
1690 | if (!sjcd_disk) { | ||
1691 | printk(KERN_ERR "SJCD: can't allocate disk"); | ||
1692 | goto out1; | ||
1693 | } | ||
1694 | sjcd_disk->major = MAJOR_NR, | ||
1695 | sjcd_disk->first_minor = 0, | ||
1696 | sjcd_disk->fops = &sjcd_fops, | ||
1697 | sprintf(sjcd_disk->disk_name, "sjcd"); | ||
1698 | sprintf(sjcd_disk->devfs_name, "sjcd"); | ||
1699 | |||
1700 | if (!request_region(sjcd_base, 4,"sjcd")) { | ||
1701 | printk | ||
1702 | ("SJCD: Init failed, I/O port (%X) is already in use\n", | ||
1703 | sjcd_base); | ||
1704 | goto out2; | ||
1705 | } | ||
1706 | |||
1707 | /* | ||
1708 | * Check for card. Since we are booting now, we can't use standard | ||
1709 | * wait algorithm. | ||
1710 | */ | ||
1711 | printk(KERN_INFO "SJCD: Resetting: "); | ||
1712 | sjcd_send_cmd(SCMD_RESET); | ||
1713 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1714 | unsigned long timer; | ||
1715 | |||
1716 | /* | ||
1717 | * Wait 10ms approx. | ||
1718 | */ | ||
1719 | for (timer = jiffies; time_before_eq(jiffies, timer);); | ||
1720 | if ((i % 100) == 0) | ||
1721 | printk("."); | ||
1722 | (void) sjcd_check_status(); | ||
1723 | } | ||
1724 | if (i == 0 || sjcd_command_failed) { | ||
1725 | printk(" reset failed, no drive found.\n"); | ||
1726 | goto out3; | ||
1727 | } else | ||
1728 | printk("\n"); | ||
1729 | |||
1730 | /* | ||
1731 | * Get and print out cdrom version. | ||
1732 | */ | ||
1733 | printk(KERN_INFO "SJCD: Getting version: "); | ||
1734 | sjcd_send_cmd(SCMD_GET_VERSION); | ||
1735 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1736 | unsigned long timer; | ||
1737 | |||
1738 | /* | ||
1739 | * Wait 10ms approx. | ||
1740 | */ | ||
1741 | for (timer = jiffies; time_before_eq(jiffies, timer);); | ||
1742 | if ((i % 100) == 0) | ||
1743 | printk("."); | ||
1744 | (void) sjcd_check_status(); | ||
1745 | } | ||
1746 | if (i == 0 || sjcd_command_failed) { | ||
1747 | printk(" get version failed, no drive found.\n"); | ||
1748 | goto out3; | ||
1749 | } | ||
1750 | |||
1751 | if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) { | ||
1752 | printk(" %1x.%02x\n", (int) sjcd_version.major, | ||
1753 | (int) sjcd_version.minor); | ||
1754 | } else { | ||
1755 | printk(" read version failed, no drive found.\n"); | ||
1756 | goto out3; | ||
1757 | } | ||
1758 | |||
1759 | /* | ||
1760 | * Check and print out the tray state. (if it is needed?). | ||
1761 | */ | ||
1762 | if (!sjcd_status_valid) { | ||
1763 | printk(KERN_INFO "SJCD: Getting status: "); | ||
1764 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
1765 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1766 | unsigned long timer; | ||
1767 | |||
1768 | /* | ||
1769 | * Wait 10ms approx. | ||
1770 | */ | ||
1771 | for (timer = jiffies; | ||
1772 | time_before_eq(jiffies, timer);); | ||
1773 | if ((i % 100) == 0) | ||
1774 | printk("."); | ||
1775 | (void) sjcd_check_status(); | ||
1776 | } | ||
1777 | if (i == 0 || sjcd_command_failed) { | ||
1778 | printk(" get status failed, no drive found.\n"); | ||
1779 | goto out3; | ||
1780 | } else | ||
1781 | printk("\n"); | ||
1782 | } | ||
1783 | |||
1784 | printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); | ||
1785 | sjcd_disk->queue = sjcd_queue; | ||
1786 | add_disk(sjcd_disk); | ||
1787 | |||
1788 | sjcd_present++; | ||
1789 | return (0); | ||
1790 | out3: | ||
1791 | release_region(sjcd_base, 4); | ||
1792 | out2: | ||
1793 | put_disk(sjcd_disk); | ||
1794 | out1: | ||
1795 | blk_cleanup_queue(sjcd_queue); | ||
1796 | out0: | ||
1797 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | ||
1798 | printk("SJCD: cannot unregister device.\n"); | ||
1799 | return (-EIO); | ||
1800 | } | ||
1801 | |||
1802 | static void __exit sjcd_exit(void) | ||
1803 | { | ||
1804 | del_gendisk(sjcd_disk); | ||
1805 | put_disk(sjcd_disk); | ||
1806 | release_region(sjcd_base, 4); | ||
1807 | blk_cleanup_queue(sjcd_queue); | ||
1808 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | ||
1809 | printk("SJCD: cannot unregister device.\n"); | ||
1810 | printk(KERN_INFO "SJCD: module: removed.\n"); | ||
1811 | } | ||
1812 | |||
1813 | module_init(sjcd_init); | ||
1814 | module_exit(sjcd_exit); | ||
1815 | |||
1816 | MODULE_LICENSE("GPL"); | ||
1817 | MODULE_ALIAS_BLOCKDEV_MAJOR(SANYO_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/sjcd.h b/drivers/cdrom/sjcd.h new file mode 100644 index 000000000000..0aa5e714659d --- /dev/null +++ b/drivers/cdrom/sjcd.h | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Definitions for a Sanyo CD-ROM interface. | ||
3 | * | ||
4 | * Copyright (C) 1995 Vadim V. Model | ||
5 | * model@cecmow.enet.dec.com | ||
6 | * vadim@rbrf.msk.su | ||
7 | * vadim@ipsun.ras.ru | ||
8 | * Eric van der Maarel | ||
9 | * H.T.M.v.d.Maarel@marin.nl | ||
10 | * | ||
11 | * This information is based on mcd.c from M. Harriss and sjcd102.lst from | ||
12 | * E. Moenkeberg. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #ifndef __SJCD_H__ | ||
30 | #define __SJCD_H__ | ||
31 | |||
32 | /* | ||
33 | * Change this to set the I/O port address as default. More flexibility | ||
34 | * come with setup implementation. | ||
35 | */ | ||
36 | #define SJCD_BASE_ADDR 0x340 | ||
37 | |||
38 | /* | ||
39 | * Change this to set the irq as default. Really SANYO do not use interrupts | ||
40 | * at all. | ||
41 | */ | ||
42 | #define SJCD_INTR_NR 0 | ||
43 | |||
44 | /* | ||
45 | * Change this to set the dma as default value. really SANYO does not use | ||
46 | * direct memory access at all. | ||
47 | */ | ||
48 | #define SJCD_DMA_NR 0 | ||
49 | |||
50 | /* | ||
51 | * Macros which allow us to find out the status of the drive. | ||
52 | */ | ||
53 | #define SJCD_STATUS_AVAILABLE( x ) (((x)&0x02)==0) | ||
54 | #define SJCD_DATA_AVAILABLE( x ) (((x)&0x01)==0) | ||
55 | |||
56 | /* | ||
57 | * Port access macro. Three ports are available: S-data port (command port), | ||
58 | * status port (read only) and D-data port (read only). | ||
59 | */ | ||
60 | #define SJCDPORT( x ) ( sjcd_base + ( x ) ) | ||
61 | #define SJCD_STATUS_PORT SJCDPORT( 1 ) | ||
62 | #define SJCD_S_DATA_PORT SJCDPORT( 0 ) | ||
63 | #define SJCD_COMMAND_PORT SJCDPORT( 0 ) | ||
64 | #define SJCD_D_DATA_PORT SJCDPORT( 2 ) | ||
65 | |||
66 | /* | ||
67 | * Drive info bits. Drive info available as first (mandatory) byte of | ||
68 | * command completion status. | ||
69 | */ | ||
70 | #define SST_NOT_READY 0x10 /* no disk in the drive (???) */ | ||
71 | #define SST_MEDIA_CHANGED 0x20 /* disk is changed */ | ||
72 | #define SST_DOOR_OPENED 0x40 /* door is open */ | ||
73 | |||
74 | /* commands */ | ||
75 | |||
76 | #define SCMD_EJECT_TRAY 0xD0 /* eject tray if not locked */ | ||
77 | #define SCMD_LOCK_TRAY 0xD2 /* lock tray when in */ | ||
78 | #define SCMD_UNLOCK_TRAY 0xD4 /* unlock tray when in */ | ||
79 | #define SCMD_CLOSE_TRAY 0xD6 /* load tray in */ | ||
80 | |||
81 | #define SCMD_RESET 0xFA /* soft reset */ | ||
82 | #define SCMD_GET_STATUS 0x80 | ||
83 | #define SCMD_GET_VERSION 0xCC | ||
84 | |||
85 | #define SCMD_DATA_READ 0xA0 /* are the same, depend on mode&args */ | ||
86 | #define SCMD_SEEK 0xA0 | ||
87 | #define SCMD_PLAY 0xA0 | ||
88 | |||
89 | #define SCMD_GET_QINFO 0xA8 | ||
90 | |||
91 | #define SCMD_SET_MODE 0xC4 | ||
92 | #define SCMD_MODE_PLAY 0xE0 | ||
93 | #define SCMD_MODE_COOKED (0xF8 & ~0x20) | ||
94 | #define SCMD_MODE_RAW 0xF9 | ||
95 | #define SCMD_MODE_x20_BIT 0x20 /* What is it for ? */ | ||
96 | |||
97 | #define SCMD_SET_VOLUME 0xAE | ||
98 | #define SCMD_PAUSE 0xE0 | ||
99 | #define SCMD_STOP 0xE0 | ||
100 | |||
101 | #define SCMD_GET_DISK_INFO 0xAA | ||
102 | |||
103 | /* | ||
104 | * Some standard arguments for SCMD_GET_DISK_INFO. | ||
105 | */ | ||
106 | #define SCMD_GET_1_TRACK 0xA0 /* get the first track information */ | ||
107 | #define SCMD_GET_L_TRACK 0xA1 /* get the last track information */ | ||
108 | #define SCMD_GET_D_SIZE 0xA2 /* get the whole disk information */ | ||
109 | |||
110 | /* | ||
111 | * Borrowed from hd.c. Allows to optimize multiple port read commands. | ||
112 | */ | ||
113 | #define S_READ_DATA( port, buf, nr ) insb( port, buf, nr ) | ||
114 | |||
115 | /* | ||
116 | * We assume that there are no audio disks with TOC length more than this | ||
117 | * number (I personally have never seen disks with more than 20 fragments). | ||
118 | */ | ||
119 | #define SJCD_MAX_TRACKS 100 | ||
120 | |||
121 | struct msf { | ||
122 | unsigned char min; | ||
123 | unsigned char sec; | ||
124 | unsigned char frame; | ||
125 | }; | ||
126 | |||
127 | struct sjcd_hw_disk_info { | ||
128 | unsigned char track_control; | ||
129 | unsigned char track_no; | ||
130 | unsigned char x, y, z; | ||
131 | union { | ||
132 | unsigned char track_no; | ||
133 | struct msf track_msf; | ||
134 | } un; | ||
135 | }; | ||
136 | |||
137 | struct sjcd_hw_qinfo { | ||
138 | unsigned char track_control; | ||
139 | unsigned char track_no; | ||
140 | unsigned char x; | ||
141 | struct msf rel; | ||
142 | struct msf abs; | ||
143 | }; | ||
144 | |||
145 | struct sjcd_play_msf { | ||
146 | struct msf start; | ||
147 | struct msf end; | ||
148 | }; | ||
149 | |||
150 | struct sjcd_disk_info { | ||
151 | unsigned char first; | ||
152 | unsigned char last; | ||
153 | struct msf disk_length; | ||
154 | struct msf first_track; | ||
155 | }; | ||
156 | |||
157 | struct sjcd_toc { | ||
158 | unsigned char ctrl_addr; | ||
159 | unsigned char track; | ||
160 | unsigned char point_index; | ||
161 | struct msf track_time; | ||
162 | struct msf disk_time; | ||
163 | }; | ||
164 | |||
165 | #if defined( SJCD_GATHER_STAT ) | ||
166 | |||
167 | struct sjcd_stat { | ||
168 | int ticks; | ||
169 | int tticks[ 8 ]; | ||
170 | int idle_ticks; | ||
171 | int start_ticks; | ||
172 | int mode_ticks; | ||
173 | int read_ticks; | ||
174 | int data_ticks; | ||
175 | int stop_ticks; | ||
176 | int stopping_ticks; | ||
177 | }; | ||
178 | |||
179 | #endif | ||
180 | |||
181 | #endif | ||
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c new file mode 100644 index 000000000000..f4be7bfd6675 --- /dev/null +++ b/drivers/cdrom/sonycd535.c | |||
@@ -0,0 +1,1692 @@ | |||
1 | /* | ||
2 | * Sony CDU-535 interface device driver | ||
3 | * | ||
4 | * This is a modified version of the CDU-31A device driver (see below). | ||
5 | * Changes were made using documentation for the CDU-531 (which Sony | ||
6 | * assures me is very similar to the 535) and partial disassembly of the | ||
7 | * DOS driver. I used Minyard's driver and replaced the CDU-31A | ||
8 | * commands with the CDU-531 commands. This was complicated by a different | ||
9 | * interface protocol with the drive. The driver is still polled. | ||
10 | * | ||
11 | * Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec. | ||
12 | * I tried polling without the sony_sleep during the data transfers but | ||
13 | * it did not speed things up any. | ||
14 | * | ||
15 | * 1993-05-23 (rgj) changed the major number to 21 to get rid of conflict | ||
16 | * with CDU-31A driver. This is the also the number from the Linux | ||
17 | * Device Driver Registry for the Sony Drive. Hope nobody else is using it. | ||
18 | * | ||
19 | * 1993-08-29 (rgj) remove the configuring of the interface board address | ||
20 | * from the top level configuration, you have to modify it in this file. | ||
21 | * | ||
22 | * 1995-01-26 Made module-capable (Joel Katz <Stimpson@Panix.COM>) | ||
23 | * | ||
24 | * 1995-05-20 | ||
25 | * Modified to support CDU-510/515 series | ||
26 | * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) | ||
27 | * Fixed to report verify_area() failures | ||
28 | * (Heiko Eissfeldt <heiko@colossus.escape.de>) | ||
29 | * | ||
30 | * 1995-06-01 | ||
31 | * More changes to support CDU-510/515 series | ||
32 | * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) | ||
33 | * | ||
34 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | ||
35 | * Removed init_module & cleanup_module in favor of | ||
36 | * module_init & module_exit. | ||
37 | * Torben Mathiasen <tmm@image.dk> | ||
38 | * | ||
39 | * September 2003 - Fix SMP support by removing cli/sti calls. | ||
40 | * Using spinlocks with a wait_queue instead. | ||
41 | * Felipe Damasio <felipewd@terra.com.br> | ||
42 | * | ||
43 | * Things to do: | ||
44 | * - handle errors and status better, put everything into a single word | ||
45 | * - use interrupts (code mostly there, but a big hole still missing) | ||
46 | * - handle multi-session CDs? | ||
47 | * - use DMA? | ||
48 | * | ||
49 | * Known Bugs: | ||
50 | * - | ||
51 | * | ||
52 | * Ken Pizzini (ken@halcyon.com) | ||
53 | * | ||
54 | * Original by: | ||
55 | * Ron Jeppesen (ronj.an@site007.saic.com) | ||
56 | * | ||
57 | * | ||
58 | *------------------------------------------------------------------------ | ||
59 | * Sony CDROM interface device driver. | ||
60 | * | ||
61 | * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above) | ||
62 | * | ||
63 | * Colossians 3:17 | ||
64 | * | ||
65 | * The Sony interface device driver handles Sony interface CDROM | ||
66 | * drives and provides a complete block-level interface as well as an | ||
67 | * ioctl() interface compatible with the Sun (as specified in | ||
68 | * include/linux/cdrom.h). With this interface, CDROMs can be | ||
69 | * accessed and standard audio CDs can be played back normally. | ||
70 | * | ||
71 | * This interface is (unfortunately) a polled interface. This is | ||
72 | * because most Sony interfaces are set up with DMA and interrupts | ||
73 | * disables. Some (like mine) do not even have the capability to | ||
74 | * handle interrupts or DMA. For this reason you will see a bit of | ||
75 | * the following: | ||
76 | * | ||
77 | * snap = jiffies; | ||
78 | * while (jiffies-snap < SONY_JIFFIES_TIMEOUT) | ||
79 | * { | ||
80 | * if (some_condition()) | ||
81 | * break; | ||
82 | * sony_sleep(); | ||
83 | * } | ||
84 | * if (some_condition not met) | ||
85 | * { | ||
86 | * return an_error; | ||
87 | * } | ||
88 | * | ||
89 | * This ugly hack waits for something to happen, sleeping a little | ||
90 | * between every try. (The conditional is written so that jiffies | ||
91 | * wrap-around is handled properly.) | ||
92 | * | ||
93 | * One thing about these drives: They talk in MSF (Minute Second Frame) format. | ||
94 | * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a | ||
95 | * disk. The funny thing is that these are sent to the drive in BCD, but the | ||
96 | * interface wants to see them in decimal. A lot of conversion goes on. | ||
97 | * | ||
98 | * Copyright (C) 1993 Corey Minyard | ||
99 | * | ||
100 | * This program is free software; you can redistribute it and/or modify | ||
101 | * it under the terms of the GNU General Public License as published by | ||
102 | * the Free Software Foundation; either version 2 of the License, or | ||
103 | * (at your option) any later version. | ||
104 | * | ||
105 | * This program is distributed in the hope that it will be useful, | ||
106 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
107 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
108 | * GNU General Public License for more details. | ||
109 | * | ||
110 | * You should have received a copy of the GNU General Public License | ||
111 | * along with this program; if not, write to the Free Software | ||
112 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
113 | * | ||
114 | */ | ||
115 | |||
116 | |||
117 | # include <linux/module.h> | ||
118 | |||
119 | #include <linux/errno.h> | ||
120 | #include <linux/signal.h> | ||
121 | #include <linux/sched.h> | ||
122 | #include <linux/timer.h> | ||
123 | #include <linux/fs.h> | ||
124 | #include <linux/kernel.h> | ||
125 | #include <linux/interrupt.h> | ||
126 | #include <linux/ioport.h> | ||
127 | #include <linux/hdreg.h> | ||
128 | #include <linux/genhd.h> | ||
129 | #include <linux/mm.h> | ||
130 | #include <linux/slab.h> | ||
131 | #include <linux/init.h> | ||
132 | |||
133 | #define REALLY_SLOW_IO | ||
134 | #include <asm/system.h> | ||
135 | #include <asm/io.h> | ||
136 | #include <asm/uaccess.h> | ||
137 | |||
138 | #include <linux/cdrom.h> | ||
139 | |||
140 | #define MAJOR_NR CDU535_CDROM_MAJOR | ||
141 | #include <linux/blkdev.h> | ||
142 | |||
143 | #define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ | ||
144 | #include "sonycd535.h" | ||
145 | |||
146 | /* | ||
147 | * this is the base address of the interface card for the Sony CDU-535 | ||
148 | * CDROM drive. If your jumpers are set for an address other than | ||
149 | * this one (the default), change the following line to the | ||
150 | * proper address. | ||
151 | */ | ||
152 | #ifndef CDU535_ADDRESS | ||
153 | # define CDU535_ADDRESS 0x340 | ||
154 | #endif | ||
155 | #ifndef CDU535_INTERRUPT | ||
156 | # define CDU535_INTERRUPT 0 | ||
157 | #endif | ||
158 | #ifndef CDU535_HANDLE | ||
159 | # define CDU535_HANDLE "cdu535" | ||
160 | #endif | ||
161 | #ifndef CDU535_MESSAGE_NAME | ||
162 | # define CDU535_MESSAGE_NAME "Sony CDU-535" | ||
163 | #endif | ||
164 | |||
165 | #define CDU535_BLOCK_SIZE 2048 | ||
166 | |||
167 | #ifndef MAX_SPINUP_RETRY | ||
168 | # define MAX_SPINUP_RETRY 3 /* 1 is sufficient for most drives... */ | ||
169 | #endif | ||
170 | #ifndef RETRY_FOR_BAD_STATUS | ||
171 | # define RETRY_FOR_BAD_STATUS 100 /* in 10th of second */ | ||
172 | #endif | ||
173 | |||
174 | #ifndef DEBUG | ||
175 | # define DEBUG 1 | ||
176 | #endif | ||
177 | |||
178 | /* | ||
179 | * SONY535_BUFFER_SIZE determines the size of internal buffer used | ||
180 | * by the drive. It must be at least 2K and the larger the buffer | ||
181 | * the better the transfer rate. It does however take system memory. | ||
182 | * On my system I get the following transfer rates using dd to read | ||
183 | * 10 Mb off /dev/cdrom. | ||
184 | * | ||
185 | * 8K buffer 43 Kb/sec | ||
186 | * 16K buffer 66 Kb/sec | ||
187 | * 32K buffer 91 Kb/sec | ||
188 | * 64K buffer 111 Kb/sec | ||
189 | * 128K buffer 123 Kb/sec | ||
190 | * 512K buffer 123 Kb/sec | ||
191 | */ | ||
192 | #define SONY535_BUFFER_SIZE (64*1024) | ||
193 | |||
194 | /* | ||
195 | * if LOCK_DOORS is defined then the eject button is disabled while | ||
196 | * the device is open. | ||
197 | */ | ||
198 | #ifndef NO_LOCK_DOORS | ||
199 | # define LOCK_DOORS | ||
200 | #endif | ||
201 | |||
202 | static int read_subcode(void); | ||
203 | static void sony_get_toc(void); | ||
204 | static int cdu_open(struct inode *inode, struct file *filp); | ||
205 | static inline unsigned int int_to_bcd(unsigned int val); | ||
206 | static unsigned int bcd_to_int(unsigned int bcd); | ||
207 | static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2], | ||
208 | Byte * response, int n_response, int ignoreStatusBit7); | ||
209 | |||
210 | /* The base I/O address of the Sony Interface. This is a variable (not a | ||
211 | #define) so it can be easily changed via some future ioctl() */ | ||
212 | static unsigned int sony535_cd_base_io = CDU535_ADDRESS; | ||
213 | module_param(sony535_cd_base_io, int, 0); | ||
214 | |||
215 | /* | ||
216 | * The following are I/O addresses of the various registers for the drive. The | ||
217 | * comment for the base address also applies here. | ||
218 | */ | ||
219 | static unsigned short select_unit_reg; | ||
220 | static unsigned short result_reg; | ||
221 | static unsigned short command_reg; | ||
222 | static unsigned short read_status_reg; | ||
223 | static unsigned short data_reg; | ||
224 | |||
225 | static DEFINE_SPINLOCK(sonycd535_lock); /* queue lock */ | ||
226 | static struct request_queue *sonycd535_queue; | ||
227 | |||
228 | static int initialized; /* Has the drive been initialized? */ | ||
229 | static int sony_disc_changed = 1; /* Has the disk been changed | ||
230 | since the last check? */ | ||
231 | static int sony_toc_read; /* Has the table of contents been | ||
232 | read? */ | ||
233 | static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead | ||
234 | buffer. */ | ||
235 | static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of | ||
236 | the read-ahead buffer. */ | ||
237 | static unsigned int sony_usage; /* How many processes have the | ||
238 | drive open. */ | ||
239 | |||
240 | static int sony_first_block = -1; /* First OS block (512 byte) in | ||
241 | the read-ahead buffer */ | ||
242 | static int sony_last_block = -1; /* Last OS block (512 byte) in | ||
243 | the read-ahead buffer */ | ||
244 | |||
245 | static struct s535_sony_toc *sony_toc; /* Points to the table of | ||
246 | contents. */ | ||
247 | |||
248 | static struct s535_sony_subcode *last_sony_subcode; /* Points to the last | ||
249 | subcode address read */ | ||
250 | static Byte **sony_buffer; /* Points to the pointers | ||
251 | to the sector buffers */ | ||
252 | |||
253 | static int sony_inuse; /* is the drive in use? Only one | ||
254 | open at a time allowed */ | ||
255 | |||
256 | /* | ||
257 | * The audio status uses the values from read subchannel data as specified | ||
258 | * in include/linux/cdrom.h. | ||
259 | */ | ||
260 | static int sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
261 | |||
262 | /* | ||
263 | * The following are a hack for pausing and resuming audio play. The drive | ||
264 | * does not work as I would expect it, if you stop it then start it again, | ||
265 | * the drive seeks back to the beginning and starts over. This holds the | ||
266 | * position during a pause so a resume can restart it. It uses the | ||
267 | * audio status variable above to tell if it is paused. | ||
268 | * I just kept the CDU-31A driver behavior rather than using the PAUSE | ||
269 | * command on the CDU-535. | ||
270 | */ | ||
271 | static Byte cur_pos_msf[3]; | ||
272 | static Byte final_pos_msf[3]; | ||
273 | |||
274 | /* What IRQ is the drive using? 0 if none. */ | ||
275 | static int sony535_irq_used = CDU535_INTERRUPT; | ||
276 | |||
277 | /* The interrupt handler will wake this queue up when it gets an interrupt. */ | ||
278 | static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); | ||
279 | |||
280 | |||
281 | /* | ||
282 | * This routine returns 1 if the disk has been changed since the last | ||
283 | * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. | ||
284 | */ | ||
285 | static int | ||
286 | cdu535_check_media_change(struct gendisk *disk) | ||
287 | { | ||
288 | /* if driver is not initialized, always return 0 */ | ||
289 | int retval = initialized ? sony_disc_changed : 0; | ||
290 | sony_disc_changed = 0; | ||
291 | return retval; | ||
292 | } | ||
293 | |||
294 | static inline void | ||
295 | enable_interrupts(void) | ||
296 | { | ||
297 | #ifdef USE_IRQ | ||
298 | /* | ||
299 | * This code was taken from cdu31a.c; it will not | ||
300 | * directly work for the cdu535 as written... | ||
301 | */ | ||
302 | curr_control_reg |= ( SONY_ATTN_INT_EN_BIT | ||
303 | | SONY_RES_RDY_INT_EN_BIT | ||
304 | | SONY_DATA_RDY_INT_EN_BIT); | ||
305 | outb(curr_control_reg, sony_cd_control_reg); | ||
306 | #endif | ||
307 | } | ||
308 | |||
309 | static inline void | ||
310 | disable_interrupts(void) | ||
311 | { | ||
312 | #ifdef USE_IRQ | ||
313 | /* | ||
314 | * This code was taken from cdu31a.c; it will not | ||
315 | * directly work for the cdu535 as written... | ||
316 | */ | ||
317 | curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT | ||
318 | | SONY_RES_RDY_INT_EN_BIT | ||
319 | | SONY_DATA_RDY_INT_EN_BIT); | ||
320 | outb(curr_control_reg, sony_cd_control_reg); | ||
321 | #endif | ||
322 | } | ||
323 | |||
324 | static irqreturn_t | ||
325 | cdu535_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
326 | { | ||
327 | disable_interrupts(); | ||
328 | if (waitqueue_active(&cdu535_irq_wait)) { | ||
329 | wake_up(&cdu535_irq_wait); | ||
330 | return IRQ_HANDLED; | ||
331 | } | ||
332 | printk(CDU535_MESSAGE_NAME | ||
333 | ": Got an interrupt but nothing was waiting\n"); | ||
334 | return IRQ_NONE; | ||
335 | } | ||
336 | |||
337 | |||
338 | /* | ||
339 | * Wait a little while. | ||
340 | */ | ||
341 | static inline void | ||
342 | sony_sleep(void) | ||
343 | { | ||
344 | if (sony535_irq_used <= 0) { /* poll */ | ||
345 | yield(); | ||
346 | } else { /* Interrupt driven */ | ||
347 | DEFINE_WAIT(wait); | ||
348 | |||
349 | spin_lock_irq(&sonycd535_lock); | ||
350 | enable_interrupts(); | ||
351 | prepare_to_wait(&cdu535_irq_wait, &wait, TASK_INTERRUPTIBLE); | ||
352 | spin_unlock_irq(&sonycd535_lock); | ||
353 | schedule(); | ||
354 | finish_wait(&cdu535_irq_wait, &wait); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | /*------------------start of SONY CDU535 very specific ---------------------*/ | ||
359 | |||
360 | /**************************************************************************** | ||
361 | * void select_unit( int unit_no ) | ||
362 | * | ||
363 | * Select the specified unit (0-3) so that subsequent commands reference it | ||
364 | ****************************************************************************/ | ||
365 | static void | ||
366 | select_unit(int unit_no) | ||
367 | { | ||
368 | unsigned int select_mask = ~(1 << unit_no); | ||
369 | outb(select_mask, select_unit_reg); | ||
370 | } | ||
371 | |||
372 | /*************************************************************************** | ||
373 | * int read_result_reg( Byte *data_ptr ) | ||
374 | * | ||
375 | * Read a result byte from the Sony CDU controller, store in location pointed | ||
376 | * to by data_ptr. Return zero on success, TIME_OUT if we did not receive | ||
377 | * data. | ||
378 | ***************************************************************************/ | ||
379 | static int | ||
380 | read_result_reg(Byte *data_ptr) | ||
381 | { | ||
382 | unsigned long snap; | ||
383 | int read_status; | ||
384 | |||
385 | snap = jiffies; | ||
386 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
387 | read_status = inb(read_status_reg); | ||
388 | if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { | ||
389 | #if DEBUG > 1 | ||
390 | printk(CDU535_MESSAGE_NAME | ||
391 | ": read_result_reg(): readStatReg = 0x%x\n", read_status); | ||
392 | #endif | ||
393 | *data_ptr = inb(result_reg); | ||
394 | return 0; | ||
395 | } else { | ||
396 | sony_sleep(); | ||
397 | } | ||
398 | } | ||
399 | printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n"); | ||
400 | return TIME_OUT; | ||
401 | } | ||
402 | |||
403 | /**************************************************************************** | ||
404 | * int read_exec_status( Byte status[2] ) | ||
405 | * | ||
406 | * Read the execution status of the last command and put into status. | ||
407 | * Handles reading second status word if available. Returns 0 on success, | ||
408 | * TIME_OUT on failure. | ||
409 | ****************************************************************************/ | ||
410 | static int | ||
411 | read_exec_status(Byte status[2]) | ||
412 | { | ||
413 | status[1] = 0; | ||
414 | if (read_result_reg(&(status[0])) != 0) | ||
415 | return TIME_OUT; | ||
416 | if ((status[0] & 0x80) != 0) { /* byte two follows */ | ||
417 | if (read_result_reg(&(status[1])) != 0) | ||
418 | return TIME_OUT; | ||
419 | } | ||
420 | #if DEBUG > 1 | ||
421 | printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n", | ||
422 | status[0], status[1]); | ||
423 | #endif | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | /**************************************************************************** | ||
428 | * int check_drive_status( void ) | ||
429 | * | ||
430 | * Check the current drive status. Using this before executing a command | ||
431 | * takes care of the problem of unsolicited drive status-2 messages. | ||
432 | * Add a check of the audio status if we think the disk is playing. | ||
433 | ****************************************************************************/ | ||
434 | static int | ||
435 | check_drive_status(void) | ||
436 | { | ||
437 | Byte status, e_status[2]; | ||
438 | int CDD, ATN; | ||
439 | Byte cmd; | ||
440 | |||
441 | select_unit(0); | ||
442 | if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */ | ||
443 | outb(SONY535_REQUEST_AUDIO_STATUS, command_reg); | ||
444 | if (read_result_reg(&status) == 0) { | ||
445 | switch (status) { | ||
446 | case 0x0: | ||
447 | break; /* play in progress */ | ||
448 | case 0x1: | ||
449 | break; /* paused */ | ||
450 | case 0x3: /* audio play completed */ | ||
451 | case 0x5: /* play not requested */ | ||
452 | sony_audio_status = CDROM_AUDIO_COMPLETED; | ||
453 | read_subcode(); | ||
454 | break; | ||
455 | case 0x4: /* error during play */ | ||
456 | sony_audio_status = CDROM_AUDIO_ERROR; | ||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | /* now check drive status */ | ||
462 | outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg); | ||
463 | if (read_result_reg(&status) != 0) | ||
464 | return TIME_OUT; | ||
465 | |||
466 | #if DEBUG > 1 | ||
467 | printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status); | ||
468 | #endif | ||
469 | |||
470 | if (status == 0) | ||
471 | return 0; | ||
472 | |||
473 | ATN = status & 0xf; | ||
474 | CDD = (status >> 4) & 0xf; | ||
475 | |||
476 | switch (ATN) { | ||
477 | case 0x0: | ||
478 | break; /* go on to CDD stuff */ | ||
479 | case SONY535_ATN_BUSY: | ||
480 | if (initialized) | ||
481 | printk(CDU535_MESSAGE_NAME " error: drive busy\n"); | ||
482 | return CD_BUSY; | ||
483 | case SONY535_ATN_EJECT_IN_PROGRESS: | ||
484 | printk(CDU535_MESSAGE_NAME " error: eject in progress\n"); | ||
485 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
486 | return CD_BUSY; | ||
487 | case SONY535_ATN_RESET_OCCURRED: | ||
488 | case SONY535_ATN_DISC_CHANGED: | ||
489 | case SONY535_ATN_RESET_AND_DISC_CHANGED: | ||
490 | #if DEBUG > 0 | ||
491 | printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n"); | ||
492 | #endif | ||
493 | sony_disc_changed = 1; | ||
494 | sony_toc_read = 0; | ||
495 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
496 | sony_first_block = -1; | ||
497 | sony_last_block = -1; | ||
498 | if (initialized) { | ||
499 | cmd = SONY535_SPIN_UP; | ||
500 | do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0); | ||
501 | sony_get_toc(); | ||
502 | } | ||
503 | return 0; | ||
504 | default: | ||
505 | printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN); | ||
506 | return CD_BUSY; | ||
507 | } | ||
508 | switch (CDD) { /* the 531 docs are not helpful in decoding this */ | ||
509 | case 0x0: /* just use the values from the DOS driver */ | ||
510 | case 0x2: | ||
511 | case 0xa: | ||
512 | break; /* no error */ | ||
513 | case 0xc: | ||
514 | printk(CDU535_MESSAGE_NAME | ||
515 | ": check_drive_status(): CDD = 0xc! Not properly handled!\n"); | ||
516 | return CD_BUSY; /* ? */ | ||
517 | default: | ||
518 | return CD_BUSY; | ||
519 | } | ||
520 | return 0; | ||
521 | } /* check_drive_status() */ | ||
522 | |||
523 | /***************************************************************************** | ||
524 | * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], | ||
525 | * Byte *response, int n_response, int ignore_status_bit7 ) | ||
526 | * | ||
527 | * Generic routine for executing commands. The command and its parameters | ||
528 | * should be placed in the cmd[] array, number of bytes in the command is | ||
529 | * stored in nCmd. The response from the command will be stored in the | ||
530 | * response array. The number of bytes you expect back (excluding status) | ||
531 | * should be passed in n_response. Finally, some | ||
532 | * commands set bit 7 of the return status even when there is no second | ||
533 | * status byte, on these commands set ignoreStatusBit7 TRUE. | ||
534 | * If the command was sent and data received back, then we return 0, | ||
535 | * else we return TIME_OUT. You still have to check the status yourself. | ||
536 | * You should call check_drive_status() before calling this routine | ||
537 | * so that you do not lose notifications of disk changes, etc. | ||
538 | ****************************************************************************/ | ||
539 | static int | ||
540 | do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2], | ||
541 | Byte * response, int n_response, int ignore_status_bit7) | ||
542 | { | ||
543 | int i; | ||
544 | |||
545 | /* write out the command */ | ||
546 | for (i = 0; i < n_cmd; i++) | ||
547 | outb(cmd[i], command_reg); | ||
548 | |||
549 | /* read back the status */ | ||
550 | if (read_result_reg(status) != 0) | ||
551 | return TIME_OUT; | ||
552 | if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) { | ||
553 | /* get second status byte */ | ||
554 | if (read_result_reg(status + 1) != 0) | ||
555 | return TIME_OUT; | ||
556 | } else { | ||
557 | status[1] = 0; | ||
558 | } | ||
559 | #if DEBUG > 2 | ||
560 | printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n", | ||
561 | *cmd, status[0], status[1]); | ||
562 | #endif | ||
563 | |||
564 | /* do not know about when I should read set of data and when not to */ | ||
565 | if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0) | ||
566 | return 0; | ||
567 | |||
568 | /* else, read in rest of data */ | ||
569 | for (i = 0; 0 < n_response; n_response--, i++) | ||
570 | if (read_result_reg(response + i) != 0) | ||
571 | return TIME_OUT; | ||
572 | return 0; | ||
573 | } /* do_sony_cmd() */ | ||
574 | |||
575 | /************************************************************************** | ||
576 | * int set_drive_mode( int mode, Byte status[2] ) | ||
577 | * | ||
578 | * Set the drive mode to the specified value (mode=0 is audio, mode=e0 | ||
579 | * is mode-1 CDROM | ||
580 | **************************************************************************/ | ||
581 | static int | ||
582 | set_drive_mode(int mode, Byte status[2]) | ||
583 | { | ||
584 | Byte cmd_buff[2]; | ||
585 | Byte ret_buff[1]; | ||
586 | |||
587 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | ||
588 | cmd_buff[1] = mode; | ||
589 | return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1); | ||
590 | } | ||
591 | |||
592 | /*************************************************************************** | ||
593 | * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], | ||
594 | * Byte *data_buff, int buff_size ) | ||
595 | * | ||
596 | * Read n_blocks of data from the CDROM starting at position params[0:2], | ||
597 | * number of blocks in stored in params[3:5] -- both these are already | ||
598 | * int bcd format. | ||
599 | * Transfer the data into the buffer pointed at by data_buff. buff_size | ||
600 | * gives the number of bytes available in the buffer. | ||
601 | * The routine returns number of bytes read in if successful, otherwise | ||
602 | * it returns one of the standard error returns. | ||
603 | ***************************************************************************/ | ||
604 | static int | ||
605 | seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], | ||
606 | Byte **buff, int buf_size) | ||
607 | { | ||
608 | Byte cmd_buff[7]; | ||
609 | int i; | ||
610 | int read_status; | ||
611 | unsigned long snap; | ||
612 | Byte *data_buff; | ||
613 | int sector_count = 0; | ||
614 | |||
615 | if (buf_size < CDU535_BLOCK_SIZE * n_blocks) | ||
616 | return NO_ROOM; | ||
617 | |||
618 | set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); | ||
619 | |||
620 | /* send command to read the data */ | ||
621 | cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1; | ||
622 | for (i = 0; i < 6; i++) | ||
623 | cmd_buff[i + 1] = params[i]; | ||
624 | for (i = 0; i < 7; i++) | ||
625 | outb(cmd_buff[i], command_reg); | ||
626 | |||
627 | /* read back the data one block at a time */ | ||
628 | while (0 < n_blocks--) { | ||
629 | /* wait for data to be ready */ | ||
630 | int data_valid = 0; | ||
631 | snap = jiffies; | ||
632 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
633 | read_status = inb(read_status_reg); | ||
634 | if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { | ||
635 | read_exec_status(status); | ||
636 | return BAD_STATUS; | ||
637 | } | ||
638 | if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { | ||
639 | /* data is ready, read it */ | ||
640 | data_buff = buff[sector_count++]; | ||
641 | for (i = 0; i < CDU535_BLOCK_SIZE; i++) | ||
642 | *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ | ||
643 | data_valid = 1; | ||
644 | break; /* exit the timeout loop */ | ||
645 | } | ||
646 | sony_sleep(); /* data not ready, sleep a while */ | ||
647 | } | ||
648 | if (!data_valid) | ||
649 | return TIME_OUT; /* if we reach this stage */ | ||
650 | } | ||
651 | |||
652 | /* read all the data, now read the status */ | ||
653 | if ((i = read_exec_status(status)) != 0) | ||
654 | return i; | ||
655 | return CDU535_BLOCK_SIZE * sector_count; | ||
656 | } /* seek_and_read_N_blocks() */ | ||
657 | |||
658 | /**************************************************************************** | ||
659 | * int request_toc_data( Byte status[2], struct s535_sony_toc *toc ) | ||
660 | * | ||
661 | * Read in the table of contents data. Converts all the bcd data | ||
662 | * into integers in the toc structure. | ||
663 | ****************************************************************************/ | ||
664 | static int | ||
665 | request_toc_data(Byte status[2], struct s535_sony_toc *toc) | ||
666 | { | ||
667 | int to_status; | ||
668 | int i, j, n_tracks, track_no; | ||
669 | int first_track_num, last_track_num; | ||
670 | Byte cmd_no = 0xb2; | ||
671 | Byte track_address_buffer[5]; | ||
672 | |||
673 | /* read the fixed portion of the table of contents */ | ||
674 | if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0) | ||
675 | return to_status; | ||
676 | |||
677 | /* convert the data into integers so we can use them */ | ||
678 | first_track_num = bcd_to_int(toc->first_track_num); | ||
679 | last_track_num = bcd_to_int(toc->last_track_num); | ||
680 | n_tracks = last_track_num - first_track_num + 1; | ||
681 | |||
682 | /* read each of the track address descriptors */ | ||
683 | for (i = 0; i < n_tracks; i++) { | ||
684 | /* read the descriptor into a temporary buffer */ | ||
685 | for (j = 0; j < 5; j++) { | ||
686 | if (read_result_reg(track_address_buffer + j) != 0) | ||
687 | return TIME_OUT; | ||
688 | if (j == 1) /* need to convert from bcd */ | ||
689 | track_no = bcd_to_int(track_address_buffer[j]); | ||
690 | } | ||
691 | /* copy the descriptor to proper location - sonycd.c just fills */ | ||
692 | memcpy(toc->tracks + i, track_address_buffer, 5); | ||
693 | } | ||
694 | return 0; | ||
695 | } /* request_toc_data() */ | ||
696 | |||
697 | /*************************************************************************** | ||
698 | * int spin_up_drive( Byte status[2] ) | ||
699 | * | ||
700 | * Spin up the drive (unless it is already spinning). | ||
701 | ***************************************************************************/ | ||
702 | static int | ||
703 | spin_up_drive(Byte status[2]) | ||
704 | { | ||
705 | Byte cmd; | ||
706 | |||
707 | /* first see if the drive is already spinning */ | ||
708 | cmd = SONY535_REQUEST_DRIVE_STATUS_1; | ||
709 | if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0) | ||
710 | return TIME_OUT; | ||
711 | if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0) | ||
712 | return 0; /* it's already spinning */ | ||
713 | |||
714 | /* otherwise, give the spin-up command */ | ||
715 | cmd = SONY535_SPIN_UP; | ||
716 | return do_sony_cmd(&cmd, 1, status, NULL, 0, 0); | ||
717 | } | ||
718 | |||
719 | /*--------------------end of SONY CDU535 very specific ---------------------*/ | ||
720 | |||
721 | /* Convert from an integer 0-99 to BCD */ | ||
722 | static inline unsigned int | ||
723 | int_to_bcd(unsigned int val) | ||
724 | { | ||
725 | int retval; | ||
726 | |||
727 | retval = (val / 10) << 4; | ||
728 | retval = retval | val % 10; | ||
729 | return retval; | ||
730 | } | ||
731 | |||
732 | |||
733 | /* Convert from BCD to an integer from 0-99 */ | ||
734 | static unsigned int | ||
735 | bcd_to_int(unsigned int bcd) | ||
736 | { | ||
737 | return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); | ||
738 | } | ||
739 | |||
740 | |||
741 | /* | ||
742 | * Convert a logical sector value (like the OS would want to use for | ||
743 | * a block device) to an MSF format. | ||
744 | */ | ||
745 | static void | ||
746 | log_to_msf(unsigned int log, Byte *msf) | ||
747 | { | ||
748 | log = log + LOG_START_OFFSET; | ||
749 | msf[0] = int_to_bcd(log / 4500); | ||
750 | log = log % 4500; | ||
751 | msf[1] = int_to_bcd(log / 75); | ||
752 | msf[2] = int_to_bcd(log % 75); | ||
753 | } | ||
754 | |||
755 | |||
756 | /* | ||
757 | * Convert an MSF format to a logical sector. | ||
758 | */ | ||
759 | static unsigned int | ||
760 | msf_to_log(Byte *msf) | ||
761 | { | ||
762 | unsigned int log; | ||
763 | |||
764 | |||
765 | log = bcd_to_int(msf[2]); | ||
766 | log += bcd_to_int(msf[1]) * 75; | ||
767 | log += bcd_to_int(msf[0]) * 4500; | ||
768 | log = log - LOG_START_OFFSET; | ||
769 | |||
770 | return log; | ||
771 | } | ||
772 | |||
773 | |||
774 | /* | ||
775 | * Take in integer size value and put it into a buffer like | ||
776 | * the drive would want to see a number-of-sector value. | ||
777 | */ | ||
778 | static void | ||
779 | size_to_buf(unsigned int size, Byte *buf) | ||
780 | { | ||
781 | buf[0] = size / 65536; | ||
782 | size = size % 65536; | ||
783 | buf[1] = size / 256; | ||
784 | buf[2] = size % 256; | ||
785 | } | ||
786 | |||
787 | |||
788 | /* | ||
789 | * The OS calls this to perform a read or write operation to the drive. | ||
790 | * Write obviously fail. Reads to a read ahead of sony_buffer_size | ||
791 | * bytes to help speed operations. This especially helps since the OS | ||
792 | * may use 1024 byte blocks and the drive uses 2048 byte blocks. Since most | ||
793 | * data access on a CD is done sequentially, this saves a lot of operations. | ||
794 | */ | ||
795 | static void | ||
796 | do_cdu535_request(request_queue_t * q) | ||
797 | { | ||
798 | struct request *req; | ||
799 | unsigned int read_size; | ||
800 | int block; | ||
801 | int nsect; | ||
802 | int copyoff; | ||
803 | int spin_up_retry; | ||
804 | Byte params[10]; | ||
805 | Byte status[2]; | ||
806 | Byte cmd[2]; | ||
807 | |||
808 | while (1) { | ||
809 | req = elv_next_request(q); | ||
810 | if (!req) | ||
811 | return; | ||
812 | |||
813 | block = req->sector; | ||
814 | nsect = req->nr_sectors; | ||
815 | if (!blk_fs_request(req)) { | ||
816 | end_request(req, 0); | ||
817 | continue; | ||
818 | } | ||
819 | if (rq_data_dir(req) == WRITE) { | ||
820 | end_request(req, 0); | ||
821 | continue; | ||
822 | } | ||
823 | /* | ||
824 | * If the block address is invalid or the request goes beyond | ||
825 | * the end of the media, return an error. | ||
826 | */ | ||
827 | if (sony_toc->lead_out_start_lba <= (block/4)) { | ||
828 | end_request(req, 0); | ||
829 | return; | ||
830 | } | ||
831 | if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { | ||
832 | end_request(req, 0); | ||
833 | return; | ||
834 | } | ||
835 | while (0 < nsect) { | ||
836 | /* | ||
837 | * If the requested sector is not currently in | ||
838 | * the read-ahead buffer, it must be read in. | ||
839 | */ | ||
840 | if ((block < sony_first_block) || (sony_last_block < block)) { | ||
841 | sony_first_block = (block / 4) * 4; | ||
842 | log_to_msf(block / 4, params); | ||
843 | |||
844 | /* | ||
845 | * If the full read-ahead would go beyond the end of the media, trim | ||
846 | * it back to read just till the end of the media. | ||
847 | */ | ||
848 | if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { | ||
849 | sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; | ||
850 | read_size = sony_toc->lead_out_start_lba - (block / 4); | ||
851 | } else { | ||
852 | sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; | ||
853 | read_size = sony_buffer_sectors; | ||
854 | } | ||
855 | size_to_buf(read_size, ¶ms[3]); | ||
856 | |||
857 | /* | ||
858 | * Read the data. If the drive was not spinning, | ||
859 | * spin it up and try some more. | ||
860 | */ | ||
861 | for (spin_up_retry=0 ;; ++spin_up_retry) { | ||
862 | /* This loop has been modified to support the Sony | ||
863 | * CDU-510/515 series, thanks to Claudio Porfiri | ||
864 | * <C.Porfiri@nisms.tei.ericsson.se>. | ||
865 | */ | ||
866 | /* | ||
867 | * This part is to deal with very slow hardware. We | ||
868 | * try at most MAX_SPINUP_RETRY times to read the same | ||
869 | * block. A check for seek_and_read_N_blocks' result is | ||
870 | * performed; if the result is wrong, the CDROM's engine | ||
871 | * is restarted and the operation is tried again. | ||
872 | */ | ||
873 | /* | ||
874 | * 1995-06-01: The system got problems when downloading | ||
875 | * from Slackware CDROM, the problem seems to be: | ||
876 | * seek_and_read_N_blocks returns BAD_STATUS and we | ||
877 | * should wait for a while before retrying, so a new | ||
878 | * part was added to discriminate the return value from | ||
879 | * seek_and_read_N_blocks for the various cases. | ||
880 | */ | ||
881 | int readStatus = seek_and_read_N_blocks(params, read_size, | ||
882 | status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); | ||
883 | if (0 <= readStatus) /* Good data; common case, placed first */ | ||
884 | break; | ||
885 | if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { | ||
886 | /* give up */ | ||
887 | if (readStatus == NO_ROOM) | ||
888 | printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); | ||
889 | else | ||
890 | printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", | ||
891 | status[0]); | ||
892 | sony_first_block = -1; | ||
893 | sony_last_block = -1; | ||
894 | end_request(req, 0); | ||
895 | return; | ||
896 | } | ||
897 | if (readStatus == BAD_STATUS) { | ||
898 | /* Sleep for a while, then retry */ | ||
899 | set_current_state(TASK_INTERRUPTIBLE); | ||
900 | spin_unlock_irq(&sonycd535_lock); | ||
901 | schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); | ||
902 | spin_lock_irq(&sonycd535_lock); | ||
903 | } | ||
904 | #if DEBUG > 0 | ||
905 | printk(CDU535_MESSAGE_NAME | ||
906 | " debug: calling spin up when reading data!\n"); | ||
907 | #endif | ||
908 | cmd[0] = SONY535_SPIN_UP; | ||
909 | do_sony_cmd(cmd, 1, status, NULL, 0, 0); | ||
910 | } | ||
911 | } | ||
912 | /* | ||
913 | * The data is in memory now, copy it to the buffer and advance to the | ||
914 | * next block to read. | ||
915 | */ | ||
916 | copyoff = block - sony_first_block; | ||
917 | memcpy(req->buffer, | ||
918 | sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); | ||
919 | |||
920 | block += 1; | ||
921 | nsect -= 1; | ||
922 | req->buffer += 512; | ||
923 | } | ||
924 | |||
925 | end_request(req, 1); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * Read the table of contents from the drive and set sony_toc_read if | ||
931 | * successful. | ||
932 | */ | ||
933 | static void | ||
934 | sony_get_toc(void) | ||
935 | { | ||
936 | Byte status[2]; | ||
937 | if (!sony_toc_read) { | ||
938 | /* do not call check_drive_status() from here since it can call this routine */ | ||
939 | if (request_toc_data(status, sony_toc) < 0) | ||
940 | return; | ||
941 | sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); | ||
942 | sony_toc_read = 1; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | |||
947 | /* | ||
948 | * Search for a specific track in the table of contents. track is | ||
949 | * passed in bcd format | ||
950 | */ | ||
951 | static int | ||
952 | find_track(int track) | ||
953 | { | ||
954 | int i; | ||
955 | int num_tracks; | ||
956 | |||
957 | |||
958 | num_tracks = bcd_to_int(sony_toc->last_track_num) - | ||
959 | bcd_to_int(sony_toc->first_track_num) + 1; | ||
960 | for (i = 0; i < num_tracks; i++) { | ||
961 | if (sony_toc->tracks[i].track == track) { | ||
962 | return i; | ||
963 | } | ||
964 | } | ||
965 | |||
966 | return -1; | ||
967 | } | ||
968 | |||
969 | /* | ||
970 | * Read the subcode and put it int last_sony_subcode for future use. | ||
971 | */ | ||
972 | static int | ||
973 | read_subcode(void) | ||
974 | { | ||
975 | Byte cmd = SONY535_REQUEST_SUB_Q_DATA; | ||
976 | Byte status[2]; | ||
977 | int dsc_status; | ||
978 | |||
979 | if (check_drive_status() != 0) | ||
980 | return -EIO; | ||
981 | |||
982 | if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode, | ||
983 | sizeof(struct s535_sony_subcode), 1)) != 0) { | ||
984 | printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n", | ||
985 | status[0], dsc_status); | ||
986 | return -EIO; | ||
987 | } | ||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | |||
992 | /* | ||
993 | * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If | ||
994 | * the drive is playing, the subchannel needs to be read (since it would be | ||
995 | * changing). If the drive is paused or completed, the subcode information has | ||
996 | * already been stored, just use that. The ioctl call wants things in decimal | ||
997 | * (not BCD), so all the conversions are done. | ||
998 | */ | ||
999 | static int | ||
1000 | sony_get_subchnl_info(void __user *arg) | ||
1001 | { | ||
1002 | struct cdrom_subchnl schi; | ||
1003 | |||
1004 | /* Get attention stuff */ | ||
1005 | if (check_drive_status() != 0) | ||
1006 | return -EIO; | ||
1007 | |||
1008 | sony_get_toc(); | ||
1009 | if (!sony_toc_read) { | ||
1010 | return -EIO; | ||
1011 | } | ||
1012 | if (copy_from_user(&schi, arg, sizeof schi)) | ||
1013 | return -EFAULT; | ||
1014 | |||
1015 | switch (sony_audio_status) { | ||
1016 | case CDROM_AUDIO_PLAY: | ||
1017 | if (read_subcode() < 0) { | ||
1018 | return -EIO; | ||
1019 | } | ||
1020 | break; | ||
1021 | |||
1022 | case CDROM_AUDIO_PAUSED: | ||
1023 | case CDROM_AUDIO_COMPLETED: | ||
1024 | break; | ||
1025 | |||
1026 | case CDROM_AUDIO_NO_STATUS: | ||
1027 | schi.cdsc_audiostatus = sony_audio_status; | ||
1028 | if (copy_to_user(arg, &schi, sizeof schi)) | ||
1029 | return -EFAULT; | ||
1030 | return 0; | ||
1031 | break; | ||
1032 | |||
1033 | case CDROM_AUDIO_INVALID: | ||
1034 | case CDROM_AUDIO_ERROR: | ||
1035 | default: | ||
1036 | return -EIO; | ||
1037 | } | ||
1038 | |||
1039 | schi.cdsc_audiostatus = sony_audio_status; | ||
1040 | schi.cdsc_adr = last_sony_subcode->address; | ||
1041 | schi.cdsc_ctrl = last_sony_subcode->control; | ||
1042 | schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); | ||
1043 | schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); | ||
1044 | if (schi.cdsc_format == CDROM_MSF) { | ||
1045 | schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); | ||
1046 | schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); | ||
1047 | schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); | ||
1048 | |||
1049 | schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); | ||
1050 | schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); | ||
1051 | schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); | ||
1052 | } else if (schi.cdsc_format == CDROM_LBA) { | ||
1053 | schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); | ||
1054 | schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); | ||
1055 | } | ||
1056 | return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0; | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | /* | ||
1061 | * The big ugly ioctl handler. | ||
1062 | */ | ||
1063 | static int | ||
1064 | cdu_ioctl(struct inode *inode, | ||
1065 | struct file *file, | ||
1066 | unsigned int cmd, | ||
1067 | unsigned long arg) | ||
1068 | { | ||
1069 | Byte status[2]; | ||
1070 | Byte cmd_buff[10], params[10]; | ||
1071 | int i; | ||
1072 | int dsc_status; | ||
1073 | void __user *argp = (void __user *)arg; | ||
1074 | |||
1075 | if (check_drive_status() != 0) | ||
1076 | return -EIO; | ||
1077 | |||
1078 | switch (cmd) { | ||
1079 | case CDROMSTART: /* Spin up the drive */ | ||
1080 | if (spin_up_drive(status) < 0) { | ||
1081 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n", | ||
1082 | status[0]); | ||
1083 | return -EIO; | ||
1084 | } | ||
1085 | return 0; | ||
1086 | break; | ||
1087 | |||
1088 | case CDROMSTOP: /* Spin down the drive */ | ||
1089 | cmd_buff[0] = SONY535_HOLD; | ||
1090 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1091 | |||
1092 | /* | ||
1093 | * Spin the drive down, ignoring the error if the disk was | ||
1094 | * already not spinning. | ||
1095 | */ | ||
1096 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | ||
1097 | cmd_buff[0] = SONY535_SPIN_DOWN; | ||
1098 | dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1099 | if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) || | ||
1100 | ((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) { | ||
1101 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n", | ||
1102 | status[0]); | ||
1103 | return -EIO; | ||
1104 | } | ||
1105 | return 0; | ||
1106 | break; | ||
1107 | |||
1108 | case CDROMPAUSE: /* Pause the drive */ | ||
1109 | cmd_buff[0] = SONY535_HOLD; /* CDU-31 driver uses AUDIO_STOP, not pause */ | ||
1110 | if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { | ||
1111 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n", | ||
1112 | status[0]); | ||
1113 | return -EIO; | ||
1114 | } | ||
1115 | /* Get the current position and save it for resuming */ | ||
1116 | if (read_subcode() < 0) { | ||
1117 | return -EIO; | ||
1118 | } | ||
1119 | cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; | ||
1120 | cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; | ||
1121 | cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; | ||
1122 | sony_audio_status = CDROM_AUDIO_PAUSED; | ||
1123 | return 0; | ||
1124 | break; | ||
1125 | |||
1126 | case CDROMRESUME: /* Start the drive after being paused */ | ||
1127 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | ||
1128 | |||
1129 | if (sony_audio_status != CDROM_AUDIO_PAUSED) { | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | spin_up_drive(status); | ||
1133 | |||
1134 | /* Start the drive at the saved position. */ | ||
1135 | cmd_buff[0] = SONY535_PLAY_AUDIO; | ||
1136 | cmd_buff[1] = 0; /* play back starting at this address */ | ||
1137 | cmd_buff[2] = cur_pos_msf[0]; | ||
1138 | cmd_buff[3] = cur_pos_msf[1]; | ||
1139 | cmd_buff[4] = cur_pos_msf[2]; | ||
1140 | cmd_buff[5] = SONY535_PLAY_AUDIO; | ||
1141 | cmd_buff[6] = 2; /* set ending address */ | ||
1142 | cmd_buff[7] = final_pos_msf[0]; | ||
1143 | cmd_buff[8] = final_pos_msf[1]; | ||
1144 | cmd_buff[9] = final_pos_msf[2]; | ||
1145 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | ||
1146 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | ||
1147 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n", | ||
1148 | status[0]); | ||
1149 | return -EIO; | ||
1150 | } | ||
1151 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
1152 | return 0; | ||
1153 | break; | ||
1154 | |||
1155 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | ||
1156 | if (copy_from_user(params, argp, 6)) | ||
1157 | return -EFAULT; | ||
1158 | spin_up_drive(status); | ||
1159 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | ||
1160 | |||
1161 | /* The parameters are given in int, must be converted */ | ||
1162 | for (i = 0; i < 3; i++) { | ||
1163 | cmd_buff[2 + i] = int_to_bcd(params[i]); | ||
1164 | cmd_buff[7 + i] = int_to_bcd(params[i + 3]); | ||
1165 | } | ||
1166 | cmd_buff[0] = SONY535_PLAY_AUDIO; | ||
1167 | cmd_buff[1] = 0; /* play back starting at this address */ | ||
1168 | /* cmd_buff[2-4] are filled in for loop above */ | ||
1169 | cmd_buff[5] = SONY535_PLAY_AUDIO; | ||
1170 | cmd_buff[6] = 2; /* set ending address */ | ||
1171 | /* cmd_buff[7-9] are filled in for loop above */ | ||
1172 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | ||
1173 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | ||
1174 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n", | ||
1175 | status[0]); | ||
1176 | return -EIO; | ||
1177 | } | ||
1178 | /* Save the final position for pauses and resumes */ | ||
1179 | final_pos_msf[0] = cmd_buff[7]; | ||
1180 | final_pos_msf[1] = cmd_buff[8]; | ||
1181 | final_pos_msf[2] = cmd_buff[9]; | ||
1182 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
1183 | return 0; | ||
1184 | break; | ||
1185 | |||
1186 | case CDROMREADTOCHDR: /* Read the table of contents header */ | ||
1187 | { | ||
1188 | struct cdrom_tochdr __user *hdr = argp; | ||
1189 | struct cdrom_tochdr loc_hdr; | ||
1190 | |||
1191 | sony_get_toc(); | ||
1192 | if (!sony_toc_read) | ||
1193 | return -EIO; | ||
1194 | loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); | ||
1195 | loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); | ||
1196 | if (copy_to_user(hdr, &loc_hdr, sizeof *hdr)) | ||
1197 | return -EFAULT; | ||
1198 | } | ||
1199 | return 0; | ||
1200 | break; | ||
1201 | |||
1202 | case CDROMREADTOCENTRY: /* Read a given table of contents entry */ | ||
1203 | { | ||
1204 | struct cdrom_tocentry __user *entry = argp; | ||
1205 | struct cdrom_tocentry loc_entry; | ||
1206 | int track_idx; | ||
1207 | Byte *msf_val = NULL; | ||
1208 | |||
1209 | sony_get_toc(); | ||
1210 | if (!sony_toc_read) { | ||
1211 | return -EIO; | ||
1212 | } | ||
1213 | |||
1214 | if (copy_from_user(&loc_entry, entry, sizeof loc_entry)) | ||
1215 | return -EFAULT; | ||
1216 | |||
1217 | /* Lead out is handled separately since it is special. */ | ||
1218 | if (loc_entry.cdte_track == CDROM_LEADOUT) { | ||
1219 | loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ; | ||
1220 | loc_entry.cdte_ctrl = sony_toc->control2; | ||
1221 | msf_val = sony_toc->lead_out_start_msf; | ||
1222 | } else { | ||
1223 | track_idx = find_track(int_to_bcd(loc_entry.cdte_track)); | ||
1224 | if (track_idx < 0) | ||
1225 | return -EINVAL; | ||
1226 | loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ; | ||
1227 | loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; | ||
1228 | msf_val = sony_toc->tracks[track_idx].track_start_msf; | ||
1229 | } | ||
1230 | |||
1231 | /* Logical buffer address or MSF format requested? */ | ||
1232 | if (loc_entry.cdte_format == CDROM_LBA) { | ||
1233 | loc_entry.cdte_addr.lba = msf_to_log(msf_val); | ||
1234 | } else if (loc_entry.cdte_format == CDROM_MSF) { | ||
1235 | loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val); | ||
1236 | loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1)); | ||
1237 | loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2)); | ||
1238 | } | ||
1239 | if (copy_to_user(entry, &loc_entry, sizeof *entry)) | ||
1240 | return -EFAULT; | ||
1241 | } | ||
1242 | return 0; | ||
1243 | break; | ||
1244 | |||
1245 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | ||
1246 | { | ||
1247 | struct cdrom_ti ti; | ||
1248 | int track_idx; | ||
1249 | |||
1250 | sony_get_toc(); | ||
1251 | if (!sony_toc_read) | ||
1252 | return -EIO; | ||
1253 | |||
1254 | if (copy_from_user(&ti, argp, sizeof ti)) | ||
1255 | return -EFAULT; | ||
1256 | if ((ti.cdti_trk0 < sony_toc->first_track_num) | ||
1257 | || (sony_toc->last_track_num < ti.cdti_trk0) | ||
1258 | || (ti.cdti_trk1 < ti.cdti_trk0)) { | ||
1259 | return -EINVAL; | ||
1260 | } | ||
1261 | track_idx = find_track(int_to_bcd(ti.cdti_trk0)); | ||
1262 | if (track_idx < 0) | ||
1263 | return -EINVAL; | ||
1264 | params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; | ||
1265 | params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; | ||
1266 | params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; | ||
1267 | /* | ||
1268 | * If we want to stop after the last track, use the lead-out | ||
1269 | * MSF to do that. | ||
1270 | */ | ||
1271 | if (bcd_to_int(sony_toc->last_track_num) <= ti.cdti_trk1) { | ||
1272 | log_to_msf(msf_to_log(sony_toc->lead_out_start_msf) - 1, | ||
1273 | &(params[4])); | ||
1274 | } else { | ||
1275 | track_idx = find_track(int_to_bcd(ti.cdti_trk1 + 1)); | ||
1276 | if (track_idx < 0) | ||
1277 | return -EINVAL; | ||
1278 | log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf) - 1, | ||
1279 | &(params[4])); | ||
1280 | } | ||
1281 | params[0] = 0x03; | ||
1282 | |||
1283 | spin_up_drive(status); | ||
1284 | |||
1285 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | ||
1286 | |||
1287 | /* Start the drive at the saved position. */ | ||
1288 | cmd_buff[0] = SONY535_PLAY_AUDIO; | ||
1289 | cmd_buff[1] = 0; /* play back starting at this address */ | ||
1290 | cmd_buff[2] = params[1]; | ||
1291 | cmd_buff[3] = params[2]; | ||
1292 | cmd_buff[4] = params[3]; | ||
1293 | cmd_buff[5] = SONY535_PLAY_AUDIO; | ||
1294 | cmd_buff[6] = 2; /* set ending address */ | ||
1295 | cmd_buff[7] = params[4]; | ||
1296 | cmd_buff[8] = params[5]; | ||
1297 | cmd_buff[9] = params[6]; | ||
1298 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | ||
1299 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | ||
1300 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n", | ||
1301 | status[0]); | ||
1302 | printk("... Params: %x %x %x %x %x %x %x\n", | ||
1303 | params[0], params[1], params[2], | ||
1304 | params[3], params[4], params[5], params[6]); | ||
1305 | return -EIO; | ||
1306 | } | ||
1307 | /* Save the final position for pauses and resumes */ | ||
1308 | final_pos_msf[0] = params[4]; | ||
1309 | final_pos_msf[1] = params[5]; | ||
1310 | final_pos_msf[2] = params[6]; | ||
1311 | sony_audio_status = CDROM_AUDIO_PLAY; | ||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | case CDROMSUBCHNL: /* Get subchannel info */ | ||
1316 | return sony_get_subchnl_info(argp); | ||
1317 | |||
1318 | case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ | ||
1319 | { | ||
1320 | struct cdrom_volctrl volctrl; | ||
1321 | |||
1322 | if (copy_from_user(&volctrl, argp, sizeof volctrl)) | ||
1323 | return -EFAULT; | ||
1324 | cmd_buff[0] = SONY535_SET_VOLUME; | ||
1325 | cmd_buff[1] = volctrl.channel0; | ||
1326 | cmd_buff[2] = volctrl.channel1; | ||
1327 | if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) { | ||
1328 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n", | ||
1329 | status[0]); | ||
1330 | return -EIO; | ||
1331 | } | ||
1332 | } | ||
1333 | return 0; | ||
1334 | |||
1335 | case CDROMEJECT: /* Eject the drive */ | ||
1336 | cmd_buff[0] = SONY535_STOP; | ||
1337 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1338 | cmd_buff[0] = SONY535_SPIN_DOWN; | ||
1339 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1340 | |||
1341 | sony_audio_status = CDROM_AUDIO_INVALID; | ||
1342 | cmd_buff[0] = SONY535_EJECT_CADDY; | ||
1343 | if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { | ||
1344 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n", | ||
1345 | status[0]); | ||
1346 | return -EIO; | ||
1347 | } | ||
1348 | return 0; | ||
1349 | break; | ||
1350 | |||
1351 | default: | ||
1352 | return -EINVAL; | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | |||
1357 | /* | ||
1358 | * Open the drive for operations. Spin the drive up and read the table of | ||
1359 | * contents if these have not already been done. | ||
1360 | */ | ||
1361 | static int | ||
1362 | cdu_open(struct inode *inode, | ||
1363 | struct file *filp) | ||
1364 | { | ||
1365 | Byte status[2], cmd_buff[2]; | ||
1366 | |||
1367 | if (sony_inuse) | ||
1368 | return -EBUSY; | ||
1369 | if (check_drive_status() != 0) | ||
1370 | return -EIO; | ||
1371 | sony_inuse = 1; | ||
1372 | |||
1373 | if (spin_up_drive(status) != 0) { | ||
1374 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n", | ||
1375 | status[0]); | ||
1376 | sony_inuse = 0; | ||
1377 | return -EIO; | ||
1378 | } | ||
1379 | sony_get_toc(); | ||
1380 | if (!sony_toc_read) { | ||
1381 | cmd_buff[0] = SONY535_SPIN_DOWN; | ||
1382 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1383 | sony_inuse = 0; | ||
1384 | return -EIO; | ||
1385 | } | ||
1386 | check_disk_change(inode->i_bdev); | ||
1387 | sony_usage++; | ||
1388 | |||
1389 | #ifdef LOCK_DOORS | ||
1390 | /* disable the eject button while mounted */ | ||
1391 | cmd_buff[0] = SONY535_DISABLE_EJECT_BUTTON; | ||
1392 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | ||
1393 | #endif | ||
1394 | |||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | |||
1399 | /* | ||
1400 | * Close the drive. Spin it down if no task is using it. The spin | ||
1401 | * down will fail if playing audio, so audio play is OK. | ||
1402 | */ | ||
1403 | static int | ||
1404 | cdu_release(struct inode *inode, | ||
1405 | struct file *filp) | ||
1406 | { | ||
1407 | Byte status[2], cmd_no; | ||
1408 | |||
1409 | sony_inuse = 0; | ||
1410 | |||
1411 | if (0 < sony_usage) { | ||
1412 | sony_usage--; | ||
1413 | } | ||
1414 | if (sony_usage == 0) { | ||
1415 | check_drive_status(); | ||
1416 | |||
1417 | if (sony_audio_status != CDROM_AUDIO_PLAY) { | ||
1418 | cmd_no = SONY535_SPIN_DOWN; | ||
1419 | do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); | ||
1420 | } | ||
1421 | #ifdef LOCK_DOORS | ||
1422 | /* enable the eject button after umount */ | ||
1423 | cmd_no = SONY535_ENABLE_EJECT_BUTTON; | ||
1424 | do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); | ||
1425 | #endif | ||
1426 | } | ||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static struct block_device_operations cdu_fops = | ||
1431 | { | ||
1432 | .owner = THIS_MODULE, | ||
1433 | .open = cdu_open, | ||
1434 | .release = cdu_release, | ||
1435 | .ioctl = cdu_ioctl, | ||
1436 | .media_changed = cdu535_check_media_change, | ||
1437 | }; | ||
1438 | |||
1439 | static struct gendisk *cdu_disk; | ||
1440 | |||
1441 | /* | ||
1442 | * Initialize the driver. | ||
1443 | */ | ||
1444 | static int __init sony535_init(void) | ||
1445 | { | ||
1446 | struct s535_sony_drive_config drive_config; | ||
1447 | Byte cmd_buff[3]; | ||
1448 | Byte ret_buff[2]; | ||
1449 | Byte status[2]; | ||
1450 | unsigned long snap; | ||
1451 | int got_result = 0; | ||
1452 | int tmp_irq; | ||
1453 | int i; | ||
1454 | int err; | ||
1455 | |||
1456 | /* Setting the base I/O address to 0 will disable it. */ | ||
1457 | if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) | ||
1458 | return 0; | ||
1459 | |||
1460 | /* Set up all the register locations */ | ||
1461 | result_reg = sony535_cd_base_io; | ||
1462 | command_reg = sony535_cd_base_io; | ||
1463 | data_reg = sony535_cd_base_io + 1; | ||
1464 | read_status_reg = sony535_cd_base_io + 2; | ||
1465 | select_unit_reg = sony535_cd_base_io + 3; | ||
1466 | |||
1467 | #ifndef USE_IRQ | ||
1468 | sony535_irq_used = 0; /* polling only until this is ready... */ | ||
1469 | #endif | ||
1470 | /* we need to poll until things get initialized */ | ||
1471 | tmp_irq = sony535_irq_used; | ||
1472 | sony535_irq_used = 0; | ||
1473 | |||
1474 | #if DEBUG > 0 | ||
1475 | printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n", | ||
1476 | sony535_cd_base_io); | ||
1477 | #endif | ||
1478 | /* look for the CD-ROM, follows the procedure in the DOS driver */ | ||
1479 | inb(select_unit_reg); | ||
1480 | /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ | ||
1481 | set_current_state(TASK_INTERRUPTIBLE); | ||
1482 | schedule_timeout((HZ+17)*40/18); | ||
1483 | inb(result_reg); | ||
1484 | |||
1485 | outb(0, read_status_reg); /* does a reset? */ | ||
1486 | snap = jiffies; | ||
1487 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
1488 | select_unit(0); | ||
1489 | if (inb(result_reg) != 0xff) { | ||
1490 | got_result = 1; | ||
1491 | break; | ||
1492 | } | ||
1493 | sony_sleep(); | ||
1494 | } | ||
1495 | |||
1496 | if (!got_result || check_drive_status() == TIME_OUT) | ||
1497 | goto Enodev; | ||
1498 | |||
1499 | /* CD-ROM drive responded -- get the drive configuration */ | ||
1500 | cmd_buff[0] = SONY535_INQUIRY; | ||
1501 | if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0) | ||
1502 | goto Enodev; | ||
1503 | |||
1504 | /* was able to get the configuration, | ||
1505 | * set drive mode as rest of init | ||
1506 | */ | ||
1507 | #if DEBUG > 0 | ||
1508 | /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ | ||
1509 | if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) | ||
1510 | printk(CDU535_MESSAGE_NAME | ||
1511 | "Inquiry command returned status = 0x%x\n", status[0]); | ||
1512 | #endif | ||
1513 | /* now ready to use interrupts, if available */ | ||
1514 | sony535_irq_used = tmp_irq; | ||
1515 | |||
1516 | /* A negative sony535_irq_used will attempt an autoirq. */ | ||
1517 | if (sony535_irq_used < 0) { | ||
1518 | unsigned long irq_mask, delay; | ||
1519 | |||
1520 | irq_mask = probe_irq_on(); | ||
1521 | enable_interrupts(); | ||
1522 | outb(0, read_status_reg); /* does a reset? */ | ||
1523 | delay = jiffies + HZ/10; | ||
1524 | while (time_before(jiffies, delay)) ; | ||
1525 | |||
1526 | sony535_irq_used = probe_irq_off(irq_mask); | ||
1527 | disable_interrupts(); | ||
1528 | } | ||
1529 | if (sony535_irq_used > 0) { | ||
1530 | if (request_irq(sony535_irq_used, cdu535_interrupt, | ||
1531 | SA_INTERRUPT, CDU535_HANDLE, NULL)) { | ||
1532 | printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME | ||
1533 | " driver; polling instead.\n", sony535_irq_used); | ||
1534 | sony535_irq_used = 0; | ||
1535 | } | ||
1536 | } | ||
1537 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | ||
1538 | cmd_buff[1] = 0x0; /* default audio */ | ||
1539 | if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0) | ||
1540 | goto Enodev_irq; | ||
1541 | |||
1542 | /* set the drive mode successful, we are set! */ | ||
1543 | sony_buffer_size = SONY535_BUFFER_SIZE; | ||
1544 | sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; | ||
1545 | |||
1546 | printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", | ||
1547 | drive_config.vendor_id, | ||
1548 | drive_config.product_id, | ||
1549 | drive_config.product_rev_level); | ||
1550 | printk(" base address %03X, ", sony535_cd_base_io); | ||
1551 | if (tmp_irq > 0) | ||
1552 | printk("IRQ%d, ", tmp_irq); | ||
1553 | printk("using %d byte buffer\n", sony_buffer_size); | ||
1554 | |||
1555 | if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) { | ||
1556 | err = -EIO; | ||
1557 | goto out1; | ||
1558 | } | ||
1559 | sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock); | ||
1560 | if (!sonycd535_queue) { | ||
1561 | err = -ENOMEM; | ||
1562 | goto out1a; | ||
1563 | } | ||
1564 | |||
1565 | blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE); | ||
1566 | sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); | ||
1567 | err = -ENOMEM; | ||
1568 | if (!sony_toc) | ||
1569 | goto out2; | ||
1570 | last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL); | ||
1571 | if (!last_sony_subcode) | ||
1572 | goto out3; | ||
1573 | sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL); | ||
1574 | if (!sony_buffer) | ||
1575 | goto out4; | ||
1576 | for (i = 0; i < sony_buffer_sectors; i++) { | ||
1577 | sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); | ||
1578 | if (!sony_buffer[i]) { | ||
1579 | while (--i>=0) | ||
1580 | kfree(sony_buffer[i]); | ||
1581 | goto out5; | ||
1582 | } | ||
1583 | } | ||
1584 | initialized = 1; | ||
1585 | |||
1586 | cdu_disk = alloc_disk(1); | ||
1587 | if (!cdu_disk) | ||
1588 | goto out6; | ||
1589 | cdu_disk->major = MAJOR_NR; | ||
1590 | cdu_disk->first_minor = 0; | ||
1591 | cdu_disk->fops = &cdu_fops; | ||
1592 | sprintf(cdu_disk->disk_name, "cdu"); | ||
1593 | sprintf(cdu_disk->devfs_name, "cdu535"); | ||
1594 | |||
1595 | if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { | ||
1596 | printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", | ||
1597 | sony535_cd_base_io); | ||
1598 | goto out7; | ||
1599 | } | ||
1600 | cdu_disk->queue = sonycd535_queue; | ||
1601 | add_disk(cdu_disk); | ||
1602 | return 0; | ||
1603 | |||
1604 | out7: | ||
1605 | put_disk(cdu_disk); | ||
1606 | out6: | ||
1607 | for (i = 0; i < sony_buffer_sectors; i++) | ||
1608 | if (sony_buffer[i]) | ||
1609 | kfree(sony_buffer[i]); | ||
1610 | out5: | ||
1611 | kfree(sony_buffer); | ||
1612 | out4: | ||
1613 | kfree(last_sony_subcode); | ||
1614 | out3: | ||
1615 | kfree(sony_toc); | ||
1616 | out2: | ||
1617 | blk_cleanup_queue(sonycd535_queue); | ||
1618 | out1a: | ||
1619 | unregister_blkdev(MAJOR_NR, CDU535_HANDLE); | ||
1620 | out1: | ||
1621 | if (sony535_irq_used) | ||
1622 | free_irq(sony535_irq_used, NULL); | ||
1623 | return err; | ||
1624 | Enodev_irq: | ||
1625 | if (sony535_irq_used) | ||
1626 | free_irq(sony535_irq_used, NULL); | ||
1627 | Enodev: | ||
1628 | printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); | ||
1629 | return -EIO; | ||
1630 | } | ||
1631 | |||
1632 | #ifndef MODULE | ||
1633 | |||
1634 | /* | ||
1635 | * accept "kernel command line" parameters | ||
1636 | * (added by emoenke@gwdg.de) | ||
1637 | * | ||
1638 | * use: tell LILO: | ||
1639 | * sonycd535=0x320 | ||
1640 | * | ||
1641 | * the address value has to be the existing CDROM port address. | ||
1642 | */ | ||
1643 | static int __init | ||
1644 | sonycd535_setup(char *strings) | ||
1645 | { | ||
1646 | int ints[3]; | ||
1647 | (void)get_options(strings, ARRAY_SIZE(ints), ints); | ||
1648 | /* if IRQ change and default io base desired, | ||
1649 | * then call with io base of 0 | ||
1650 | */ | ||
1651 | if (ints[0] > 0) | ||
1652 | if (ints[1] != 0) | ||
1653 | sony535_cd_base_io = ints[1]; | ||
1654 | if (ints[0] > 1) | ||
1655 | sony535_irq_used = ints[2]; | ||
1656 | if ((strings != NULL) && (*strings != '\0')) | ||
1657 | printk(CDU535_MESSAGE_NAME | ||
1658 | ": Warning: Unknown interface type: %s\n", strings); | ||
1659 | |||
1660 | return 1; | ||
1661 | } | ||
1662 | |||
1663 | __setup("sonycd535=", sonycd535_setup); | ||
1664 | |||
1665 | #endif /* MODULE */ | ||
1666 | |||
1667 | static void __exit | ||
1668 | sony535_exit(void) | ||
1669 | { | ||
1670 | int i; | ||
1671 | |||
1672 | release_region(sony535_cd_base_io, 4); | ||
1673 | for (i = 0; i < sony_buffer_sectors; i++) | ||
1674 | kfree(sony_buffer[i]); | ||
1675 | kfree(sony_buffer); | ||
1676 | kfree(last_sony_subcode); | ||
1677 | kfree(sony_toc); | ||
1678 | del_gendisk(cdu_disk); | ||
1679 | put_disk(cdu_disk); | ||
1680 | blk_cleanup_queue(sonycd535_queue); | ||
1681 | if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) | ||
1682 | printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); | ||
1683 | else | ||
1684 | printk(KERN_INFO CDU535_HANDLE " module released\n"); | ||
1685 | } | ||
1686 | |||
1687 | module_init(sony535_init); | ||
1688 | module_exit(sony535_exit); | ||
1689 | |||
1690 | |||
1691 | MODULE_LICENSE("GPL"); | ||
1692 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); | ||
diff --git a/drivers/cdrom/sonycd535.h b/drivers/cdrom/sonycd535.h new file mode 100644 index 000000000000..5dea1ef168d6 --- /dev/null +++ b/drivers/cdrom/sonycd535.h | |||
@@ -0,0 +1,183 @@ | |||
1 | #ifndef SONYCD535_H | ||
2 | #define SONYCD535_H | ||
3 | |||
4 | /* | ||
5 | * define all the commands recognized by the CDU-531/5 | ||
6 | */ | ||
7 | #define SONY535_REQUEST_DRIVE_STATUS_1 (0x80) | ||
8 | #define SONY535_REQUEST_SENSE (0x82) | ||
9 | #define SONY535_REQUEST_DRIVE_STATUS_2 (0x84) | ||
10 | #define SONY535_REQUEST_ERROR_STATUS (0x86) | ||
11 | #define SONY535_REQUEST_AUDIO_STATUS (0x88) | ||
12 | #define SONY535_INQUIRY (0x8a) | ||
13 | |||
14 | #define SONY535_SET_INACTIVITY_TIME (0x90) | ||
15 | |||
16 | #define SONY535_SEEK_AND_READ_N_BLOCKS_1 (0xa0) | ||
17 | #define SONY535_SEEK_AND_READ_N_BLOCKS_2 (0xa4) | ||
18 | #define SONY535_PLAY_AUDIO (0xa6) | ||
19 | |||
20 | #define SONY535_REQUEST_DISC_CAPACITY (0xb0) | ||
21 | #define SONY535_REQUEST_TOC_DATA (0xb2) | ||
22 | #define SONY535_REQUEST_SUB_Q_DATA (0xb4) | ||
23 | #define SONY535_REQUEST_ISRC (0xb6) | ||
24 | #define SONY535_REQUEST_UPC_EAN (0xb8) | ||
25 | |||
26 | #define SONY535_SET_DRIVE_MODE (0xc0) | ||
27 | #define SONY535_REQUEST_DRIVE_MODE (0xc2) | ||
28 | #define SONY535_SET_RETRY_COUNT (0xc4) | ||
29 | |||
30 | #define SONY535_DIAGNOSTIC_1 (0xc6) | ||
31 | #define SONY535_DIAGNOSTIC_4 (0xcc) | ||
32 | #define SONY535_DIAGNOSTIC_5 (0xce) | ||
33 | |||
34 | #define SONY535_EJECT_CADDY (0xd0) | ||
35 | #define SONY535_DISABLE_EJECT_BUTTON (0xd2) | ||
36 | #define SONY535_ENABLE_EJECT_BUTTON (0xd4) | ||
37 | |||
38 | #define SONY535_HOLD (0xe0) | ||
39 | #define SONY535_AUDIO_PAUSE_ON_OFF (0xe2) | ||
40 | #define SONY535_SET_VOLUME (0xe8) | ||
41 | |||
42 | #define SONY535_STOP (0xf0) | ||
43 | #define SONY535_SPIN_UP (0xf2) | ||
44 | #define SONY535_SPIN_DOWN (0xf4) | ||
45 | |||
46 | #define SONY535_CLEAR_PARAMETERS (0xf6) | ||
47 | #define SONY535_CLEAR_ENDING_ADDRESS (0xf8) | ||
48 | |||
49 | /* | ||
50 | * define some masks | ||
51 | */ | ||
52 | #define SONY535_DATA_NOT_READY_BIT (0x1) | ||
53 | #define SONY535_RESULT_NOT_READY_BIT (0x2) | ||
54 | |||
55 | /* | ||
56 | * drive status 1 | ||
57 | */ | ||
58 | #define SONY535_STATUS1_COMMAND_ERROR (0x1) | ||
59 | #define SONY535_STATUS1_DATA_ERROR (0x2) | ||
60 | #define SONY535_STATUS1_SEEK_ERROR (0x4) | ||
61 | #define SONY535_STATUS1_DISC_TYPE_ERROR (0x8) | ||
62 | #define SONY535_STATUS1_NOT_SPINNING (0x10) | ||
63 | #define SONY535_STATUS1_EJECT_BUTTON_PRESSED (0x20) | ||
64 | #define SONY535_STATUS1_CADDY_NOT_INSERTED (0x40) | ||
65 | #define SONY535_STATUS1_BYTE_TWO_FOLLOWS (0x80) | ||
66 | |||
67 | /* | ||
68 | * drive status 2 | ||
69 | */ | ||
70 | #define SONY535_CDD_LOADING_ERROR (0x7) | ||
71 | #define SONY535_CDD_NO_DISC (0x8) | ||
72 | #define SONY535_CDD_UNLOADING_ERROR (0x9) | ||
73 | #define SONY535_CDD_CADDY_NOT_INSERTED (0xd) | ||
74 | #define SONY535_ATN_RESET_OCCURRED (0x2) | ||
75 | #define SONY535_ATN_DISC_CHANGED (0x4) | ||
76 | #define SONY535_ATN_RESET_AND_DISC_CHANGED (0x6) | ||
77 | #define SONY535_ATN_EJECT_IN_PROGRESS (0xe) | ||
78 | #define SONY535_ATN_BUSY (0xf) | ||
79 | |||
80 | /* | ||
81 | * define some parameters | ||
82 | */ | ||
83 | #define SONY535_AUDIO_DRIVE_MODE (0) | ||
84 | #define SONY535_CDROM_DRIVE_MODE (0xe0) | ||
85 | |||
86 | #define SONY535_PLAY_OP_PLAYBACK (0) | ||
87 | #define SONY535_PLAY_OP_ENTER_HOLD (1) | ||
88 | #define SONY535_PLAY_OP_SET_AUDIO_ENDING_ADDR (2) | ||
89 | #define SONY535_PLAY_OP_SCAN_FORWARD (3) | ||
90 | #define SONY535_PLAY_OP_SCAN_BACKWARD (4) | ||
91 | |||
92 | /* | ||
93 | * convert from msf format to block number | ||
94 | */ | ||
95 | #define SONY_BLOCK_NUMBER(m,s,f) (((m)*60L+(s))*75L+(f)) | ||
96 | #define SONY_BLOCK_NUMBER_MSF(x) (((x)[0]*60L+(x)[1])*75L+(x)[2]) | ||
97 | |||
98 | /* | ||
99 | * error return values from the doSonyCmd() routines | ||
100 | */ | ||
101 | #define TIME_OUT (-1) | ||
102 | #define NO_CDROM (-2) | ||
103 | #define BAD_STATUS (-3) | ||
104 | #define CD_BUSY (-4) | ||
105 | #define NOT_DATA_CD (-5) | ||
106 | #define NO_ROOM (-6) | ||
107 | |||
108 | #define LOG_START_OFFSET 150 /* Offset of first logical sector */ | ||
109 | |||
110 | #define SONY_JIFFIES_TIMEOUT (5*HZ) /* Maximum time | ||
111 | the drive will wait/try for an | ||
112 | operation */ | ||
113 | #define SONY_READY_RETRIES (50000) /* How many times to retry a | ||
114 | spin waiting for a register | ||
115 | to come ready */ | ||
116 | #define SONY535_FAST_POLLS (10000) /* how many times recheck | ||
117 | status waiting for a data | ||
118 | to become ready */ | ||
119 | |||
120 | typedef unsigned char Byte; | ||
121 | |||
122 | /* | ||
123 | * This is the complete status returned from the drive configuration request | ||
124 | * command. | ||
125 | */ | ||
126 | struct s535_sony_drive_config | ||
127 | { | ||
128 | char vendor_id[8]; | ||
129 | char product_id[16]; | ||
130 | char product_rev_level[4]; | ||
131 | }; | ||
132 | |||
133 | /* The following is returned from the request sub-q data command */ | ||
134 | struct s535_sony_subcode | ||
135 | { | ||
136 | unsigned char address :4; | ||
137 | unsigned char control :4; | ||
138 | unsigned char track_num; | ||
139 | unsigned char index_num; | ||
140 | unsigned char rel_msf[3]; | ||
141 | unsigned char abs_msf[3]; | ||
142 | }; | ||
143 | |||
144 | struct s535_sony_disc_capacity | ||
145 | { | ||
146 | Byte mFirstTrack, sFirstTrack, fFirstTrack; | ||
147 | Byte mLeadOut, sLeadOut, fLeadOut; | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * The following is returned from the request TOC (Table Of Contents) command. | ||
152 | * (last_track_num-first_track_num+1) values are valid in tracks. | ||
153 | */ | ||
154 | struct s535_sony_toc | ||
155 | { | ||
156 | unsigned char reserved0 :4; | ||
157 | unsigned char control0 :4; | ||
158 | unsigned char point0; | ||
159 | unsigned char first_track_num; | ||
160 | unsigned char reserved0a; | ||
161 | unsigned char reserved0b; | ||
162 | unsigned char reserved1 :4; | ||
163 | unsigned char control1 :4; | ||
164 | unsigned char point1; | ||
165 | unsigned char last_track_num; | ||
166 | unsigned char dummy1; | ||
167 | unsigned char dummy2; | ||
168 | unsigned char reserved2 :4; | ||
169 | unsigned char control2 :4; | ||
170 | unsigned char point2; | ||
171 | unsigned char lead_out_start_msf[3]; | ||
172 | struct | ||
173 | { | ||
174 | unsigned char reserved :4; | ||
175 | unsigned char control :4; | ||
176 | unsigned char track; | ||
177 | unsigned char track_start_msf[3]; | ||
178 | } tracks[100]; | ||
179 | |||
180 | unsigned int lead_out_start_lba; | ||
181 | }; | ||
182 | |||
183 | #endif /* SONYCD535_H */ | ||
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c new file mode 100644 index 000000000000..fcca26c89bbc --- /dev/null +++ b/drivers/cdrom/viocd.c | |||
@@ -0,0 +1,809 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * drivers/cdrom/viocd.c | ||
3 | * | ||
4 | * iSeries Virtual CD Rom | ||
5 | * | ||
6 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
7 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
8 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
9 | * Stephen Rothwell <sfr@au1.ibm.com> | ||
10 | * | ||
11 | * (C) Copyright 2000-2004 IBM Corporation | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation; either version 2 of the | ||
16 | * License, or (at your option) anyu later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software Foundation, | ||
25 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * This routine provides access to CD ROM drives owned and managed by an | ||
28 | * OS/400 partition running on the same box as this Linux partition. | ||
29 | * | ||
30 | * All operations are performed by sending messages back and forth to | ||
31 | * the OS/400 partition. | ||
32 | */ | ||
33 | |||
34 | #include <linux/major.h> | ||
35 | #include <linux/blkdev.h> | ||
36 | #include <linux/cdrom.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/dma-mapping.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/completion.h> | ||
42 | #include <linux/proc_fs.h> | ||
43 | #include <linux/seq_file.h> | ||
44 | |||
45 | #include <asm/bug.h> | ||
46 | |||
47 | #include <asm/vio.h> | ||
48 | #include <asm/scatterlist.h> | ||
49 | #include <asm/iSeries/HvTypes.h> | ||
50 | #include <asm/iSeries/HvLpEvent.h> | ||
51 | #include <asm/iSeries/vio.h> | ||
52 | |||
53 | #define VIOCD_DEVICE "iseries/vcd" | ||
54 | #define VIOCD_DEVICE_DEVFS "iseries/vcd" | ||
55 | |||
56 | #define VIOCD_VERS "1.06" | ||
57 | |||
58 | #define VIOCD_KERN_WARNING KERN_WARNING "viocd: " | ||
59 | #define VIOCD_KERN_INFO KERN_INFO "viocd: " | ||
60 | |||
61 | struct viocdlpevent { | ||
62 | struct HvLpEvent event; | ||
63 | u32 reserved; | ||
64 | u16 version; | ||
65 | u16 sub_result; | ||
66 | u16 disk; | ||
67 | u16 flags; | ||
68 | u32 token; | ||
69 | u64 offset; /* On open, max number of disks */ | ||
70 | u64 len; /* On open, size of the disk */ | ||
71 | u32 block_size; /* Only set on open */ | ||
72 | u32 media_size; /* Only set on open */ | ||
73 | }; | ||
74 | |||
75 | enum viocdsubtype { | ||
76 | viocdopen = 0x0001, | ||
77 | viocdclose = 0x0002, | ||
78 | viocdread = 0x0003, | ||
79 | viocdwrite = 0x0004, | ||
80 | viocdlockdoor = 0x0005, | ||
81 | viocdgetinfo = 0x0006, | ||
82 | viocdcheck = 0x0007 | ||
83 | }; | ||
84 | |||
85 | /* | ||
86 | * Should probably make this a module parameter....sigh | ||
87 | */ | ||
88 | #define VIOCD_MAX_CD HVMAXARCHITECTEDVIRTUALCDROMS | ||
89 | |||
90 | static const struct vio_error_entry viocd_err_table[] = { | ||
91 | {0x0201, EINVAL, "Invalid Range"}, | ||
92 | {0x0202, EINVAL, "Invalid Token"}, | ||
93 | {0x0203, EIO, "DMA Error"}, | ||
94 | {0x0204, EIO, "Use Error"}, | ||
95 | {0x0205, EIO, "Release Error"}, | ||
96 | {0x0206, EINVAL, "Invalid CD"}, | ||
97 | {0x020C, EROFS, "Read Only Device"}, | ||
98 | {0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"}, | ||
99 | {0x020E, EIO, "Optical System Error (Varied Off?)"}, | ||
100 | {0x02FF, EIO, "Internal Error"}, | ||
101 | {0x3010, EIO, "Changed Volume"}, | ||
102 | {0xC100, EIO, "Optical System Error"}, | ||
103 | {0x0000, 0, NULL}, | ||
104 | }; | ||
105 | |||
106 | /* | ||
107 | * This is the structure we use to exchange info between driver and interrupt | ||
108 | * handler | ||
109 | */ | ||
110 | struct viocd_waitevent { | ||
111 | struct completion com; | ||
112 | int rc; | ||
113 | u16 sub_result; | ||
114 | int changed; | ||
115 | }; | ||
116 | |||
117 | /* this is a lookup table for the true capabilities of a device */ | ||
118 | struct capability_entry { | ||
119 | char *type; | ||
120 | int capability; | ||
121 | }; | ||
122 | |||
123 | static struct capability_entry capability_table[] __initdata = { | ||
124 | { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
125 | { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
126 | { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
127 | { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
128 | { "6321", CDC_LOCK }, | ||
129 | { "632B", 0 }, | ||
130 | { NULL , CDC_LOCK }, | ||
131 | }; | ||
132 | |||
133 | /* These are our internal structures for keeping track of devices */ | ||
134 | static int viocd_numdev; | ||
135 | |||
136 | struct cdrom_info { | ||
137 | char rsrcname[10]; | ||
138 | char type[4]; | ||
139 | char model[3]; | ||
140 | }; | ||
141 | /* | ||
142 | * This needs to be allocated since it is passed to the | ||
143 | * Hypervisor and we may be a module. | ||
144 | */ | ||
145 | static struct cdrom_info *viocd_unitinfo; | ||
146 | static dma_addr_t unitinfo_dmaaddr; | ||
147 | |||
148 | struct disk_info { | ||
149 | struct gendisk *viocd_disk; | ||
150 | struct cdrom_device_info viocd_info; | ||
151 | struct device *dev; | ||
152 | }; | ||
153 | static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; | ||
154 | |||
155 | #define DEVICE_NR(di) ((di) - &viocd_diskinfo[0]) | ||
156 | |||
157 | static spinlock_t viocd_reqlock; | ||
158 | |||
159 | #define MAX_CD_REQ 1 | ||
160 | |||
161 | /* procfs support */ | ||
162 | static int proc_viocd_show(struct seq_file *m, void *v) | ||
163 | { | ||
164 | int i; | ||
165 | |||
166 | for (i = 0; i < viocd_numdev; i++) { | ||
167 | seq_printf(m, "viocd device %d is iSeries resource %10.10s" | ||
168 | "type %4.4s, model %3.3s\n", | ||
169 | i, viocd_unitinfo[i].rsrcname, | ||
170 | viocd_unitinfo[i].type, | ||
171 | viocd_unitinfo[i].model); | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int proc_viocd_open(struct inode *inode, struct file *file) | ||
177 | { | ||
178 | return single_open(file, proc_viocd_show, NULL); | ||
179 | } | ||
180 | |||
181 | static struct file_operations proc_viocd_operations = { | ||
182 | .open = proc_viocd_open, | ||
183 | .read = seq_read, | ||
184 | .llseek = seq_lseek, | ||
185 | .release = single_release, | ||
186 | }; | ||
187 | |||
188 | static int viocd_blk_open(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | struct disk_info *di = inode->i_bdev->bd_disk->private_data; | ||
191 | return cdrom_open(&di->viocd_info, inode, file); | ||
192 | } | ||
193 | |||
194 | static int viocd_blk_release(struct inode *inode, struct file *file) | ||
195 | { | ||
196 | struct disk_info *di = inode->i_bdev->bd_disk->private_data; | ||
197 | return cdrom_release(&di->viocd_info, file); | ||
198 | } | ||
199 | |||
200 | static int viocd_blk_ioctl(struct inode *inode, struct file *file, | ||
201 | unsigned cmd, unsigned long arg) | ||
202 | { | ||
203 | struct disk_info *di = inode->i_bdev->bd_disk->private_data; | ||
204 | return cdrom_ioctl(file, &di->viocd_info, inode, cmd, arg); | ||
205 | } | ||
206 | |||
207 | static int viocd_blk_media_changed(struct gendisk *disk) | ||
208 | { | ||
209 | struct disk_info *di = disk->private_data; | ||
210 | return cdrom_media_changed(&di->viocd_info); | ||
211 | } | ||
212 | |||
213 | struct block_device_operations viocd_fops = { | ||
214 | .owner = THIS_MODULE, | ||
215 | .open = viocd_blk_open, | ||
216 | .release = viocd_blk_release, | ||
217 | .ioctl = viocd_blk_ioctl, | ||
218 | .media_changed = viocd_blk_media_changed, | ||
219 | }; | ||
220 | |||
221 | /* Get info on CD devices from OS/400 */ | ||
222 | static void __init get_viocd_info(void) | ||
223 | { | ||
224 | HvLpEvent_Rc hvrc; | ||
225 | int i; | ||
226 | struct viocd_waitevent we; | ||
227 | |||
228 | viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, | ||
229 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, | ||
230 | &unitinfo_dmaaddr, GFP_ATOMIC); | ||
231 | if (viocd_unitinfo == NULL) { | ||
232 | printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); | ||
233 | return; | ||
234 | } | ||
235 | |||
236 | memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); | ||
237 | |||
238 | init_completion(&we.com); | ||
239 | |||
240 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
241 | HvLpEvent_Type_VirtualIo, | ||
242 | viomajorsubtype_cdio | viocdgetinfo, | ||
243 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
244 | viopath_sourceinst(viopath_hostLp), | ||
245 | viopath_targetinst(viopath_hostLp), | ||
246 | (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, | ||
247 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); | ||
248 | if (hvrc != HvLpEvent_Rc_Good) { | ||
249 | printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", | ||
250 | (int)hvrc); | ||
251 | goto error_ret; | ||
252 | } | ||
253 | |||
254 | wait_for_completion(&we.com); | ||
255 | |||
256 | if (we.rc) { | ||
257 | const struct vio_error_entry *err = | ||
258 | vio_lookup_rc(viocd_err_table, we.sub_result); | ||
259 | printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", | ||
260 | we.rc, we.sub_result, err->msg); | ||
261 | goto error_ret; | ||
262 | } | ||
263 | |||
264 | for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) | ||
265 | viocd_numdev++; | ||
266 | |||
267 | error_ret: | ||
268 | if (viocd_numdev == 0) { | ||
269 | dma_free_coherent(iSeries_vio_dev, | ||
270 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, | ||
271 | viocd_unitinfo, unitinfo_dmaaddr); | ||
272 | viocd_unitinfo = NULL; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static int viocd_open(struct cdrom_device_info *cdi, int purpose) | ||
277 | { | ||
278 | struct disk_info *diskinfo = cdi->handle; | ||
279 | int device_no = DEVICE_NR(diskinfo); | ||
280 | HvLpEvent_Rc hvrc; | ||
281 | struct viocd_waitevent we; | ||
282 | |||
283 | init_completion(&we.com); | ||
284 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
285 | HvLpEvent_Type_VirtualIo, | ||
286 | viomajorsubtype_cdio | viocdopen, | ||
287 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
288 | viopath_sourceinst(viopath_hostLp), | ||
289 | viopath_targetinst(viopath_hostLp), | ||
290 | (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), | ||
291 | 0, 0, 0); | ||
292 | if (hvrc != 0) { | ||
293 | printk(VIOCD_KERN_WARNING | ||
294 | "bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
295 | (int)hvrc); | ||
296 | return -EIO; | ||
297 | } | ||
298 | |||
299 | wait_for_completion(&we.com); | ||
300 | |||
301 | if (we.rc) { | ||
302 | const struct vio_error_entry *err = | ||
303 | vio_lookup_rc(viocd_err_table, we.sub_result); | ||
304 | printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on open: %s\n", | ||
305 | we.rc, we.sub_result, err->msg); | ||
306 | return -err->errno; | ||
307 | } | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static void viocd_release(struct cdrom_device_info *cdi) | ||
313 | { | ||
314 | int device_no = DEVICE_NR((struct disk_info *)cdi->handle); | ||
315 | HvLpEvent_Rc hvrc; | ||
316 | |||
317 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
318 | HvLpEvent_Type_VirtualIo, | ||
319 | viomajorsubtype_cdio | viocdclose, | ||
320 | HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, | ||
321 | viopath_sourceinst(viopath_hostLp), | ||
322 | viopath_targetinst(viopath_hostLp), 0, | ||
323 | VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0); | ||
324 | if (hvrc != 0) | ||
325 | printk(VIOCD_KERN_WARNING | ||
326 | "bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
327 | (int)hvrc); | ||
328 | } | ||
329 | |||
330 | /* Send a read or write request to OS/400 */ | ||
331 | static int send_request(struct request *req) | ||
332 | { | ||
333 | HvLpEvent_Rc hvrc; | ||
334 | struct disk_info *diskinfo = req->rq_disk->private_data; | ||
335 | u64 len; | ||
336 | dma_addr_t dmaaddr; | ||
337 | int direction; | ||
338 | u16 cmd; | ||
339 | struct scatterlist sg; | ||
340 | |||
341 | BUG_ON(req->nr_phys_segments > 1); | ||
342 | |||
343 | if (rq_data_dir(req) == READ) { | ||
344 | direction = DMA_FROM_DEVICE; | ||
345 | cmd = viomajorsubtype_cdio | viocdread; | ||
346 | } else { | ||
347 | direction = DMA_TO_DEVICE; | ||
348 | cmd = viomajorsubtype_cdio | viocdwrite; | ||
349 | } | ||
350 | |||
351 | if (blk_rq_map_sg(req->q, req, &sg) == 0) { | ||
352 | printk(VIOCD_KERN_WARNING | ||
353 | "error setting up scatter/gather list\n"); | ||
354 | return -1; | ||
355 | } | ||
356 | |||
357 | if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) { | ||
358 | printk(VIOCD_KERN_WARNING "error allocating sg tce\n"); | ||
359 | return -1; | ||
360 | } | ||
361 | dmaaddr = sg_dma_address(&sg); | ||
362 | len = sg_dma_len(&sg); | ||
363 | |||
364 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
365 | HvLpEvent_Type_VirtualIo, cmd, | ||
366 | HvLpEvent_AckInd_DoAck, | ||
367 | HvLpEvent_AckType_ImmediateAck, | ||
368 | viopath_sourceinst(viopath_hostLp), | ||
369 | viopath_targetinst(viopath_hostLp), | ||
370 | (u64)req, VIOVERSION << 16, | ||
371 | ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, | ||
372 | (u64)req->sector * 512, len, 0); | ||
373 | if (hvrc != HvLpEvent_Rc_Good) { | ||
374 | printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc); | ||
375 | return -1; | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | |||
382 | static int rwreq; | ||
383 | |||
384 | static void do_viocd_request(request_queue_t *q) | ||
385 | { | ||
386 | struct request *req; | ||
387 | |||
388 | while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { | ||
389 | if (!blk_fs_request(req)) | ||
390 | end_request(req, 0); | ||
391 | else if (send_request(req) < 0) { | ||
392 | printk(VIOCD_KERN_WARNING | ||
393 | "unable to send message to OS/400!"); | ||
394 | end_request(req, 0); | ||
395 | } else | ||
396 | rwreq++; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr) | ||
401 | { | ||
402 | struct viocd_waitevent we; | ||
403 | HvLpEvent_Rc hvrc; | ||
404 | int device_no = DEVICE_NR((struct disk_info *)cdi->handle); | ||
405 | |||
406 | init_completion(&we.com); | ||
407 | |||
408 | /* Send the open event to OS/400 */ | ||
409 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
410 | HvLpEvent_Type_VirtualIo, | ||
411 | viomajorsubtype_cdio | viocdcheck, | ||
412 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
413 | viopath_sourceinst(viopath_hostLp), | ||
414 | viopath_targetinst(viopath_hostLp), | ||
415 | (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), | ||
416 | 0, 0, 0); | ||
417 | if (hvrc != 0) { | ||
418 | printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
419 | (int)hvrc); | ||
420 | return -EIO; | ||
421 | } | ||
422 | |||
423 | wait_for_completion(&we.com); | ||
424 | |||
425 | /* Check the return code. If bad, assume no change */ | ||
426 | if (we.rc) { | ||
427 | const struct vio_error_entry *err = | ||
428 | vio_lookup_rc(viocd_err_table, we.sub_result); | ||
429 | printk(VIOCD_KERN_WARNING | ||
430 | "bad rc %d:0x%04X on check_change: %s; Assuming no change\n", | ||
431 | we.rc, we.sub_result, err->msg); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | return we.changed; | ||
436 | } | ||
437 | |||
438 | static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) | ||
439 | { | ||
440 | HvLpEvent_Rc hvrc; | ||
441 | u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle); | ||
442 | /* NOTE: flags is 1 or 0 so it won't overwrite the device_no */ | ||
443 | u64 flags = !!locking; | ||
444 | struct viocd_waitevent we; | ||
445 | |||
446 | init_completion(&we.com); | ||
447 | |||
448 | /* Send the lockdoor event to OS/400 */ | ||
449 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
450 | HvLpEvent_Type_VirtualIo, | ||
451 | viomajorsubtype_cdio | viocdlockdoor, | ||
452 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
453 | viopath_sourceinst(viopath_hostLp), | ||
454 | viopath_targetinst(viopath_hostLp), | ||
455 | (u64)&we, VIOVERSION << 16, | ||
456 | (device_no << 48) | (flags << 32), 0, 0, 0); | ||
457 | if (hvrc != 0) { | ||
458 | printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
459 | (int)hvrc); | ||
460 | return -EIO; | ||
461 | } | ||
462 | |||
463 | wait_for_completion(&we.com); | ||
464 | |||
465 | if (we.rc != 0) | ||
466 | return -EIO; | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int viocd_packet(struct cdrom_device_info *cdi, | ||
471 | struct packet_command *cgc) | ||
472 | { | ||
473 | unsigned int buflen = cgc->buflen; | ||
474 | int ret = -EIO; | ||
475 | |||
476 | switch (cgc->cmd[0]) { | ||
477 | case GPCMD_READ_DISC_INFO: | ||
478 | { | ||
479 | disc_information *di = (disc_information *)cgc->buffer; | ||
480 | |||
481 | if (buflen >= 2) { | ||
482 | di->disc_information_length = cpu_to_be16(1); | ||
483 | ret = 0; | ||
484 | } | ||
485 | if (buflen >= 3) | ||
486 | di->erasable = | ||
487 | (cdi->ops->capability & ~cdi->mask | ||
488 | & (CDC_DVD_RAM | CDC_RAM)) != 0; | ||
489 | } | ||
490 | break; | ||
491 | default: | ||
492 | if (cgc->sense) { | ||
493 | /* indicate Unknown code */ | ||
494 | cgc->sense->sense_key = 0x05; | ||
495 | cgc->sense->asc = 0x20; | ||
496 | cgc->sense->ascq = 0x00; | ||
497 | } | ||
498 | break; | ||
499 | } | ||
500 | |||
501 | cgc->stat = ret; | ||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | static void restart_all_queues(int first_index) | ||
506 | { | ||
507 | int i; | ||
508 | |||
509 | for (i = first_index + 1; i < viocd_numdev; i++) | ||
510 | if (viocd_diskinfo[i].viocd_disk) | ||
511 | blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); | ||
512 | for (i = 0; i <= first_index; i++) | ||
513 | if (viocd_diskinfo[i].viocd_disk) | ||
514 | blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); | ||
515 | } | ||
516 | |||
517 | /* This routine handles incoming CD LP events */ | ||
518 | static void vio_handle_cd_event(struct HvLpEvent *event) | ||
519 | { | ||
520 | struct viocdlpevent *bevent; | ||
521 | struct viocd_waitevent *pwe; | ||
522 | struct disk_info *di; | ||
523 | unsigned long flags; | ||
524 | struct request *req; | ||
525 | |||
526 | |||
527 | if (event == NULL) | ||
528 | /* Notification that a partition went away! */ | ||
529 | return; | ||
530 | /* First, we should NEVER get an int here...only acks */ | ||
531 | if (event->xFlags.xFunction == HvLpEvent_Function_Int) { | ||
532 | printk(VIOCD_KERN_WARNING | ||
533 | "Yikes! got an int in viocd event handler!\n"); | ||
534 | if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) { | ||
535 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
536 | HvCallEvent_ackLpEvent(event); | ||
537 | } | ||
538 | } | ||
539 | |||
540 | bevent = (struct viocdlpevent *)event; | ||
541 | |||
542 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
543 | case viocdopen: | ||
544 | if (event->xRc == 0) { | ||
545 | di = &viocd_diskinfo[bevent->disk]; | ||
546 | blk_queue_hardsect_size(di->viocd_disk->queue, | ||
547 | bevent->block_size); | ||
548 | set_capacity(di->viocd_disk, | ||
549 | bevent->media_size * | ||
550 | bevent->block_size / 512); | ||
551 | } | ||
552 | /* FALLTHROUGH !! */ | ||
553 | case viocdgetinfo: | ||
554 | case viocdlockdoor: | ||
555 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; | ||
556 | return_complete: | ||
557 | pwe->rc = event->xRc; | ||
558 | pwe->sub_result = bevent->sub_result; | ||
559 | complete(&pwe->com); | ||
560 | break; | ||
561 | |||
562 | case viocdcheck: | ||
563 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; | ||
564 | pwe->changed = bevent->flags; | ||
565 | goto return_complete; | ||
566 | |||
567 | case viocdclose: | ||
568 | break; | ||
569 | |||
570 | case viocdwrite: | ||
571 | case viocdread: | ||
572 | /* | ||
573 | * Since this is running in interrupt mode, we need to | ||
574 | * make sure we're not stepping on any global I/O operations | ||
575 | */ | ||
576 | di = &viocd_diskinfo[bevent->disk]; | ||
577 | spin_lock_irqsave(&viocd_reqlock, flags); | ||
578 | dma_unmap_single(di->dev, bevent->token, bevent->len, | ||
579 | ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread) | ||
580 | ? DMA_FROM_DEVICE : DMA_TO_DEVICE); | ||
581 | req = (struct request *)bevent->event.xCorrelationToken; | ||
582 | rwreq--; | ||
583 | |||
584 | if (event->xRc != HvLpEvent_Rc_Good) { | ||
585 | const struct vio_error_entry *err = | ||
586 | vio_lookup_rc(viocd_err_table, | ||
587 | bevent->sub_result); | ||
588 | printk(VIOCD_KERN_WARNING "request %p failed " | ||
589 | "with rc %d:0x%04X: %s\n", | ||
590 | req, event->xRc, | ||
591 | bevent->sub_result, err->msg); | ||
592 | end_request(req, 0); | ||
593 | } else | ||
594 | end_request(req, 1); | ||
595 | |||
596 | /* restart handling of incoming requests */ | ||
597 | spin_unlock_irqrestore(&viocd_reqlock, flags); | ||
598 | restart_all_queues(bevent->disk); | ||
599 | break; | ||
600 | |||
601 | default: | ||
602 | printk(VIOCD_KERN_WARNING | ||
603 | "message with invalid subtype %0x04X!\n", | ||
604 | event->xSubtype & VIOMINOR_SUBTYPE_MASK); | ||
605 | if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) { | ||
606 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
607 | HvCallEvent_ackLpEvent(event); | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | static struct cdrom_device_ops viocd_dops = { | ||
613 | .open = viocd_open, | ||
614 | .release = viocd_release, | ||
615 | .media_changed = viocd_media_changed, | ||
616 | .lock_door = viocd_lock_door, | ||
617 | .generic_packet = viocd_packet, | ||
618 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM | ||
619 | }; | ||
620 | |||
621 | static int __init find_capability(const char *type) | ||
622 | { | ||
623 | struct capability_entry *entry; | ||
624 | |||
625 | for(entry = capability_table; entry->type; ++entry) | ||
626 | if(!strncmp(entry->type, type, 4)) | ||
627 | break; | ||
628 | return entry->capability; | ||
629 | } | ||
630 | |||
631 | static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
632 | { | ||
633 | struct gendisk *gendisk; | ||
634 | int deviceno; | ||
635 | struct disk_info *d; | ||
636 | struct cdrom_device_info *c; | ||
637 | struct cdrom_info *ci; | ||
638 | struct request_queue *q; | ||
639 | |||
640 | deviceno = vdev->unit_address; | ||
641 | if (deviceno >= viocd_numdev) | ||
642 | return -ENODEV; | ||
643 | |||
644 | d = &viocd_diskinfo[deviceno]; | ||
645 | c = &d->viocd_info; | ||
646 | ci = &viocd_unitinfo[deviceno]; | ||
647 | |||
648 | c->ops = &viocd_dops; | ||
649 | c->speed = 4; | ||
650 | c->capacity = 1; | ||
651 | c->handle = d; | ||
652 | c->mask = ~find_capability(ci->type); | ||
653 | sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); | ||
654 | |||
655 | if (register_cdrom(c) != 0) { | ||
656 | printk(VIOCD_KERN_WARNING "Cannot register viocd CD-ROM %s!\n", | ||
657 | c->name); | ||
658 | goto out; | ||
659 | } | ||
660 | printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " | ||
661 | "type %4.4s, model %3.3s\n", | ||
662 | c->name, ci->rsrcname, ci->type, ci->model); | ||
663 | q = blk_init_queue(do_viocd_request, &viocd_reqlock); | ||
664 | if (q == NULL) { | ||
665 | printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", | ||
666 | c->name); | ||
667 | goto out_unregister_cdrom; | ||
668 | } | ||
669 | gendisk = alloc_disk(1); | ||
670 | if (gendisk == NULL) { | ||
671 | printk(VIOCD_KERN_WARNING "Cannot create gendisk for %s!\n", | ||
672 | c->name); | ||
673 | goto out_cleanup_queue; | ||
674 | } | ||
675 | gendisk->major = VIOCD_MAJOR; | ||
676 | gendisk->first_minor = deviceno; | ||
677 | strncpy(gendisk->disk_name, c->name, | ||
678 | sizeof(gendisk->disk_name)); | ||
679 | snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name), | ||
680 | VIOCD_DEVICE_DEVFS "%d", deviceno); | ||
681 | blk_queue_max_hw_segments(q, 1); | ||
682 | blk_queue_max_phys_segments(q, 1); | ||
683 | blk_queue_max_sectors(q, 4096 / 512); | ||
684 | gendisk->queue = q; | ||
685 | gendisk->fops = &viocd_fops; | ||
686 | gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; | ||
687 | set_capacity(gendisk, 0); | ||
688 | gendisk->private_data = d; | ||
689 | d->viocd_disk = gendisk; | ||
690 | d->dev = &vdev->dev; | ||
691 | gendisk->driverfs_dev = d->dev; | ||
692 | add_disk(gendisk); | ||
693 | return 0; | ||
694 | |||
695 | out_cleanup_queue: | ||
696 | blk_cleanup_queue(q); | ||
697 | out_unregister_cdrom: | ||
698 | unregister_cdrom(c); | ||
699 | out: | ||
700 | return -ENODEV; | ||
701 | } | ||
702 | |||
703 | static int viocd_remove(struct vio_dev *vdev) | ||
704 | { | ||
705 | struct disk_info *d = &viocd_diskinfo[vdev->unit_address]; | ||
706 | |||
707 | if (unregister_cdrom(&d->viocd_info) != 0) | ||
708 | printk(VIOCD_KERN_WARNING | ||
709 | "Cannot unregister viocd CD-ROM %s!\n", | ||
710 | d->viocd_info.name); | ||
711 | del_gendisk(d->viocd_disk); | ||
712 | blk_cleanup_queue(d->viocd_disk->queue); | ||
713 | put_disk(d->viocd_disk); | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * viocd_device_table: Used by vio.c to match devices that we | ||
719 | * support. | ||
720 | */ | ||
721 | static struct vio_device_id viocd_device_table[] __devinitdata = { | ||
722 | { "viocd", "" }, | ||
723 | { 0, } | ||
724 | }; | ||
725 | |||
726 | MODULE_DEVICE_TABLE(vio, viocd_device_table); | ||
727 | static struct vio_driver viocd_driver = { | ||
728 | .name = "viocd", | ||
729 | .id_table = viocd_device_table, | ||
730 | .probe = viocd_probe, | ||
731 | .remove = viocd_remove | ||
732 | }; | ||
733 | |||
734 | static int __init viocd_init(void) | ||
735 | { | ||
736 | struct proc_dir_entry *e; | ||
737 | int ret = 0; | ||
738 | |||
739 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
740 | vio_set_hostlp(); | ||
741 | /* If we don't have a host, bail out */ | ||
742 | if (viopath_hostLp == HvLpIndexInvalid) | ||
743 | return -ENODEV; | ||
744 | } | ||
745 | |||
746 | printk(VIOCD_KERN_INFO "vers " VIOCD_VERS ", hosting partition %d\n", | ||
747 | viopath_hostLp); | ||
748 | |||
749 | if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) { | ||
750 | printk(VIOCD_KERN_WARNING "Unable to get major %d for %s\n", | ||
751 | VIOCD_MAJOR, VIOCD_DEVICE); | ||
752 | return -EIO; | ||
753 | } | ||
754 | |||
755 | ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, | ||
756 | MAX_CD_REQ + 2); | ||
757 | if (ret) { | ||
758 | printk(VIOCD_KERN_WARNING | ||
759 | "error opening path to host partition %d\n", | ||
760 | viopath_hostLp); | ||
761 | goto out_unregister; | ||
762 | } | ||
763 | |||
764 | /* Initialize our request handler */ | ||
765 | vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); | ||
766 | |||
767 | get_viocd_info(); | ||
768 | |||
769 | spin_lock_init(&viocd_reqlock); | ||
770 | |||
771 | ret = vio_register_driver(&viocd_driver); | ||
772 | if (ret) | ||
773 | goto out_free_info; | ||
774 | |||
775 | e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); | ||
776 | if (e) { | ||
777 | e->owner = THIS_MODULE; | ||
778 | e->proc_fops = &proc_viocd_operations; | ||
779 | } | ||
780 | |||
781 | return 0; | ||
782 | |||
783 | out_free_info: | ||
784 | dma_free_coherent(iSeries_vio_dev, | ||
785 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, | ||
786 | viocd_unitinfo, unitinfo_dmaaddr); | ||
787 | vio_clearHandler(viomajorsubtype_cdio); | ||
788 | viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); | ||
789 | out_unregister: | ||
790 | unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); | ||
791 | return ret; | ||
792 | } | ||
793 | |||
794 | static void __exit viocd_exit(void) | ||
795 | { | ||
796 | remove_proc_entry("iSeries/viocd", NULL); | ||
797 | vio_unregister_driver(&viocd_driver); | ||
798 | if (viocd_unitinfo != NULL) | ||
799 | dma_free_coherent(iSeries_vio_dev, | ||
800 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, | ||
801 | viocd_unitinfo, unitinfo_dmaaddr); | ||
802 | viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); | ||
803 | vio_clearHandler(viomajorsubtype_cdio); | ||
804 | unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); | ||
805 | } | ||
806 | |||
807 | module_init(viocd_init); | ||
808 | module_exit(viocd_exit); | ||
809 | MODULE_LICENSE("GPL"); | ||