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