📄 dvdioctl.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include <atamain.h>
static DWORD rkret[] =
{
sizeof (RKFMT_AGID) << 24,
sizeof (RKFMT_CHLGKEY) << 24,
sizeof (RKFMT_BUS) << 24,
sizeof (RKFMT_BUS) << 24,
sizeof (RKFMT_TITLE) << 24,
0,
0,
0,
sizeof (RKFMT_RPC) << 24,
};
DWORD EndSwap(DWORD dwInput)
{
register DWORD dwResult;
dwResult = (dwInput << 24) | ((dwInput & 0xff00) << 8) | ((dwInput & 0xff0000) >> 8) | (dwInput >> 24);
return(dwResult);
}
/*
** setup_readkey()
**
** setup a read key command
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
DWORD DVDSetupReadTitleKey(ATAPI_COMMAND_PACKET *pCmdPkt, BYTE bKeyType, BYTE bAgid, DWORD dwLBA)
{
DWORD dwRet;
PRKCDB pcdb = (PRKCDB)(pCmdPkt);
pcdb->OpCode = DVDOP_REPORT_KEY;
pcdb->KeyFmt = (bAgid << 6) | bKeyType;
pcdb->Lun = 0;
if (bKeyType > (sizeof(rkret) / sizeof (DWORD)))
{
dwRet = 0;
}
else
{
dwRet = rkret[bKeyType];
}
//
// set up endian swapped allocation length, and clear reserved
//
*(PDWORD)(&pcdb->Reserved) = dwRet;
//
// set up the LBA field
//
pcdb->LBA = EndSwap(dwLBA);
pcdb->NACA = 0;
return(EndSwap(dwRet));
}
DWORD DVDSetupReadDiscKey( ATAPI_COMMAND_PACKET *pCmdPkt, BYTE bAgid)
{
PRDVDCDB pcdb = (PRDVDCDB)(pCmdPkt);
pcdb->OpCode = DVDOP_READ_DVD_STRUC;
pcdb->Lun = 0;
*((DWORD *)&pcdb->RMDLBA) = 0;
pcdb->Layer = 0;
pcdb->Format = DVDSTRUC_FMT_DISCKEY;
pcdb->Len = (USHORT)(sizeof (RKFMT_DISC) << 8 | sizeof (RKFMT_DISC) >>8);
pcdb->agid = bAgid;
pcdb->NACA = 0;
return(sizeof (RKFMT_DISC));
}
DWORD DVDSetupReadKey(ATAPI_COMMAND_PACKET *pCmdPkt, PDVD_COPY_PROTECT_KEY pKey)
{
switch (pKey->KeyType)
{
case DvdTitleKey:
return(DVDSetupReadTitleKey(pCmdPkt, (BYTE)(pKey->KeyType), (BYTE)pKey->SessionId, pKey->StartAddr +1));
case DvdDriveKey:
return(DVDSetupReadDiscKey(pCmdPkt, (BYTE)((pKey->SessionId) << 6)));
default:
return(DVDSetupReadTitleKey(pCmdPkt, (BYTE)(pKey->KeyType), (BYTE)pKey->SessionId, 0));
}
return 0;
}
DWORD CopyDVDKey(DWORD dwKeyLength,PDVD_COPY_PROTECT_KEY pKey ,PRKFMT_TITLE pTitle )
{
DWORD dwTmp;
PBYTE psrc, pdest;
dwTmp = dwKeyLength - 4;
//
// copy the key
//
pdest = (PBYTE)&(pKey->KeyData[0]);
switch (pKey->KeyType)
{
case DvdTitleKey:
pKey->KeyFlags = pTitle->cgms;
dwTmp--;
psrc = (PBYTE)&(pTitle->title[0]);
pdest = (PBYTE)&(pKey->KeyData[0]);
break;
case DvdAGID:
pKey->SessionId = ((PRKFMT_AGID)pTitle)->agid >> 6;
dwTmp = 0;
break;
default:
psrc = (PBYTE)&(pTitle->cgms);
pdest = (PBYTE)&(pKey->KeyData[0]);
break;
} // end switch on key type
for (;dwTmp >0; dwTmp--)
{
*pdest++ = *psrc++;
}
return(TRUE);
}
DWORD CDisk::DVDReadKey(PIOREQ pIOReq)
{
DWORD dwError = ERROR_SUCCESS;
SGX_BUF SgBuf;
ATAPI_COMMAND_PACKET CmdPkt;
PDVD_COPY_PROTECT_KEY pKey = (PDVD_COPY_PROTECT_KEY)pIOReq->pInBuf;
DWORD dwLength;
RKFMT_DISC keyBuf;
DWORD dwRet;
memset( &CmdPkt, 0, sizeof(ATAPI_COMMAND_PACKET));
if (pIOReq->dwCode == IOCTL_DVD_START_SESSION) {
pKey->KeyType = DvdAGID;
// TODO: Add Region check here !!!
dwLength = DVDSetupReadTitleKey( &CmdPkt, DvdAGID, 0, 0);
} else {
dwLength = DVDSetupReadKey(&CmdPkt, pKey);
}
if (dwLength > pKey->KeyLength) {
DEBUGMSG(ZONE_ERROR, (TEXT("cdReadKey illegal key request\r\n")));
return (ERROR_INVALID_PARAMETER);
}
SgBuf.sb_len = dwLength;
SgBuf.sb_buf = (PBYTE) &keyBuf;
if (AtapiSendCommand(&CmdPkt)) {
if (AtapiReceiveData(&SgBuf, 1, &dwRet)) {
CopyDVDKey(dwLength, pKey, (PRKFMT_TITLE)&keyBuf);
} else {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("Atapi:DVDReadKey failed on recieve\r\n")));
dwError = ERROR_READ_FAULT;
}
} else {
dwError = ERROR_GEN_FAILURE;
}
return dwError;
}
// Transfers the region and copy protect information to the client
DWORD CDisk::DVDGetRegion(PIOREQ pIOReq)
{
DWORD dwError = ERROR_SUCCESS;
DWORD dwLength;
SGX_BUF SgBuf;
DWORD dwRet;
RKFMT_RPC rpcData;
PDVD_REGIONCE preg;
ATAPI_COMMAND_PACKET CmdPkt;
memset( &CmdPkt, 0, sizeof(ATAPI_COMMAND_PACKET));
preg = (PDVD_REGIONCE)MapPtrToProcess((LPVOID)pIOReq->pOutBuf, GetCallerProcess());
DVDGetCopySystem(&(preg->CopySystem));
if (m_dwDeviceFlags & DFLAGS_MEDIA_ISDVD) {
memset( &CmdPkt, 0, sizeof(ATAPI_COMMAND_PACKET));
dwLength = DVDSetupReadTitleKey(&CmdPkt, DvdGetRPC, 0, 0);
SgBuf.sb_len = sizeof(RKFMT_RPC);
SgBuf.sb_buf = (PBYTE) &rpcData;
if (AtapiSendCommand(&CmdPkt)) {
if (AtapiReceiveData(&SgBuf, 1, &dwRet)) {
if (rpcData.ResetCounts & 0xc0) {
preg->SystemRegion = rpcData.SystemRegion ^ 0xff;
preg->ResetCount = rpcData.ResetCounts & 0x07;
} else {
// TODO: This is a virgin drive. Should we set the region ???
// TODO: For now send back the default region
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("Atapi:Brand new drive !!!\r\n")));
preg->SystemRegion = (BYTE)DEFAULT_DECODER_REGION;
preg->ResetCount = 0;
}
} else {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("Atapi:DVDGetRegion failed on recieve\r\n")));
dwError = ERROR_READ_FAULT;
}
} else {
// Probably a RPC I Drive
preg->SystemRegion = (BYTE)DEFAULT_DECODER_REGION;
preg->ResetCount = 0;
}
}
return dwError;
}
DWORD DVDSetupSendKey(ATAPI_COMMAND_PACKET *pCmd, PDVD_COPY_PROTECT_KEY pKey, RKFMT_CHLGKEY * keyBuf)
{
BYTE KeyType;
BYTE agid;
DWORD dwRet;
DWORD dwTmp;
PRKCDB pcdb = (PRKCDB)pCmd;
PVOID pdata = &(pKey->KeyData[0]);
KeyType = (BYTE)pKey->KeyType;
agid = (BYTE)pKey->SessionId;
pcdb->OpCode = DVDOP_SEND_KEY;
pcdb->Lun = 0;
pcdb->KeyFmt = (agid << 6) | KeyType;
if (!KeyType || KeyType > DvdBusKey2 || (pKey->KeyLength <
((dwRet = rkret[KeyType]) >> 24)))
{
return(0);
}
keyBuf->Len = (WORD)((dwRet >> 16) - (2 << 8));
keyBuf->Reserved[0] = keyBuf->Reserved[1] = 0;
if (KeyType == DvdBusKey2)
{
for (dwTmp = 0;dwTmp < 5;dwTmp++ )
{
*((PBYTE)(&keyBuf->chlgkey) + dwTmp) = *((PBYTE)pdata + dwTmp);
}
for (;dwTmp < 8; dwTmp++)
{
*((PBYTE)(&keyBuf->chlgkey) + dwTmp) = 0;
}
}
else
{
for (dwTmp = 0;dwTmp < ((dwRet >> 26) - 1);dwTmp++ )
{
*((PDWORD)(&keyBuf->chlgkey) + dwTmp) = *((PDWORD)pdata + dwTmp);
}
}
//
// set up endian swapped allocation length, and clear reserved
//
*(PDWORD)(&pcdb->Reserved) = dwRet;
pcdb->LBA = 0;
pcdb->NACA = 0;
return(EndSwap(dwRet));
}
DWORD CDisk::DVDSendKey(PIOREQ pIOReq)
{
DWORD dwError = ERROR_SUCCESS;
ATAPI_COMMAND_PACKET CmdPkt;
PDVD_COPY_PROTECT_KEY pKey = (PDVD_COPY_PROTECT_KEY)pIOReq->pInBuf;
DWORD dwLength;
RKFMT_CHLGKEY keyBuf;
SGX_BUF SgBuf;
DWORD dwRet;
memset( &CmdPkt, 0, sizeof(ATAPI_COMMAND_PACKET));
if (pIOReq->dwCode == IOCTL_DVD_END_SESSION) {
BYTE bAgid;
pKey->KeyType = DvdAGID;
bAgid= (BYTE)pKey->SessionId;
if (bAgid == -1)
bAgid = 0;
dwLength = DVDSetupReadTitleKey(&CmdPkt, -1, bAgid, 0);
} else {
dwLength = DVDSetupSendKey(&CmdPkt, pKey, &keyBuf);
}
SgBuf.sb_len = dwLength;
SgBuf.sb_buf = (PBYTE) &keyBuf;
if (AtapiSendCommand(&CmdPkt)) {
if (!AtapiSendData(&SgBuf, 1, &dwRet)) {
DEBUGMSG( ZONE_ERROR|ZONE_CDROM, (TEXT("Atapi::DVDSendKey Failed\r\n")));
dwError = ERROR_WRITE_FAULT;
}
} else {
dwError = ERROR_GEN_FAILURE;
}
return dwError;
}
DWORD CDisk::DVDSetRegion(PIOREQ pIOReq)
{
// TODO: Implement Me
return ERROR_NOT_SUPPORTED;
}
BOOL CDisk::DVDGetCopySystem(LPBYTE pbCopySystem)
{
BOOL fSuccess = TRUE;
ATAPI_COMMAND_PACKET CmdPkt;
PRDVDCDB pCmd = (PRDVDCDB)&CmdPkt;
RDVDFMT_Copy fmtCopy;
SGX_BUF SgBuf;
DWORD dwRet;
memset( &CmdPkt, 0, sizeof(ATAPI_COMMAND_PACKET));
pCmd->OpCode= DVDOP_READ_DVD_STRUC;
pCmd->Format= DVDSTRUC_FMT_COPY;
pCmd->Len = sizeof (RDVDFMT_Copy) << 8; //Endian Swap the length
// pCmd->Len = keyLength << 8;
SgBuf.sb_len = sizeof(RDVDFMT_Copy);
SgBuf.sb_buf = (PBYTE) &fmtCopy;
m_dwDeviceFlags &= ~DFLAGS_MEDIA_ISDVD;
if (AtapiSendCommand(&CmdPkt)) {
if (AtapiReceiveData(&SgBuf, 1, &dwRet)) {
*pbCopySystem = (BYTE)(fmtCopy.Data);
}
} else {
fSuccess = FALSE;
}
return fSuccess;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -