Re: Asynchronous CDROM Events in Userland

Jens Axboe (axboe@suse.de)
Mon, 4 Feb 2002 08:57:12 +0100


--C7zPtVaVf+AK4Oqc
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Feb 04 2002, Erik Andersen wrote:
> Jens Axboe and I wrote a little test app a year or two ago to check
> for whether drives supported asynchronous mode. We found it to be
> unsupported on 100% of the drives we tested (and we tested quite a
> few)...

Yep, _no_ drives to date support queued event notification. However, a
polled approach is really not too bad -- it simply means that we'll push
it to user space instead. I've written a small utility for reference.

-- 
Jens Axboe

--C7zPtVaVf+AK4Oqc Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="cd_poll.c"

/* * simple media event poller for cdroms implementing the GET_EVENT * interface * * Copyright (C) 2001 Jens Axboe <axboe@suse.de> */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/ioctl.h>

#include <linux/cdrom.h>

#define INIT_CGC(cgc) memset((cgc), 0, sizeof(struct cdrom_generic_command))

void dump_cgc(struct cdrom_generic_command *cgc) { struct request_sense *sense = cgc->sense; int i;

printf("cdb: "); for (i = 0; i < 12; i++) printf("%02x ", cgc->cmd[i]); printf("\n");

printf("buffer (%d): ", cgc->buflen); for (i = 0; i < cgc->buflen; i++) printf("%02x ", cgc->buffer[i]); printf("\n");

if (!sense) return;

printf("sense: %02x.%02x.%02x\n", sense->sense_key, sense->asc, sense->ascq); }

int wait_cmd(int fd, struct cdrom_generic_command *cgc, void *buffer, int len, int ddir, int timeout) { struct request_sense sense; int ret;

memset(&sense, 0, sizeof(sense));

cgc->timeout = timeout; cgc->buffer = buffer; cgc->buflen = len; cgc->data_direction = ddir; cgc->sense = &sense; cgc->quiet = 1;

ret = ioctl(fd, CDROM_SEND_PACKET, cgc); if (ret == -1) { perror("ioctl"); dump_cgc(cgc); }

return ret; }

int get_media_event(int fd) { struct cdrom_generic_command cgc; unsigned char buffer[8]; int ret;

INIT_CGC(&cgc); memset(buffer, 0, sizeof(buffer));

cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; cgc.cmd[1] = 1; cgc.cmd[4] = 16; cgc.cmd[8] = sizeof(buffer);

ret = wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, 600); if (ret < 0) { perror("GET_EVENT"); return ret; }

return buffer[4] & 0xf; }

int poll_events(int fd) { int event, quit, first;

quit = 0; first = 1; do { event = get_media_event(fd); if (event < 0) break;

switch (event) { case 0: if (first) printf("no media change\n"); break; case 1: printf("eject request\n"); break; case 2: printf("new media\n"); break; case 3: printf("media removal\n"); break; case 4: printf("media change\n"); break; default: printf("unknown media event (%d)\n", event); break; }

first = 0;

if (event) continue;

sleep(2);

} while (!quit);

return event; }

int main(int argc, char *argv[]) { int fd;

fd = open("/dev/cdrom", O_RDONLY | O_NONBLOCK); if (fd == -1) { perror("open"); return 1; }

return poll_events(fd); }

--C7zPtVaVf+AK4Oqc-- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/