Apple Superdrive unter FreeBSD

fbsd470

Member
Hallo zusammen,

aus meiner Apple Zeit habe ich noch ein Superdrive (USB CD/DVD-Brenner) rumliegen. Dieses habe ich nun unter FreeBSD in Betrieb genommen, was aber nicht ganz reibungslos verlaufen ist. Von meinem Linux-Rechner weiß ich, dass das Superdrive erst mal mit einer magischen Bytefolge entsperrt werden muss, bevor es an einem nicht Apple-Rechner verwendet werden kann. Gelöst is das Ganze dort mit einer .rules Datei, die folgende Zeile enthält:
Code:
ACTION=="add", ATTRS{idProduct}=="1500", ATTRS{idVendor}=="05ac", DRIVERS=="usb", RUN+="/usr/bin/sg_raw /dev/$kernel EA 00 00 00 00 00 01"

Diese Regel habe ich nun nach FreeBSD in /usr/local/etc/devd/applesd.conf portiert:
Code:
notify 100 {
    match "system"        "USB";
    match "subsystem"    "DEVICE";
    match "type"        "ATTACH";
    match "vendor"        "0x05ac";
    match "product"        "0x1500";
    action "exec /usr/local/bin/applesd.sh";
};

Das aufgerufene Script applesd.sh schreibt anschließend die magic bytes ins Superdrive:
Code:
#!/bin/sh

sleep 1
camcontrol cmd cd0 -c "EA 00 00 00 00 00 01"

Beim Script musste ich etwas improvisieren, da ich auf zwei Probleme gestoßen bin:
  • die devd-Nachricht enthält keine direkt verwertbaren Informationen zur device-id, die ich als Adresse für camcontrol verwenden könnte
  • wenn ich das camcontrol Kommando direkt als 'action' angebe, führt dieses nicht zum Erfolg, da es offenbar zu früh kommt

Da ich sowieso nie mehr als ein CD/DVD-Laufwerk an meinen Rechner anschließe, habe ich das Device 'cd0' einfach direkt ins Script geschrieben. Zum Lösen des Timing Problems dient eine simple 'sleep' Anweisung. Ohne diese klappt es nicht, offenbar dauert es etwas bis das Laufwerk an den Bus angehängt und anschließend das Device angelegt wird.


Was mich nun brennend interessieren würde: wie könnte man so etwas professioneller lösen? Habt ihr so etwas oder was ähnliches schon mal gemacht?



Hier noch die Ausgabe von devd zum 'attach event':
Code:
!system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.3 cdev=ugen0.3 vendor=0x05ac product=0x1500 devclass=0x00 devsubclass=0x00 sernum="KZ8EC2L2638         " release=0x0203 mode=host port=1 parent=ugen0.1

und die Device-Liste von camcontrol:
Code:
# camcontrol devlist
<Apple SuperDrive 2.03>            at scbus0 target 0 lun 0 (cd0,pass0)
 

mr44er

moderater Moderator
Teammitglied
wie könnte man so etwas professioneller lösen?
1.) Am elegantesten mit einer modifizierten firmware, die man dann auf das Laufwerk flasht. Da bezweifle ich aber instinktiv, dass es eine solche gibt, weil Apple und weil
2.) ein freies Laufwerk ohne Gedöhnse ~30€ kostet
3.) /sbin/camcontrol cmd cd0 -c "EA 00 00 00 00 00 01" in /etc/rc.local schreiben. Oder wie das Laufwerk eben heißt camcontrol devlist... /dev/ada1 .../dev/da0..etc
Das geht aber dann auch nur wenn das Ding beim Start eingesteckt ist.
 

pit234a

Well-Known Member
Code:
cat /var/run/devd.pipe
zeigt, wann das Gerät erkannt wurde. Wie man das aber von einem Script aus fischen kann, weiß ich nicht.
Tatsächlich hatte ich früher auch solch einen Super-Drive. Das ist schon lange her, aber der hatte sofort funktioniert, ohne alles Gedöns.
Nachdem ich ihn irgendwann nicht mehr finden konnte, ersetzte ich das Dingens durch Standard-Geräte und vermisse ihn nicht.
 

Yamagi

Possessed With Psi Powers
Teammitglied
Das Problem ist, dass ein USB-Gerät in zwei Phasen angemeldet wird. Nicht nur unter FreeBSD, sondern generell. Sobald der Gerät-Controller und der Host-Controller sich sehen und der initiale Handshake beendet ist, generiert der Kernel das generische ugenX.Y-Device und sendet das Attach Event. Erst danach handeln Kernel und Gerät-Controller die Details aus. Meist geht es schnell, aber es gibt Geräte, die ewig brauchen. Mein Spitzenreiter ist mein Garmin Dakota 50, was sich gute 30 Sekunden Zeit lässt... Leider gibt es kein weiteres Attach-Event, wenn das eigentliche Device bereit ist.

Man kommt also nicht drum herum ein Script dazwischenzuschalten und zu pollen, ob das Device da ist. Da du im devd-Event das ugenX.Y-Device hast, kannst du über usbconfig auf das eigentliche Device kommen. Zum Beispiel: usbconfig -v | grep ugen3.2.0 | awk '{print $2}' | tr -d : Bei ugenX.Y.Z ist Z das Subdevice. Es ist statisch und bei den meisten Geräten 0.

Es so lange ausführen, bis das Device gefunden wurde. Anschließend kann man das Device in camcontrol füttern.

Eventuell bekommt man es noch etwas eleganter hin. Grundsätzlich bleibt die Frage, ob es den Aufwand wert ist und man nicht auch einfach damit leben kann, dass cd0 hardgecodet ist. :)
 

crotchmaster

happy BSD user
1.) Am elegantesten mit einer modifizierten firmware, die man dann auf das Laufwerk flasht. Da bezweifle ich aber instinktiv, dass es eine solche gibt, weil Apple und weil
2.) ein freies Laufwerk ohne Gedöhnse ~30€ kostet
3.) /sbin/camcontrol cmd cd0 -c "EA 00 00 00 00 00 01" in /etc/rc.local schreiben. Oder wie das Laufwerk eben heißt camcontrol devlist... /dev/ada1 .../dev/da0..etc
Das geht aber dann auch nur wenn das Ding beim Start eingesteckt ist.
Es gibt noch eine 4. Möglichkeit. Man kann die Interfaceplatine im Laufwerk tauschen, man sollte allerdings wissen, wo beim Lötkolben vorne und hinten ist. :D
Dann funktioniert das Laufwerk sowohl an PCs, als auch Macs, die selber ein CD/DVD-Laufwerk haben und deshalb des externe Apple Laufwerk verschmähen. Ginge auch mit dem 30€ Laufwerk, hätte aber nicht so ein elegantes Aussehen. ;)
Ich habe das vor einigen Jahren mal gemacht.
 

mr44er

moderater Moderator
Teammitglied
man sollte allerdings wissen, wo beim Lötkolben vorne und hinten ist.
Das merkt man spätestens, wenn es nach bacon riecht. Richtig gemacht hinterlässt man aber auch keine Fingerabdrücke mehr. :D

Aus Interesse und der TE wird es auch fragen: Bekommt man die Platine noch? Wenn man das non-branded pendant gebraucht kaufen müsste fürs Schlachten, kann man ja auch gleich dieses Laufwerk nutzen.
 

fbsd470

Member
...schön wie sich dieser Thread entwickelt :)

Ich muss aber gestehen, meine Frage ist eher theoretischer Natur. Das Superdrive hänge ich höchstens 2-3 mal pro Jahr an einen Rechner, öfter brauche ich das nicht. Und für die paar Mal könnte ich natürlich das camcontrol Kommando per Hand reinklopfen.
Mir geht es hauptsächlich darum was zu lernen. Ich denke ich verfolge den Vorschlag von @Yamagi weiter und suche mir die passenden Script-Schnipsel aus dem www zusammen. Sobald ich was brauchbares habe stelle ich es hier vor.

Btw, löten könnte ich sogar einigermaßen, aber ein Umbau der Hardware rentiert sich bei der sporadischen Nutzung nicht.
 

pit234a

Well-Known Member
was mir aber noch durch den Kopf ging: dsbmd von @marcel macht eigentlich schon sehr viel, was gebraucht wird.
@marcel wird mir hier nicht mehr aufgelistet, womöglich hat er sich abgemeldet.
Über nomad-bsd könnte man ihn vielleicht finden.
dsbmd pollt ja auf neue Geräte und kann dann auch Regeln befolgen, sie schließlich dem dsbmc zum mounten übergeben.
In meiner unbekümmerten und von keinem Fachwissen getrübten Überlegung, könnte es da ziemlich einfach sein, das Gerät von dsbmd entsprechend behandeln zu lassen. Ich gründe diese Vermutung darauf, dass auch manuell angelegte md-Geräte durch die SW entsprechend behandelt und aufbereitet werden. In einem dsbmc erscheinen die dann als neue HW, wie wenn ein neues Gerät angestöpselt oder eine neue CD/DVD eingelegt wird. Ich denke mir nun, dass für ein Super-Drive (wenn es eindeutig als solches erkannt werden kann) einfach eine zusätzliche Regel ausgeführt werden braucht und schwups, schon wäre es da...
 

fbsd470

