ec698c44e8bfc6154a6c202d88cdc2be9bcdfa31
[pandora-kernel.git] / drivers / ide / ide-cd_ioctl.c
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
15 int 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  */
26 int 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
65 int 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
87 int 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
117 int 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
140 static 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
169 static 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
204 static 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
223 static 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
246 int 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 }