diff options
-rw-r--r-- | drivers/cdrom/cdrom.c | 877 |
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 | 2199 | static 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 | */ | ||
2203 | int 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); | 2232 | static 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); | 2249 | static 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: { | 2258 | static 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 */ | 2274 | static 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: { | 2303 | static 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)) | 2331 | static 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: { | 2340 | static 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: { | 2350 | static 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 | |||
2375 | static 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 | |||
2388 | static 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 | |||
2407 | static 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 | 2418 | static 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: { | 2430 | static 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: { | 2450 | static 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 | */ | ||
2482 | static 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 | |||
2512 | static 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 | |||
2518 | static 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 | |||
2551 | static 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 | |||
2574 | static 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 | |||
2604 | static 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 | |||
2618 | static 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 | } | ||
2636 | static 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 | |||
2650 | static 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 | |||
2670 | static 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 | */ | ||
2690 | int 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 | ||