Member
ok, jetzt habe ich ein paar Infos zusammengesucht um die Idee von @Yamagi weiterzuentwickeln. Es scheint als würde das doch eine ziemliche Odyssee:
  • das devd event liefert über die Variable cdev den String "ugen0.3"
  • diesen müsste man um .0 zu "ugen0.3.0" ergänzen und anschließend das Ergebnis von usbconfig -v danach parsen
  • so kommt man an die unit number von umass ran (hier 0). Laut https://arrowd.name/posts/2015-08-23-scsi-usb.html ist die Nummer von umass-sim die gleiche wie die von umass
  • anschließend die Ausgabe von camcontrol devlist -b nach "umass-sim0" absuchen und "scbus#" (bei mir 0) extrahieren
  • nun noch die Liste von camcontrol devlist nach "scbus#" absuchen und die target Nummer extrahieren
  • die Nummer von scbus und vom target können anschließend als Adresse (hier 0:0) für camcontrol hergenommen werden

Uff, ganz schön heftig. Ich belasse es deshalb bei meinem quick & dirty Ansatz mit hartkodiertem cd0 und kurzer sleep Anweisung.

Aus Interesse habe ich dann noch eine minimal "bessere" Lösung gebastelt, diese prüft ob das Device cd0 angelegt wurde und schreibt erst dann das Kommando raus. Nach spätestens 5 Sekunden wird so oder so abgebrochen:
Code:
#!/bin/sh

t1=$(date "+%s")

while [ $(($(date "+%s")-$t1)) -lt 5 ]
do
    if [ ! -z "$(camcontrol devlist | grep cd0)" ]
    then
        camcontrol cmd cd0 -c "EA 00 00 00 00 00 01"
        break
    fi
done

Funktionieren tut beides :rolleyes:
 

mr44er

moderater Moderator
Teammitglied
  • das devd event liefert über die Variable cdev den String "ugen0.3"
  • diesen müsste man um .0 zu "ugen0.3.0" ergänzen und anschließend das Ergebnis von usbconfig -v danach parsen
Die ids ändern sich auch gern mal ratzfatz komplett, wenn man an einen anderen USB-Slot steckt oder vorher schon ein Gerät mehr steckt als sonst. Oft ist auch das frontpanel an einem ganz anderen Controller mit ganz anderem Chip.
Random Beispiel:
Code:
root@ws01:/mnt # usbconfig
ugen0.1: <Intel UHCI root HUB> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen8.1: <AMD XHCI root HUB> at usbus8, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=SAVE (0mA)
ugen1.1: <Intel UHCI root HUB> at usbus1, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen3.1: <Intel EHCI root HUB> at usbus3, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen4.1: <Intel UHCI root HUB> at usbus4, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen5.1: <Intel UHCI root HUB> at usbus5, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen6.1: <Intel UHCI root HUB> at usbus6, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen7.1: <Intel EHCI root HUB> at usbus7, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen2.1: <Intel UHCI root HUB> at usbus2, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen7.2: <QEMU QEMU USB Tablet> at usbus7, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (100mA)
ugen8.2: <vendor 0x1a40 USB 2.0 Hub> at usbus8, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (100mA)
ugen8.3: <NOVATEK USB Keyboard> at usbus8, cfg=0 md=HOST spd=LOW (1.5Mbps) pwr=ON (100mA)
ugen8.4: <Logitech USB-PS/2 Optical Mouse> at usbus8, cfg=0 md=HOST spd=LOW (1.5Mbps) pwr=ON (98mA)

Noch eine andere Idee: Eventuell hast du noch einen ganz alten MüllPC im Keller mit IDE-Laufwerk. Diese Adapter funktionieren ganz ok damit, CD/DVD lesen ist eh lahm und sind auf jeden Fall billiger zu bekommen als ein Laufwerk:
I721270.1-goobay-USB-zu-IDE-SATA-Adapter-Set.jpg
 

crotchmaster

happy BSD user
Update: Ich habe damals, das war schon 2012, diesen Adapter verwendet, den es allerdings nicht mehr gibt: DeLock 61704
Die kleine Platine für die Stromversorgung und die USB-B Buchse habe ich abgelötet und da das Kabel des Superdrives angelötet. Natürlich auf die Belegung der Kabel achten!
Auf dem einen Platinenfoto mit Draufsicht auf die Buchsen sieht man den Quarz. Den hab ich über Verlängerungsdrähte ausgelagert und in Schrumpfschlauch isoliert, da ansonsten kein Platz zwischen Rückseite der Laufwerks und Gehäuse ist. Die Platine aufstecken und mit Tape fixieren. Eine Anleitung zum Öffnen des Laufwerks findet sich bei iFixit.
 

Anhänge

  • IMG_5538.jpeg
    IMG_5538.jpeg
    46,6 KB · Aufrufe: 36
  • IMG_5539.jpeg
    IMG_5539.jpeg
    31 KB · Aufrufe: 34
  • IMG_5540.jpeg
    IMG_5540.jpeg
    38,6 KB · Aufrufe: 38
Oben