Sign in to follow this  
Followers 0
bhoar

Help? Checking CD/DVD Tray position - 99% done, but...

19 posts in this topic

#1 ·  Posted (edited)

[sOLVED - see 8th post]

The idea here is to send a special SCSI command to the drive directly, and have it report back whether or not the tray/door is open or closed. This would improves upon the standard methods that cannot seem to differentiate between an empty but closed tray and an open tray.

I need this specifically because a.) I don't want to interrupt what the drive is doing with another application and b.) I need to make sure all drive trays are closed before moving the robot arm in the space that open trays occupy.

The code below is based primarily on VB and C++ examples found on microsoft's development site and other dev forums, using DeviceIoControl to perform a IOCTL_SCSI_PASS_THROUGH transaction containing the CDB 0xBD which requests "Mechanism Status".

This is what I see as a result of the DeviceIoControl call:

1) The DLLCall does not return an error via $ret[0] or @error, so the general calling dllcall convention seems to be OK.

2) Apparently, the DeviceIoControl does not return a non-null value via $returnvalue, so I take it that worked OK.

3) However, all of the values in the structure I passed seem to be unchanged, which means the call didn't do anything. I don't know if a SCSI command was issued at all.

I'm clearly missing something in the preparation/population of the data structures, access control or with the DeviceIoControl request, but I am currently at a loss as to why all the data comes back from the call unchanged. I've tried several CDB sizes (8,10,12,16).

Anyone want a challenge? :D

[this is my continuation of an ancient discussion here: http://www.autoitscript.com/forum/index.php?showtopic=25089 ]

EDIT: attachment removed. See eight post for final version.

-brendan

Edited by bhoar

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Oh scrap that, still buggy. But at least the SCSI call is executing.

(removed attachment)

-brendan

Edited by bhoar

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Ok, here's the final one. It finally works....got bit by AND vs. BITAND.

Little bit of humor there. Oof. Was that a TOS violation? :D

Thanks to Robert Nelson for assistance.

-brendan

Edited by bhoar

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

DON'T WORK FOR ME (I HAVE ATAPI DVD-RW)

LOCK/UNLOCK WORK, BUT I DON'T KNOW CHECK THIS.

MsgBox(4096, LockDevice("E:", 1), "Try yo CD")
MsgBox(4096, LockDevice("E:", 0), "All Better")
Func LockDevice($szdrivewithcolon, $block)
 Local Const $invalid_handle_value = -1
 Local Const $open_existing = 3
 Local Const $file_attribute_normal = 128
 Local Const $file_share_write = 2
 Local Const $file_share_read = 1
 Local Const $generic_read = 2147483648
 Local Const $ioctl_storage_media_removal = 2967556
 
 $block = Not (Not $block)
 $szdrivewithcolon = StringReplace($szdrivewithcolon, "", "")
 If StringLen($szdrivewithcolon) <> 2 Then Return -1
 
 $szdrivewithcolon = "\\.\"& $szdrivewithcolon
 
 $hdrive = DllCall("kernel32.dll", "int", "CreateFile", "str", $szdrivewithcolon, _
   "int", $generic_read, "int", BitOR($file_share_read, $file_share_write), "ptr", 0, "int", $open_existing, _
   "int", $file_attribute_normal, "ptr", 0)
 
 If $hdrive[0] = $invalid_handle_value Then Return -2
 
 $bool = DLLStructCreate ("byte")
 DLLStructSetData ($bool, 1, $block)
 
 $lockmediarslt = DllCall("kernel32.dll", "int", "DeviceIoControl", "int", $hdrive[0], _
   "int", $ioctl_storage_media_removal, "ptr", DllStructGetPtr ($bool), "int", 1, _
   "int", 0, "int", 0, "int_ptr", 0, "ptr", 0)
 DllCall("kernel32.dll", "int", "CloseHandle", "int", $hdrive[0])
 $bool = 0
 
 Return $lockmediarslt[0]
EndFunc   ;==>LockDevice
Edited by psandu.ro

Share this post


Link to post
Share on other sites

DON'T WORK FOR ME (I HAVE ATAPI DVD-RW)

Try this change:

replace:
    DllStructSetData($sptwb, 6, $CDBSIZE);Length of CDB to be set before making call - or always 12?
with:
    DllStructSetData($sptwb, 6, 12);Length of real CDB to be set before making call - or always 12?

-brendan

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Updated code with above change and to be better organized.

-brendan

Edited by bhoar

Share this post


Link to post
Share on other sites

Very strange problem, but it's definitely tracking the tray status

On my win2000 system with a USB DVD-RW, this works:

$second_byte = DllStructGetData($sptwb, 16, 2) ;should be the second byte
    ;now we need the bit here 00010000
    
    $traystatus = BitAND($second_byte, 0x10)

That is, I have to change to change the byte I'm grabbing the flag from.

Something odd is going on. Gotta figure out if it's me or if it's windows. Probably me. :D

-brendan

Share this post


Link to post
Share on other sites

Fixed: I stupidly changed the buffer size of the sense response to an odd number.

Tested this against several drives both USB and IDE/ATAPI on 2K and XP. It uses SPTI, not ASPI, so it will not work on 95/98/ME.

This should be the final version of this example.

Sorry for all the posts pushing this thread to the top. Maybe someone will find the SCSI stuff useful someday.

-brendan

cdtray_routines.au3

Share this post


Link to post
Share on other sites

sorry.

don't work!

$second_byte = DllStructGetData($sptwb, 16, 2) ;should be the second byte

;now we need the bit here 00010000

$second_byte=0 everytime

i try $second_byte = DllStructGetData($sptwb, 16, 1) and nothing.

Share this post


Link to post
Share on other sites

i reinstall autoit and work!

sorry and thanks.

the questions is how now: how i check if cd-tray is blocked or not?

Share this post


Link to post
Share on other sites

i reinstall autoit and work!

sorry and thanks.

the questions is how now: how i check if cd-tray is blocked or not?

Blocked...or Locked?

-brendan

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I don't see a scsi command that will tell me whether or not a drive is locked or unlocked. However, we can tell it to lock/unlock.

So... I did update the routines so that, in addition to reporting on the current tray status, you can also lock/unlock the trays and load/unload (=mount/eject) the trays as well. Yes, CDTray can do that last one, I know. :D

See attached.

-brendan

cdtray_routines.au3

Edited by bhoar

Share this post


Link to post
Share on other sites

work on Combo Drive but on CD-RW don't work for me.

It's always closed.

Share this post


Link to post
Share on other sites

If you uncomment-out (comment-in? heh.) the debugging code, you should be able to record if the response from the drive is the same in both situations. Older drives had their firmware written before the MMC-3 standard (or perhaps MMC-2) added the tray flag to the mechanism status response.

I should really be writing results to file, though. More updates later.

-brendan

Share this post


Link to post
Share on other sites

I tried both posts 8 and 12 but they say the same thing... an error message about line 76 or 72

$cdb = DllStructCreate($CDB_STRUCT)

$cdb = ^ ERROR

Error: Unknown function name

a little help would be appreciative

Share this post


Link to post
Share on other sites

IIRC, you need to be using the beta (or at least what was beta at the time I wrote the script).

-brendan

Share this post


Link to post
Share on other sites

Is this just for SCSI drives?

I was looking for something to Lock/Unlock my IDE DVD/CD drive.


2015 - Still no flying cars, instead blankets with sleeves.

Share this post


Link to post
Share on other sites

Is this just for SCSI drives?

I was looking for something to Lock/Unlock my IDE DVD/CD drive.

It works for all optical drives (SCSI, IDE/ATA/PATA, SATA, Firewire, USB) that I have tested, though success via USB may be limited by the bridge chipset in use at the time.

Here's a snippet you could combine with the above approach for locking/unlocking the drive:

CODE
Func PopulateCDB_LockTray(ByRef $cdb)

$fname = "PopulateCDB_LockTray"

$CDBCOMMAND = 0x1E ;Prevent/Allow Medium Removal

DllStructSetData($cdb, 1, $CDBCOMMAND, 1)

DllStructSetData($cdb, 1, 0x00, 2)

DllStructSetData($cdb, 1, 0x00, 3)

DllStructSetData($cdb, 1, 0x00, 4)

DllStructSetData($cdb, 1, 0x01, 5); Lock = Set bit 0 to 1

DllStructSetData($cdb, 1, 0x00, 6)

DllStructSetData($cdb, 1, 0x00, 7)

DllStructSetData($cdb, 1, 0x00, 8)

DllStructSetData($cdb, 1, 0x00, 9)

DllStructSetData($cdb, 1, 0x00, 10)

DllStructSetData($cdb, 1, 0x00, 11)

DllStructSetData($cdb, 1, 0x00, 12)

;The next four are not used for ATAPI compatibility, but should be set to zero anyway.

DllStructSetData($cdb, 1, 0x00, 13)

DllStructSetData($cdb, 1, 0x00, 14)

DllStructSetData($cdb, 1, 0x00, 15)

DllStructSetData($cdb, 1, 0x00, 16)

EndFunc ;==>PopulateCDB_LockTray

Func PopulateCDB_UnLockTray(ByRef $cdb)

$fname = "PopulateCDB_UnLockTray"

$CDBCOMMAND = 0x1E ;Prevent/Allow Medium Removal

DllStructSetData($cdb, 1, $CDBCOMMAND, 1)

DllStructSetData($cdb, 1, 0x00, 2)

DllStructSetData($cdb, 1, 0x00, 3)

DllStructSetData($cdb, 1, 0x00, 4)

DllStructSetData($cdb, 1, 0x00, 5); Unlock = Set bit 0 to 0

DllStructSetData($cdb, 1, 0x00, 6)

DllStructSetData($cdb, 1, 0x00, 7)

DllStructSetData($cdb, 1, 0x00, 8)

DllStructSetData($cdb, 1, 0x00, 9)

DllStructSetData($cdb, 1, 0x00, 10)

DllStructSetData($cdb, 1, 0x00, 11)

DllStructSetData($cdb, 1, 0x00, 12)

;The next four are not used for ATAPI compatibility, but should be set to zero anyway.

DllStructSetData($cdb, 1, 0x00, 13)

DllStructSetData($cdb, 1, 0x00, 14)

DllStructSetData($cdb, 1, 0x00, 15)

DllStructSetData($cdb, 1, 0x00, 16)

EndFunc ;==>PopulateCDB_UnLockTray

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0