Check out the new blog at http://linuxehacking.ovh , this one will no longer be updated

venerdì 12 luglio 2013

How To: Emulatore DVD-ROM Hardware USB

Cosa è un emulatore DVD-ROM hardware

Un emulatore DVD-ROM hardware è un dispositivo che svolge un compito simile a quello di programmi come Daemon Tools o un device loop su linux, ma lo svolge presentandosi come un vero e proprio drive USB dvd-rom.
Le potenzialità di ciò sono che non può essere beccato dai DRM dei videogiochi e permette di fare il boot dal BIOS di qualsiasi ISO senza usare programmi come unetbootin.

Occorrente

  • BeagleBone Black
  • Una o più macchine con Linux possibilmente decenti ( se si intende ricompilare da se il driver )
  • Un minimo di praticità nell'uso di Linux, e nella compilazione di kernel/drivers
La beagleboneblack esce attualmente con Linux 3.8.13 , per utilizzarla in questo modo, onde evitare problemi con BIOS poco tolleranti, va eliminato il driver g_multi.ko
Una volta eliminato quel driver e riavviata la board è possibile scaricare il driver per il kernel precompilato della beaglebone qui g_mass_storage.ko .
Per utilizzare il driver è sufficiente eseguire il comando come root:
#insmod g_mass_storage.ko file=/percorsoimmagineiso cdrom=1 ro=1

Una volta eseguito il comando dopo pochi secondi dovrebbe comparire sul PC al quale è collegata la beaglebone un lettore DVD con dentro il "dischetto"

Kernel non standard e sorgenti delle modifiche

Per poter utilizzare immagini ISO > 2.4 GB ho dovuto applicare delle modifiche al driver del gadget mass storage che riporto di seguito:

commit f6037e02d14c57531efc14074aa59b0054227f8c
Author: Tiziano Bacocco <tiziano@localhost.localdomain>
Date:   Fri Jul 12 13:04:43 2013 +0200

    DVD-ROM Patch

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 5d027b3..cb87b4a 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -1192,6 +1192,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
  return -EINVAL;
  }
 
+ printk("readcap: %ld\n",curlun->num_sectors-1);
  put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
  /* Max logical block */
  put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
@@ -1220,6 +1221,63 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
  return 8;
 }
 
