aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-cd_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/ide-cd_ioctl.c')
-rw-r--r--drivers/ide/ide-cd_ioctl.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
new file mode 100644
index 000000000000..ec698c44e8bf
--- /dev/null
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -0,0 +1,265 @@
1/*
2 * cdrom.c IOCTLs handling for ide-cd driver.
3 *
4 * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
5 * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
6 * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
7 */
8
9#include <linux/kernel.h>
10#include <linux/cdrom.h>
11#include <linux/ide.h>
12
13#include "ide-cd.h"
14
15int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
16{
17 ide_drive_t *drive = cdi->handle;
18
19 return ide_cd_lockdoor(drive, lock, NULL);
20}
21
22/*
23 * ATAPI devices are free to select the speed you request or any slower
24 * rate. :-( Requesting too fast a speed will _not_ produce an error.
25 */
26int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
27{
28 ide_drive_t *drive = cdi->handle;
29 struct cdrom_info *cd = drive->driver_data;
30 struct request rq;
31 struct request_sense sense;
32 u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
33 int stat;
34
35 ide_cd_init_rq(drive, &rq);
36
37 rq.sense = &sense;
38
39 if (speed == 0)
40 speed = 0xffff; /* set to max */
41 else
42 speed *= 177; /* Nx to kbytes/s */
43
44 rq.cmd[0] = GPCMD_SET_SPEED;
45 /* Read Drive speed in kbytes/second MSB/LSB */
46 rq.cmd[2] = (speed >> 8) & 0xff;
47 rq.cmd[3] = speed & 0xff;
48 if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
49 (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
50 /* Write Drive speed in kbytes/second MSB/LSB */
51 rq.cmd[4] = (speed >> 8) & 0xff;
52 rq.cmd[5] = speed & 0xff;
53 }
54
55 stat = ide_cd_queue_pc(drive, &rq);
56
57 if (!ide_cdrom_get_capabilities(drive, buf)) {
58 ide_cdrom_update_speed(drive, buf);
59 cdi->speed = cd->current_speed;
60 }
61
62 return 0;
63}
64
65int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
66 struct cdrom_multisession *ms_info)
67{
68 struct atapi_toc *toc;
69 ide_drive_t *drive = cdi->handle;
70 struct cdrom_info *info = drive->driver_data;
71 struct request_sense sense;
72 int ret;
73
74 if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0 || !info->toc) {
75 ret = ide_cd_read_toc(drive, &sense);
76 if (ret)
77 return ret;
78 }
79
80 toc = info->toc;
81 ms_info->addr.lba = toc->last_session_lba;
82 ms_info->xa_flag = toc->xa_flag;
83
84 return 0;
85}
86
87int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
88 struct cdrom_mcn *mcn_info)
89{
90 ide_drive_t *drive = cdi->handle;
91 int stat, mcnlen;
92 struct request rq;
93 char buf[24];
94
95 ide_cd_init_rq(drive, &rq);
96
97 rq.data = buf;
98 rq.data_len = sizeof(buf);
99
100 rq.cmd[0] = GPCMD_READ_SUBCHANNEL;
101 rq.cmd[1] = 2; /* MSF addressing */
102 rq.cmd[2] = 0x40; /* request subQ data */
103 rq.cmd[3] = 2; /* format */
104 rq.cmd[8] = sizeof(buf);
105
106 stat = ide_cd_queue_pc(drive, &rq);
107 if (stat)
108 return stat;
109
110 mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
111 memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
112 mcn_info->medium_catalog_number[mcnlen] = '\0';
113
114 return 0;
115}
116
117int ide_cdrom_reset(struct cdrom_device_info *cdi)
118{
119 ide_drive_t *drive = cdi->handle;
120 struct cdrom_info *cd = drive->driver_data;
121 struct request_sense sense;
122 struct request req;
123 int ret;
124
125 ide_cd_init_rq(drive, &req);
126 req.cmd_type = REQ_TYPE_SPECIAL;
127 req.cmd_flags = REQ_QUIET;
128 ret = ide_do_drive_cmd(drive, &req, ide_wait);
129
130 /*
131 * A reset will unlock the door. If it was previously locked,
132 * lock it again.
133 */
134 if (cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED)
135 (void)ide_cd_lockdoor(drive, 1, &sense);
136
137 return ret;
138}
139
140static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
141 struct atapi_toc_entry **ent)
142{
143 struct cdrom_info *info = drive->driver_data;
144 struct atapi_toc *toc = info->toc;
145 int ntracks;
146
147 /*
148 * don't serve cached data, if the toc isn't valid
149 */
150 if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0)
151 return -EINVAL;
152
153 /* Check validity of requested track number. */
154 ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
155
156 if (toc->hdr.first_track == CDROM_LEADOUT)
157 ntracks = 0;
158
159 if (track == CDROM_LEADOUT)
160 *ent = &toc->ent[ntracks];
161 else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
162 return -EINVAL;
163 else
164 *ent = &toc->ent[track - toc->hdr.first_track];
165
166 return 0;
167}
168
169static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
170{
171 struct cdrom_ti *ti = arg;
172 struct atapi_toc_entry *first_toc, *last_toc;
173 unsigned long lba_start, lba_end;
174 int stat;
175 struct request rq;
176 struct request_sense sense;
177
178 stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
179 if (stat)
180 return stat;
181
182 stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
183 if (stat)
184 return stat;
185
186 if (ti->cdti_trk1 != CDROM_LEADOUT)
187 ++last_toc;
188 lba_start = first_toc->addr.lba;
189 lba_end = last_toc->addr.lba;
190
191 if (lba_end <= lba_start)
192 return -EINVAL;
193
194 ide_cd_init_rq(drive, &rq);
195
196 rq.sense = &sense;
197 rq.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
198 lba_to_msf(lba_start, &rq.cmd[3], &rq.cmd[4], &rq.cmd[5]);
199 lba_to_msf(lba_end - 1, &rq.cmd[6], &rq.cmd[7], &rq.cmd[8]);
200
201 return ide_cd_queue_pc(drive, &rq);
202}
203
204static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
205{
206 struct cdrom_info *cd = drive->driver_data;
207 struct cdrom_tochdr *tochdr = arg;
208 struct atapi_toc *toc;
209 int stat;
210
211 /* Make sure our saved TOC is valid. */
212 stat = ide_cd_read_toc(drive, NULL);
213 if (stat)
214 return stat;
215
216 toc = cd->toc;
217 tochdr->cdth_trk0 = toc->hdr.first_track;
218 tochdr->cdth_trk1 = toc->hdr.last_track;
219
220 return 0;
221}
222
223static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
224{
225 struct cdrom_tocentry *tocentry = arg;
226 struct atapi_toc_entry *toce;
227 int stat;
228
229 stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
230 if (stat)
231 return stat;
232
233 tocentry->cdte_ctrl = toce->control;
234 tocentry->cdte_adr = toce->adr;
235 if (tocentry->cdte_format == CDROM_MSF) {
236 lba_to_msf(toce->addr.lba,
237 &tocentry->cdte_addr.msf.minute,
238 &tocentry->cdte_addr.msf.second,
239 &tocentry->cdte_addr.msf.frame);
240 } else
241 tocentry->cdte_addr.lba = toce->addr.lba;
242
243 return 0;
244}
245
246int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
247 unsigned int cmd, void *arg)
248{
249 ide_drive_t *drive = cdi->handle;
250
251 switch (cmd) {
252 /*
253 * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
254 * atapi doesn't support it
255 */
256 case CDROMPLAYTRKIND:
257 return ide_cd_fake_play_trkind(drive, arg);
258 case CDROMREADTOCHDR:
259 return ide_cd_read_tochdr(drive, arg);
260 case CDROMREADTOCENTRY:
261 return ide_cd_read_tocentry(drive, arg);
262 default:
263 return -EINVAL;
264 }
265}