aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cdrom
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2006-03-23 06:00:14 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-23 10:38:09 -0500
commitd2c5d4fc07a41a6048b01d3b2930aeff1235fda5 (patch)
tree83bfa8bfd38e4d4063123d32a20f5e1e5b026a10 /drivers/cdrom
parent2dd0ebcd2ab7b18a50c0810ddb45a84316e4ee2e (diff)
[PATCH] cleanup cdrom_ioctl
Add a small helper for each ioctl to cut down cdrom_ioctl to a readable size. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: Acked-by: Jens Axboe <axboe@suse.de> Signed-off-by: Benoit Boissinot <benoit.boissinot@ens-lyon.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/cdrom')
-rw-r--r--drivers/cdrom/cdrom.c877
1 files changed, 537 insertions, 340 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 879bbc26ce96..d6653fc03b92 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2196,395 +2196,592 @@ retry:
2196 return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); 2196 return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);
2197} 2197}
2198 2198
2199/* Just about every imaginable ioctl is supported in the Uniform layer 2199static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
2200 * these days. ATAPI / SCSI specific code now mainly resides in 2200 void __user *argp)
2201 * mmc_ioct().
2202 */
2203int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
2204 struct inode *ip, unsigned int cmd, unsigned long arg)
2205{ 2201{
2206 struct cdrom_device_ops *cdo = cdi->ops; 2202 struct cdrom_multisession ms_info;
2203 u8 requested_format;
2207 int ret; 2204 int ret;
2208 2205
2209 /* Try the generic SCSI command ioctl's first.. */ 2206 cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
2210 ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, (void __user *)arg); 2207
2211 if (ret != -ENOTTY) 2208 if (!(cdi->ops->capability & CDC_MULTI_SESSION))
2209 return -ENOSYS;
2210
2211 if (copy_from_user(&ms_info, argp, sizeof(ms_info)))
2212 return -EFAULT;
2213
2214 requested_format = ms_info.addr_format;
2215 if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
2216 return -EINVAL;
2217 ms_info.addr_format = CDROM_LBA;
2218
2219 ret = cdi->ops->get_last_session(cdi, &ms_info);
2220 if (ret)
2212 return ret; 2221 return ret;
2213 2222
2214 /* the first few commands do not deal with audio drive_info, but 2223 sanitize_format(&ms_info.addr, &ms_info.addr_format, requested_format);
2215 only with routines in cdrom device operations. */ 2224
2216 switch (cmd) { 2225 if (copy_to_user(argp, &ms_info, sizeof(ms_info)))
2217 case CDROMMULTISESSION: { 2226 return -EFAULT;
2218 struct cdrom_multisession ms_info; 2227
2219 u_char requested_format; 2228 cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
2220 cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); 2229 return 0;
2221 if (!(cdo->capability & CDC_MULTI_SESSION)) 2230}
2222 return -ENOSYS; 2231
2223 IOCTL_IN(arg, struct cdrom_multisession, ms_info); 2232static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
2224 requested_format = ms_info.addr_format; 2233{
2225 if (!((requested_format == CDROM_MSF) || 2234 cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n");
2226 (requested_format == CDROM_LBA))) 2235
2227 return -EINVAL; 2236 if (!CDROM_CAN(CDC_OPEN_TRAY))
2228 ms_info.addr_format = CDROM_LBA; 2237 return -ENOSYS;
2229 if ((ret=cdo->get_last_session(cdi, &ms_info))) 2238 if (cdi->use_count != 1 || keeplocked)
2239 return -EBUSY;
2240 if (CDROM_CAN(CDC_LOCK)) {
2241 int ret = cdi->ops->lock_door(cdi, 0);
2242 if (ret)
2230 return ret; 2243 return ret;
2231 sanitize_format(&ms_info.addr, &ms_info.addr_format, 2244 }
2232 requested_format);
2233 IOCTL_OUT(arg, struct cdrom_multisession, ms_info);
2234 cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
2235 return 0;
2236 }
2237 2245
2238 case CDROMEJECT: { 2246 return cdi->ops->tray_move(cdi, 1);
2239 cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); 2247}
2240 if (!CDROM_CAN(CDC_OPEN_TRAY))
2241 return -ENOSYS;
2242 if (cdi->use_count != 1 || keeplocked)
2243 return -EBUSY;
2244 if (CDROM_CAN(CDC_LOCK))
2245 if ((ret=cdo->lock_door(cdi, 0)))
2246 return ret;
2247 2248
2248 return cdo->tray_move(cdi, 1); 2249static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
2249 } 2250{
2251 cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
2250 2252
2251 case CDROMCLOSETRAY: { 2253 if (!CDROM_CAN(CDC_CLOSE_TRAY))
2252 cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); 2254 return -ENOSYS;
2253 if (!CDROM_CAN(CDC_CLOSE_TRAY)) 2255 return cdi->ops->tray_move(cdi, 0);
2254 return -ENOSYS; 2256}
2255 return cdo->tray_move(cdi, 0);
2256 }
2257 2257
2258 case CDROMEJECT_SW: { 2258static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,
2259 cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 2259 unsigned long arg)
2260 if (!CDROM_CAN(CDC_OPEN_TRAY)) 2260{
2261 return -ENOSYS; 2261 cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
2262 if (keeplocked)
2263 return -EBUSY;
2264 cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
2265 if (arg)
2266 cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
2267 return 0;
2268 }
2269 2262
2270 case CDROM_MEDIA_CHANGED: { 2263 if (!CDROM_CAN(CDC_OPEN_TRAY))
2271 struct cdrom_changer_info *info; 2264 return -ENOSYS;
2272 int changed; 2265 if (keeplocked)
2266 return -EBUSY;
2273 2267
2274 cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 2268 cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
2275 if (!CDROM_CAN(CDC_MEDIA_CHANGED)) 2269 if (arg)
2276 return -ENOSYS; 2270 cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
2271 return 0;
2272}
2277 2273
2278 /* cannot select disc or select current disc */ 2274static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
2279 if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) 2275 unsigned long arg)
2280 return media_changed(cdi, 1); 2276{
2277 struct cdrom_changer_info *info;
2278 int ret;
2281 2279
2282 if ((unsigned int)arg >= cdi->capacity) 2280 cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
2283 return -EINVAL;
2284 2281
2285 info = kmalloc(sizeof(*info), GFP_KERNEL); 2282 if (!CDROM_CAN(CDC_MEDIA_CHANGED))
2286 if (!info) 2283 return -ENOSYS;
2287 return -ENOMEM;
2288 2284
2289 if ((ret = cdrom_read_mech_status(cdi, info))) { 2285 /* cannot select disc or select current disc */
2290 kfree(info); 2286 if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
2291 return ret; 2287 return media_changed(cdi, 1);
2292 }
2293 2288
2294 changed = info->slots[arg].change; 2289 if ((unsigned int)arg >= cdi->capacity)
2295 kfree(info); 2290 return -EINVAL;
2296 return changed;
2297 }
2298 2291
2299 case CDROM_SET_OPTIONS: { 2292 info = kmalloc(sizeof(*info), GFP_KERNEL);
2300 cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 2293 if (!info)
2301 /* options need to be in sync with capability. too late for 2294 return -ENOMEM;
2302 that, so we have to check each one separately... */
2303 switch (arg) {
2304 case CDO_USE_FFLAGS:
2305 case CDO_CHECK_TYPE:
2306 break;
2307 case CDO_LOCK:
2308 if (!CDROM_CAN(CDC_LOCK))
2309 return -ENOSYS;
2310 break;
2311 case 0:
2312 return cdi->options;
2313 /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
2314 default:
2315 if (!CDROM_CAN(arg))
2316 return -ENOSYS;
2317 }
2318 cdi->options |= (int) arg;
2319 return cdi->options;
2320 }
2321 2295
2322 case CDROM_CLEAR_OPTIONS: { 2296 ret = cdrom_read_mech_status(cdi, info);
2323 cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); 2297 if (!ret)
2324 cdi->options &= ~(int) arg; 2298 ret = info->slots[arg].change;
2325 return cdi->options; 2299 kfree(info);
2326 } 2300 return ret;
2301}
2327 2302
2328 case CDROM_SELECT_SPEED: { 2303static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
2329 cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 2304 unsigned long arg)
2330 if (!CDROM_CAN(CDC_SELECT_SPEED)) 2305{
2331 return -ENOSYS; 2306 cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
2332 return cdo->select_speed(cdi, arg);
2333 }
2334 2307
2335 case CDROM_SELECT_DISC: { 2308 /*
2336 cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); 2309 * Options need to be in sync with capability.
2337 if (!CDROM_CAN(CDC_SELECT_DISC)) 2310 * Too late for that, so we have to check each one separately.
2311 */
2312 switch (arg) {
2313 case CDO_USE_FFLAGS:
2314 case CDO_CHECK_TYPE:
2315 break;
2316 case CDO_LOCK:
2317 if (!CDROM_CAN(CDC_LOCK))
2318 return -ENOSYS;
2319 break;
2320 case 0:
2321 return cdi->options;
2322 /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
2323 default:
2324 if (!CDROM_CAN(arg))
2338 return -ENOSYS; 2325 return -ENOSYS;
2326 }
2327 cdi->options |= (int) arg;
2328 return cdi->options;
2329}
2339 2330
2340 if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE)) 2331static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
2341 if ((int)arg >= cdi->capacity) 2332 unsigned long arg)
2342 return -EINVAL; 2333{
2343 2334 cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
2344 /* cdo->select_disc is a hook to allow a driver-specific
2345 * way of seleting disc. However, since there is no
2346 * equiv hook for cdrom_slot_status this may not
2347 * actually be useful...
2348 */
2349 if (cdo->select_disc != NULL)
2350 return cdo->select_disc(cdi, arg);
2351
2352 /* no driver specific select_disc(), call our own */
2353 cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
2354 return cdrom_select_disc(cdi, arg);
2355 }
2356 2335
2357 case CDROMRESET: { 2336 cdi->options &= ~(int) arg;
2358 if (!capable(CAP_SYS_ADMIN)) 2337 return cdi->options;
2359 return -EACCES; 2338}
2360 cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
2361 if (!CDROM_CAN(CDC_RESET))
2362 return -ENOSYS;
2363 invalidate_bdev(ip->i_bdev, 0);
2364 return cdo->reset(cdi);
2365 }
2366 2339
2367 case CDROM_LOCKDOOR: { 2340static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
2368 cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); 2341 unsigned long arg)
2369 if (!CDROM_CAN(CDC_LOCK)) 2342{
2370 return -EDRIVE_CANT_DO_THIS; 2343 cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
2371 keeplocked = arg ? 1 : 0;
2372 /* don't unlock the door on multiple opens,but allow root
2373 * to do so */
2374 if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN))
2375 return -EBUSY;
2376 return cdo->lock_door(cdi, arg);
2377 }
2378 2344
2379 case CDROM_DEBUG: { 2345 if (!CDROM_CAN(CDC_SELECT_SPEED))
2380 if (!capable(CAP_SYS_ADMIN)) 2346 return -ENOSYS;
2381 return -EACCES; 2347 return cdi->ops->select_speed(cdi, arg);
2382 cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); 2348}
2383 debug = arg ? 1 : 0;
2384 return debug;
2385 }
2386 2349
2387 case CDROM_GET_CAPABILITY: { 2350static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
2388 cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); 2351 unsigned long arg)
2389 return (cdo->capability & ~cdi->mask); 2352{
2390 } 2353 cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
2354
2355 if (!CDROM_CAN(CDC_SELECT_DISC))
2356 return -ENOSYS;
2357
2358 if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
2359 if ((int)arg >= cdi->capacity)
2360 return -EINVAL;
2361 }
2362
2363 /*
2364 * ->select_disc is a hook to allow a driver-specific way of
2365 * seleting disc. However, since there is no equivalent hook for
2366 * cdrom_slot_status this may not actually be useful...
2367 */
2368 if (cdi->ops->select_disc)
2369 return cdi->ops->select_disc(cdi, arg);
2370
2371 cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
2372 return cdrom_select_disc(cdi, arg);
2373}
2374
2375static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
2376 struct block_device *bdev)
2377{
2378 cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
2379
2380 if (!capable(CAP_SYS_ADMIN))
2381 return -EACCES;
2382 if (!CDROM_CAN(CDC_RESET))
2383 return -ENOSYS;
2384 invalidate_bdev(bdev, 0);
2385 return cdi->ops->reset(cdi);
2386}
2387
2388static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
2389 unsigned long arg)
2390{
2391 cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
2392
2393 if (!CDROM_CAN(CDC_LOCK))
2394 return -EDRIVE_CANT_DO_THIS;
2395
2396 keeplocked = arg ? 1 : 0;
2397
2398 /*
2399 * Don't unlock the door on multiple opens by default, but allow
2400 * root to do so.
2401 */
2402 if (cdi->use_count != 1 && !arg && !capable(CAP_SYS_ADMIN))
2403 return -EBUSY;
2404 return cdi->ops->lock_door(cdi, arg);
2405}
2406
2407static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
2408 unsigned long arg)
2409{
2410 cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
2411
2412 if (!capable(CAP_SYS_ADMIN))
2413 return -EACCES;
2414 debug = arg ? 1 : 0;
2415 return debug;
2416}
2391 2417
2392/* The following function is implemented, although very few audio 2418static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)
2419{
2420 cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
2421 return (cdi->ops->capability & ~cdi->mask);
2422}
2423
2424/*
2425 * The following function is implemented, although very few audio
2393 * discs give Universal Product Code information, which should just be 2426 * discs give Universal Product Code information, which should just be
2394 * the Medium Catalog Number on the box. Note, that the way the code 2427 * the Medium Catalog Number on the box. Note, that the way the code
2395 * is written on the CD is /not/ uniform across all discs! 2428 * is written on the CD is /not/ uniform across all discs!
2396 */ 2429 */
2397 case CDROM_GET_MCN: { 2430static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
2398 struct cdrom_mcn mcn; 2431 void __user *argp)
2399 cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); 2432{
2400 if (!(cdo->capability & CDC_MCN)) 2433 struct cdrom_mcn mcn;
2401 return -ENOSYS; 2434 int ret;
2402 if ((ret=cdo->get_mcn(cdi, &mcn)))
2403 return ret;
2404 IOCTL_OUT(arg, struct cdrom_mcn, mcn);
2405 cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
2406 return 0;
2407 }
2408 2435
2409 case CDROM_DRIVE_STATUS: { 2436 cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
2410 cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
2411 if (!(cdo->capability & CDC_DRIVE_STATUS))
2412 return -ENOSYS;
2413 if (!CDROM_CAN(CDC_SELECT_DISC))
2414 return cdo->drive_status(cdi, CDSL_CURRENT);
2415 if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
2416 return cdo->drive_status(cdi, CDSL_CURRENT);
2417 if (((int)arg >= cdi->capacity))
2418 return -EINVAL;
2419 return cdrom_slot_status(cdi, arg);
2420 }
2421 2437
2422 /* Ok, this is where problems start. The current interface for the 2438 if (!(cdi->ops->capability & CDC_MCN))
2423 CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption 2439 return -ENOSYS;
2424 that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, 2440 ret = cdi->ops->get_mcn(cdi, &mcn);
2425 while this is often the case, it is also very common for CDs to 2441 if (ret)
2426 have some tracks with data, and some tracks with audio. Just 2442 return ret;
2427 because I feel like it, I declare the following to be the best
2428 way to cope. If the CD has ANY data tracks on it, it will be
2429 returned as a data CD. If it has any XA tracks, I will return
2430 it as that. Now I could simplify this interface by combining these
2431 returns with the above, but this more clearly demonstrates
2432 the problem with the current interface. Too bad this wasn't
2433 designed to use bitmasks... -Erik
2434
2435 Well, now we have the option CDS_MIXED: a mixed-type CD.
2436 User level programmers might feel the ioctl is not very useful.
2437 ---david
2438 */
2439 case CDROM_DISC_STATUS: {
2440 tracktype tracks;
2441 cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
2442 cdrom_count_tracks(cdi, &tracks);
2443 if (tracks.error)
2444 return(tracks.error);
2445
2446 /* Policy mode on */
2447 if (tracks.audio > 0) {
2448 if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0)
2449 return CDS_AUDIO;
2450 else
2451 return CDS_MIXED;
2452 }
2453 if (tracks.cdi > 0) return CDS_XA_2_2;
2454 if (tracks.xa > 0) return CDS_XA_2_1;
2455 if (tracks.data > 0) return CDS_DATA_1;
2456 /* Policy mode off */
2457 2443
2458 cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); 2444 if (copy_to_user(argp, &mcn, sizeof(mcn)))
2459 return CDS_NO_INFO; 2445 return -EFAULT;
2460 } 2446 cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
2447 return 0;
2448}
2461 2449
2462 case CDROM_CHANGER_NSLOTS: { 2450static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,
2463 cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); 2451 unsigned long arg)
2464 return cdi->capacity; 2452{
2465 } 2453 cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
2454
2455 if (!(cdi->ops->capability & CDC_DRIVE_STATUS))
2456 return -ENOSYS;
2457 if (!CDROM_CAN(CDC_SELECT_DISC) ||
2458 (arg == CDSL_CURRENT || arg == CDSL_NONE))
2459 return cdi->ops->drive_status(cdi, CDSL_CURRENT);
2460 if (((int)arg >= cdi->capacity))
2461 return -EINVAL;
2462 return cdrom_slot_status(cdi, arg);
2463}
2464
2465/*
2466 * Ok, this is where problems start. The current interface for the
2467 * CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption that
2468 * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, while this
2469 * is often the case, it is also very common for CDs to have some tracks
2470 * with data, and some tracks with audio. Just because I feel like it,
2471 * I declare the following to be the best way to cope. If the CD has ANY
2472 * data tracks on it, it will be returned as a data CD. If it has any XA
2473 * tracks, I will return it as that. Now I could simplify this interface
2474 * by combining these returns with the above, but this more clearly
2475 * demonstrates the problem with the current interface. Too bad this
2476 * wasn't designed to use bitmasks... -Erik
2477 *
2478 * Well, now we have the option CDS_MIXED: a mixed-type CD.
2479 * User level programmers might feel the ioctl is not very useful.
2480 * ---david
2481 */
2482static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
2483{
2484 tracktype tracks;
2485
2486 cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
2487
2488 cdrom_count_tracks(cdi, &tracks);
2489 if (tracks.error)
2490 return tracks.error;
2491
2492 /* Policy mode on */
2493 if (tracks.audio > 0) {
2494 if (!tracks.data && !tracks.cdi && !tracks.xa)
2495 return CDS_AUDIO;
2496 else
2497 return CDS_MIXED;
2498 }
2499
2500 if (tracks.cdi > 0)
2501 return CDS_XA_2_2;
2502 if (tracks.xa > 0)
2503 return CDS_XA_2_1;
2504 if (tracks.data > 0)
2505 return CDS_DATA_1;
2506 /* Policy mode off */
2507
2508 cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
2509 return CDS_NO_INFO;
2510}
2511
2512static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)
2513{
2514 cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
2515 return cdi->capacity;
2516}
2517
2518static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
2519 void __user *argp)
2520{
2521 struct cdrom_subchnl q;
2522 u8 requested, back;
2523 int ret;
2524
2525 /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
2526
2527 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2528 return -ENOSYS;
2529 if (copy_from_user(&q, argp, sizeof(q)))
2530 return -EFAULT;
2531
2532 requested = q.cdsc_format;
2533 if (requested != CDROM_MSF && requested != CDROM_LBA)
2534 return -EINVAL;
2535 q.cdsc_format = CDROM_MSF;
2536
2537 ret = cdi->ops->audio_ioctl(cdi, CDROMSUBCHNL, &q);
2538 if (ret)
2539 return ret;
2540
2541 back = q.cdsc_format; /* local copy */
2542 sanitize_format(&q.cdsc_absaddr, &back, requested);
2543 sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
2544
2545 if (copy_to_user(argp, &q, sizeof(q)))
2546 return -EFAULT;
2547 /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
2548 return 0;
2549}
2550
2551static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
2552 void __user *argp)
2553{
2554 struct cdrom_tochdr header;
2555 int ret;
2556
2557 /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
2558
2559 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2560 return -ENOSYS;
2561 if (copy_from_user(&header, argp, sizeof(header)))
2562 return -EFAULT;
2563
2564 ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
2565 if (ret)
2566 return ret;
2567
2568 if (copy_to_user(argp, &header, sizeof(header)))
2569 return -EFAULT;
2570 /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
2571 return 0;
2572}
2573
2574static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
2575 void __user *argp)
2576{
2577 struct cdrom_tocentry entry;
2578 u8 requested_format;
2579 int ret;
2580
2581 /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
2582
2583 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2584 return -ENOSYS;
2585 if (copy_from_user(&entry, argp, sizeof(entry)))
2586 return -EFAULT;
2587
2588 requested_format = entry.cdte_format;
2589 if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
2590 return -EINVAL;
2591 /* make interface to low-level uniform */
2592 entry.cdte_format = CDROM_MSF;
2593 ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry);
2594 if (ret)
2595 return ret;
2596 sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format);
2597
2598 if (copy_to_user(argp, &entry, sizeof(entry)))
2599 return -EFAULT;
2600 /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
2601 return 0;
2602}
2603
2604static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,
2605 void __user *argp)
2606{
2607 struct cdrom_msf msf;
2608
2609 cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
2610
2611 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2612 return -ENOSYS;
2613 if (copy_from_user(&msf, argp, sizeof(msf)))
2614 return -EFAULT;
2615 return cdi->ops->audio_ioctl(cdi, CDROMPLAYMSF, &msf);
2616}
2617
2618static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,
2619 void __user *argp)
2620{
2621 struct cdrom_ti ti;
2622 int ret;
2623
2624 cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
2625
2626 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2627 return -ENOSYS;
2628 if (copy_from_user(&ti, argp, sizeof(ti)))
2629 return -EFAULT;
2630
2631 ret = check_for_audio_disc(cdi, cdi->ops);
2632 if (ret)
2633 return ret;
2634 return cdi->ops->audio_ioctl(cdi, CDROMPLAYTRKIND, &ti);
2635}
2636static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,
2637 void __user *argp)
2638{
2639 struct cdrom_volctrl volume;
2640
2641 cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
2642
2643 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2644 return -ENOSYS;
2645 if (copy_from_user(&volume, argp, sizeof(volume)))
2646 return -EFAULT;
2647 return cdi->ops->audio_ioctl(cdi, CDROMVOLCTRL, &volume);
2648}
2649
2650static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,
2651 void __user *argp)
2652{
2653 struct cdrom_volctrl volume;
2654 int ret;
2655
2656 cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
2657
2658 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2659 return -ENOSYS;
2660
2661 ret = cdi->ops->audio_ioctl(cdi, CDROMVOLREAD, &volume);
2662 if (ret)
2663 return ret;
2664
2665 if (copy_to_user(argp, &volume, sizeof(volume)))
2666 return -EFAULT;
2667 return 0;
2668}
2669
2670static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
2671 unsigned int cmd)
2672{
2673 int ret;
2674
2675 cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
2676
2677 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2678 return -ENOSYS;
2679 ret = check_for_audio_disc(cdi, cdi->ops);
2680 if (ret)
2681 return ret;
2682 return cdi->ops->audio_ioctl(cdi, cmd, NULL);
2683}
2684
2685/*
2686 * Just about every imaginable ioctl is supported in the Uniform layer
2687 * these days.
2688 * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
2689 */
2690int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
2691 struct inode *ip, unsigned int cmd, unsigned long arg)
2692{
2693 void __user *argp = (void __user *)arg;
2694 int ret;
2695
2696 /*
2697 * Try the generic SCSI command ioctl's first.
2698 */
2699 ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, argp);
2700 if (ret != -ENOTTY)
2701 return ret;
2702
2703 switch (cmd) {
2704 case CDROMMULTISESSION:
2705 return cdrom_ioctl_multisession(cdi, argp);
2706 case CDROMEJECT:
2707 return cdrom_ioctl_eject(cdi);
2708 case CDROMCLOSETRAY:
2709 return cdrom_ioctl_closetray(cdi);
2710 case CDROMEJECT_SW:
2711 return cdrom_ioctl_eject_sw(cdi, arg);
2712 case CDROM_MEDIA_CHANGED:
2713 return cdrom_ioctl_media_changed(cdi, arg);
2714 case CDROM_SET_OPTIONS:
2715 return cdrom_ioctl_set_options(cdi, arg);
2716 case CDROM_CLEAR_OPTIONS:
2717 return cdrom_ioctl_clear_options(cdi, arg);
2718 case CDROM_SELECT_SPEED:
2719 return cdrom_ioctl_select_speed(cdi, arg);
2720 case CDROM_SELECT_DISC:
2721 return cdrom_ioctl_select_disc(cdi, arg);
2722 case CDROMRESET:
2723 return cdrom_ioctl_reset(cdi, ip->i_bdev);
2724 case CDROM_LOCKDOOR:
2725 return cdrom_ioctl_lock_door(cdi, arg);
2726 case CDROM_DEBUG:
2727 return cdrom_ioctl_debug(cdi, arg);
2728 case CDROM_GET_CAPABILITY:
2729 return cdrom_ioctl_get_capability(cdi);
2730 case CDROM_GET_MCN:
2731 return cdrom_ioctl_get_mcn(cdi, argp);
2732 case CDROM_DRIVE_STATUS:
2733 return cdrom_ioctl_drive_status(cdi, arg);
2734 case CDROM_DISC_STATUS:
2735 return cdrom_ioctl_disc_status(cdi);
2736 case CDROM_CHANGER_NSLOTS:
2737 return cdrom_ioctl_changer_nslots(cdi);
2466 } 2738 }
2467 2739
2468 /* use the ioctls that are implemented through the generic_packet() 2740 /*
2469 interface. this may look at bit funny, but if -ENOTTY is 2741 * Use the ioctls that are implemented through the generic_packet()
2470 returned that particular ioctl is not implemented and we 2742 * interface. this may look at bit funny, but if -ENOTTY is
2471 let it go through the device specific ones. */ 2743 * returned that particular ioctl is not implemented and we
2744 * let it go through the device specific ones.
2745 */
2472 if (CDROM_CAN(CDC_GENERIC_PACKET)) { 2746 if (CDROM_CAN(CDC_GENERIC_PACKET)) {
2473 ret = mmc_ioctl(cdi, cmd, arg); 2747 ret = mmc_ioctl(cdi, cmd, arg);
2474 if (ret != -ENOTTY) { 2748 if (ret != -ENOTTY)
2475 return ret; 2749 return ret;
2476 }
2477 } 2750 }
2478 2751
2479 /* note: most of the cdinfo() calls are commented out here, 2752 /*
2480 because they fill up the sys log when CD players poll 2753 * Note: most of the cdinfo() calls are commented out here,
2481 the drive. */ 2754 * because they fill up the sys log when CD players poll
2755 * the drive.
2756 */
2482 switch (cmd) { 2757 switch (cmd) {
2483 case CDROMSUBCHNL: { 2758 case CDROMSUBCHNL:
2484 struct cdrom_subchnl q; 2759 return cdrom_ioctl_get_subchnl(cdi, argp);
2485 u_char requested, back; 2760 case CDROMREADTOCHDR:
2486 if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2761 return cdrom_ioctl_read_tochdr(cdi, argp);
2487 return -ENOSYS; 2762 case CDROMREADTOCENTRY:
2488 /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 2763 return cdrom_ioctl_read_tocentry(cdi, argp);
2489 IOCTL_IN(arg, struct cdrom_subchnl, q); 2764 case CDROMPLAYMSF:
2490 requested = q.cdsc_format; 2765 return cdrom_ioctl_play_msf(cdi, argp);
2491 if (!((requested == CDROM_MSF) || 2766 case CDROMPLAYTRKIND:
2492 (requested == CDROM_LBA))) 2767 return cdrom_ioctl_play_trkind(cdi, argp);
2493 return -EINVAL; 2768 case CDROMVOLCTRL:
2494 q.cdsc_format = CDROM_MSF; 2769 return cdrom_ioctl_volctrl(cdi, argp);
2495 if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) 2770 case CDROMVOLREAD:
2496 return ret; 2771 return cdrom_ioctl_volread(cdi, argp);
2497 back = q.cdsc_format; /* local copy */
2498 sanitize_format(&q.cdsc_absaddr, &back, requested);
2499 sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
2500 IOCTL_OUT(arg, struct cdrom_subchnl, q);
2501 /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
2502 return 0;
2503 }
2504 case CDROMREADTOCHDR: {
2505 struct cdrom_tochdr header;
2506 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2507 return -ENOSYS;
2508 /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
2509 IOCTL_IN(arg, struct cdrom_tochdr, header);
2510 if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))
2511 return ret;
2512 IOCTL_OUT(arg, struct cdrom_tochdr, header);
2513 /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
2514 return 0;
2515 }
2516 case CDROMREADTOCENTRY: {
2517 struct cdrom_tocentry entry;
2518 u_char requested_format;
2519 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2520 return -ENOSYS;
2521 /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
2522 IOCTL_IN(arg, struct cdrom_tocentry, entry);
2523 requested_format = entry.cdte_format;
2524 if (!((requested_format == CDROM_MSF) ||
2525 (requested_format == CDROM_LBA)))
2526 return -EINVAL;
2527 /* make interface to low-level uniform */
2528 entry.cdte_format = CDROM_MSF;
2529 if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))
2530 return ret;
2531 sanitize_format(&entry.cdte_addr,
2532 &entry.cdte_format, requested_format);
2533 IOCTL_OUT(arg, struct cdrom_tocentry, entry);
2534 /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
2535 return 0;
2536 }
2537 case CDROMPLAYMSF: {
2538 struct cdrom_msf msf;
2539 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2540 return -ENOSYS;
2541 cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
2542 IOCTL_IN(arg, struct cdrom_msf, msf);
2543 return cdo->audio_ioctl(cdi, cmd, &msf);
2544 }
2545 case CDROMPLAYTRKIND: {
2546 struct cdrom_ti ti;
2547 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2548 return -ENOSYS;
2549 cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
2550 IOCTL_IN(arg, struct cdrom_ti, ti);
2551 CHECKAUDIO;
2552 return cdo->audio_ioctl(cdi, cmd, &ti);
2553 }
2554 case CDROMVOLCTRL: {
2555 struct cdrom_volctrl volume;
2556 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2557 return -ENOSYS;
2558 cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
2559 IOCTL_IN(arg, struct cdrom_volctrl, volume);
2560 return cdo->audio_ioctl(cdi, cmd, &volume);
2561 }
2562 case CDROMVOLREAD: {
2563 struct cdrom_volctrl volume;
2564 if (!CDROM_CAN(CDC_PLAY_AUDIO))
2565 return -ENOSYS;
2566 cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
2567 if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))
2568 return ret;
2569 IOCTL_OUT(arg, struct cdrom_volctrl, volume);
2570 return 0;
2571 }
2572 case CDROMSTART: 2772 case CDROMSTART:
2573 case CDROMSTOP: 2773 case CDROMSTOP:
2574 case CDROMPAUSE: 2774 case CDROMPAUSE:
2575 case CDROMRESUME: { 2775 case CDROMRESUME:
2576 if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2776 return cdrom_ioctl_audioctl(cdi, cmd);
2577 return -ENOSYS; 2777 }
2578 cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
2579 CHECKAUDIO;
2580 return cdo->audio_ioctl(cdi, cmd, NULL);
2581 }
2582 } /* switch */
2583 2778
2584 /* do the device specific ioctls */ 2779 /*
2780 * Finally, do the device specific ioctls
2781 */
2585 if (CDROM_CAN(CDC_IOCTLS)) 2782 if (CDROM_CAN(CDC_IOCTLS))
2586 return cdo->dev_ioctl(cdi, cmd, arg); 2783 return cdi->ops->dev_ioctl(cdi, cmd, arg);
2587 2784
2588 return -ENOSYS; 2785 return -ENOSYS;
2589} 2786}
2590 2787