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
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