aboutsummaryrefslogtreecommitdiff
path: root/toys/other/eject.c
blob: 279f7a3188ea6f5284381331cb5c4d8877f431c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* eject.c - eject device.
 *
 * Copyright 2012 Harvind Singh <harvindsingh1981@gmail.com>
 * Copyright 2013 Kyungwan Han <asura321@gamil.com>
 * Not in SUSv4.

USE_EJECT(NEWTOY(eject, ">1stT[!tT]", TOYFLAG_USR|TOYFLAG_BIN))

config EJECT
  bool "eject"
  default y
  help
    usage: eject [-s] [-t] [-T] [...]

    Eject DEVICE or default /dev/cdrom

    -s  SCSI device
    -t  Close tray
    -T  Open/close tray (toggle).
*/

#define FOR_eject
#include "toys.h"
#include <scsi/sg.h>
#include <scsi/scsi.h>

#define CDROM_DRIVE_STATUS 0x5326 //Get tray position, etc.
#define CDROM_CLOSE_TRAY 0x5319   //Pendant of CDROM_EJECT.
#define CDROM_EJECT 0x5309        //Ejects the cdrom media.
#define DRIVE_NOT_READY 3         //Drive is busy.

/*
 * Remove SCSI Device.
 */
static void remove_scsi(int dscptr)
{
  char sg_driver_cmd[3][6] = {
    { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 }, //allow medium removal
    { START_STOP, 0, 0, 0, 1, 0 }, //start the motor
    { START_STOP, 0, 0, 0, 2, 0 } //eject the media
  };

  unsigned i;
  unsigned char buffer1[32],buffer2[2];
  sg_io_hdr_t in_out_header;

  if ((ioctl(dscptr, SG_GET_VERSION_NUM, &i) < 0) || (i < 30000))
    error_exit("not a sg device or old sg driver");

  memset(&in_out_header, 0, sizeof(sg_io_hdr_t));
  in_out_header.interface_id = 'S';
  in_out_header.cmd_len = 6;
  in_out_header.mx_sb_len = sizeof(buffer1);
  in_out_header.dxfer_direction = SG_DXFER_NONE;
  in_out_header.dxferp = buffer2;
  in_out_header.sbp = buffer1;
  in_out_header.timeout = 2000;

  for (i = 0; i < 3; i++) {
    in_out_header.cmdp = (void *)sg_driver_cmd[i];
    xioctl(dscptr, SG_IO, (void *)&in_out_header);
  }
  /* force kernel to reread partition table when new disc is inserted */
  ioctl(dscptr, BLKRRPART);
}

/*
 * eject main function.
 */
void eject_main(void)
{
  int fd, out = 0, rc = 0;
  char *device_name;
  if (!toys.optc) device_name = "/dev/cdrom";
  else device_name = toys.optargs[0];

  fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
  if (!toys.optflags) xioctl(fd, CDROM_EJECT, &out);
  else if (toys.optflags & FLAG_s) remove_scsi(fd);
  else {
    if (toys.optflags & FLAG_T || toys.optflags & FLAG_t) {
      rc = ioctl(fd, CDROM_DRIVE_STATUS, &out);
      if (toys.optflags & FLAG_t || rc == 2) //CDS_TRAY_OPEN = 2
        xioctl(fd, CDROM_CLOSE_TRAY, &out);
      else xioctl(fd, CDROM_EJECT, &out);
    }
  }
  xclose(fd);
}