+static int do_read_disc_information(struct fsg_common* common, struct fsg_buffhd * bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ if (common->cmnd[1] & ~0x02) { /* Mask away MSF */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ u8* outbuf = (u8*)bh->buf;
+ memset(outbuf,0,34);
+ outbuf[1] = 32;
+ outbuf[2] = 0xe; /* last session complete, disc finalized */
+ outbuf[3] = 1;   /* first track on disc */
+ outbuf[4] = 1;   /* # of sessions */
+ outbuf[5] = 1;   /* first track of last session */
+ outbuf[6] = 1;   /* last track of last session */
+ outbuf[7] = 0x20; /* unrestricted use */
+ outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */
+ return 34;
+}
+
+static int do_get_configuration(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ if (common->cmnd[1] & ~0x02) { /* Mask away MSF */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ u8* buf = (u8*)bh->buf;
+ int cur;
+ if ( curlun->num_sectors > CD_MAX_SECTORS )
+ {
+ printk("Is dvd\n");
+ cur = MMC_PROFILE_DVD_ROM;
+ }
+ else
+ cur = MMC_PROFILE_CD_ROM;
+ memset(buf,0,40);
+ put_unaligned_be32(36,&buf[0]);
+ put_unaligned_be16(cur,&buf[6]);
+ buf[10] = 0x03;
+ buf[11] = 8;
+ put_unaligned_be16(MMC_PROFILE_DVD_ROM,&buf[12]);
+ buf[14] = ( cur == MMC_PROFILE_DVD_ROM );
+ put_unaligned_be16(MMC_PROFILE_CD_ROM,&buf[16]);
+ buf[18] = ( cur == MMC_PROFILE_CD_ROM );
+ put_unaligned_be16(1,&buf[20]);
+ buf[22] = 0x08 | 0x03;
+ buf[23] = 8;
+ put_unaligned_be32(1,&buf[24]);
+ buf[28] = 1;
+ put_unaligned_be16(3,&buf[32]);
+ buf[34] = 0x08 | 0x3;
+ buf[35] = 4;
+ buf[36] = 0x39;
+ return 40;
+}
+
 static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
 {
  struct fsg_lun *curlun = common->curlun;
@@ -1245,6 +1303,7 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
  buf[14] = 0xAA; /* Lead-out track number */
  store_cdrom_address(&buf[16], msf, curlun->num_sectors);
  return 20;
+
 }
 
 static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
@@ -1727,9 +1786,9 @@ static int check_command(struct fsg_common *common, int cmnd_size,
  if (common->data_dir != DATA_DIR_UNKNOWN)
  sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
  common->data_size);
- VDBG(common, "SCSI command: %s;  Dc=%d, D%c=%u;  Hc=%d%s\n",
-      name, cmnd_size, dirletter[(int) data_dir],
-      common->data_size_from_cmnd, common->cmnd_size, hdlen);
+ //printk( "SCSI command: %s;  Dc=%d, D%c=%u;  Hc=%d%s\n",
+   //   name, cmnd_size, dirletter[(int) data_dir],
+  //    common->data_size_from_cmnd, common->cmnd_size, hdlen);
 
  /*
   * We can't reply at all until we know the correct data direction
@@ -2087,7 +2146,21 @@ static int do_scsi_command(struct fsg_common *common)
  if (reply == 0)
  reply = do_write(common);
  break;
-
+ case 0x51://READ_DISC_INFORMATION
+ common->data_size_from_cmnd = 0;
+ if (!common->curlun || !common->curlun->cdrom)
+ goto unknown_cmnd;
+ printk("READ_DISC_INFORMATION\n");
+
+ reply = do_read_disc_information(common,bh);
+    break;
+ case 0x46://GET_CONFIGURATION
+ common->data_size_from_cmnd = 0;
+ if (!common->curlun || !common->curlun->cdrom)
+ goto unknown_cmnd;
+ printk("GET_CONFIGURATION\n");
+ reply = do_get_configuration(common,bh);
+ break;
  /*
   * Some mandatory commands that we recognize but don't implement.
   * They don't mean much in this setting.  It's left as an exercise
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 0e3ae43..f328ab6 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -124,6 +124,42 @@ struct interrupt_data {
 #define SS_WRITE_ERROR 0x030c02
 #define SS_WRITE_PROTECTED 0x072700
 
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
+
 #define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
 #define ASC(x) ((u8) ((x) >> 8))
 #define ASCQ(x) ((u8) (x))
@@ -165,7 +201,6 @@ static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev)
  return container_of(dev, struct fsg_lun, dev);
 }
 
-
 /* Big enough to hold our biggest descriptor */
 #define EP0_BUFSIZE 256
 #define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
@@ -540,12 +575,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
  min_sectors = 1;
  if (curlun->cdrom) {
  min_sectors = 300; /* Smallest track is 300 frames */
- if (num_sectors >= 256*60*75) {
+ /*if (num_sectors >= 256*60*75) {
  num_sectors = 256*60*75 - 1;
  LINFO(curlun, "file too big: %s\n", filename);
  LINFO(curlun, "using only first %d blocks\n",
  (int) num_sectors);
- }
+ }*/
  }
  if (num_sectors < min_sectors) {
  LINFO(curlun, "file too small: %s\n", filename);
@@ -562,6 +597,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
  curlun->filp = filp;
  curlun->file_length = size;
  curlun->num_sectors = num_sectors;
+ printk("lun_open: %zd\n",curlun->num_sectors-1);
  LDBG(curlun, "open backing file: %s\n", filename);
  return 0;
 
@@ -596,6 +632,8 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
  addr /= 75;
  dest[2] = addr % 60; /* Seconds */
  addr /= 60;
+ if ( addr > 255 )
+ printk("store_cdrom_address: overflow \n");
  dest[1] = addr; /* Minutes */
  dest[0] = 0; /* Reserved */
  } else {


Questa patch applicata al kernel che si sta compilando permette di ottenere il driver modificato con il supporto alle immagini > 2.4 GB