Exemple #1
0
int
zellvd_rem_init(struct sis1100_softc* sc, int reset)
{
/* sc->sem_hw must be held by caller!*/
#define MIN_FV_1 1
#define MAX_FV_1 17
#define MIN_FV_2 17
#define MAX_FV_2 17
#define MIN_FV_3 1
#define MAX_FV_3 1
    int min_fv=0, max_fv=0;
    u_int32_t hv, fk, fv;

    hv=(sc->remote_ident>>8)&0xff;
    fk=(sc->remote_ident>>16)&0xff;
    fv=(sc->remote_ident>>24)&0xff;

    switch (sc->remote_ident&0x00ffff00) {
    case 0x00010100: /* LVD controller with F1 */
        min_fv=MIN_FV_1;
        max_fv=MAX_FV_1;
        break;
    case 0x00010200: /* LVD controller with GPX */
        min_fv=MIN_FV_2;
        max_fv=MAX_FV_2;
        break;
    case 0x00010300: /* LVD controller with both F1 and GPX */
        min_fv=MIN_FV_3;
        max_fv=MAX_FV_3;
        break;
    default:
        pERROR(sc, "zellvd: remote hw/fw type not supported");
        return -1;
    }
    if (fv<min_fv) {
        pERROR(sc, "zellvd: remote firmware version too old;"
                " at least version %d is required.",
                min_fv);
        return -1;
    }
    if (fv>max_fv) {
        pINFO(sc, "zellvd: Driver not tested with"
                " remote firmware versions higher than %d.",
                max_fv);
    }

    if (reset>0)
        lvd_writeremreg(sc, cr, 0, 1); /* reset cr */

    return 0;
}
		/* static */
		INT_PTR HookedLoggedOutSAS::MicrosoftDialogProcWrapper(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
		{
			if(s_hookedDlgProc == 0)
			{
				pERROR(L"HookedLoggedOutSAS::MicrosoftDialogProcWrapper: Dialog wrapper called before we know who we're hooking!");
				return 0;	// Nothin we can do!
			}

			// Fall through if hooking is not enabled
			if(!s_hookingEnabled)
				return s_hookedDlgProc(hwnd, msg, wparam, lparam);

			// Hooking is on, so we let msgina do its thing
			INT_PTR msginaResult = s_hookedDlgProc(hwnd, msg, wparam, lparam);

			// If we're init'ing, then we set username, password and queue a message to login
			if(msg == WM_INITDIALOG)
			{
				std::wstring domainUsername = s_loginResult.Domain();
				domainUsername += L"\\";
				domainUsername += s_loginResult.Username();

				pDEBUG(L"HookedLoggedOutSAS::MicrosoftDialogProcWrapper: Hooked dialog, setting username/password and submitting for user: %s", domainUsername.c_str());
				SetDlgItemText(hwnd, IDC_MSGINA_USERNAME, domainUsername.c_str());
				SetDlgItemText(hwnd, IDC_MSGINA_PASSWORD, s_loginResult.Password().c_str());			
				SendMessage(hwnd, WM_COMMAND, 1, 1);
			}

			return msginaResult;
		}
Exemple #3
0
		GinaChain::GinaChain(WinlogonInterface *pWinLogonIface) : 
			Gina(pWinLogonIface), WinlogonProxy(pWinLogonIface), m_passthru(false)
		{
			// Are we in passthru mode?
			m_passthru = pGina::Registry::GetBool(L"GinaPassthru", false);

			// When we use the winlogon router table, we want it to 
			//	direct all winlogon calls to us (via our WinlogonProxy 
			//	implementation).  We sit between winlogon and a real
			//	GINA, so our Gina interface let's us have first shot
			//	at Winlogon->Gina direction calls, and WinlogonRouter+
			//	WinlogonProxy let's us have first shot at Gina->Winlogon
			//	direction traffic.
			WinlogonRouter::Interface(this);

			// Init and load our chained/wrapped gina
			std::wstring ginaName = pGina::Registry::GetString(L"ChainedGinaPath", L"MSGINA.DLL");
			pDEBUG(L"Wrapping gina: %s", ginaName.c_str());

			m_wrappedGina = new GinaWrapper(ginaName.c_str());
			if(!m_wrappedGina->Load())
			{
				pERROR(L"Failed to load wrapped gina: 0x%08x", GetLastError());
				return;
			}

			// Now negotiate and initialize our wrapped gina			
			if(!m_wrappedGina->Negotiate(WinlogonInterface::Version()))
			{	
				pERROR(L"Failed to negotiate with wrapped gina using version: %d (0x%08x)", WinlogonInterface::Version(), WinlogonInterface::Version());
				return;
			}

			if(!m_wrappedGina->Initialize(L"Winsta0", WinlogonRouter::Interface(), NULL, WinlogonRouter::DispatchTable()))
			{
				pERROR(L"Failed to initialize wrapped gina");
				return;
			}
		}
Exemple #4
0
static int
_sis1100_write(struct sis1100_softc* sc, struct sis1100_fdata* fd,
    size_t count, size_t* count_written, u_int32_t addr,
    const char __user *data)
{
    int32_t am;
    int datasize;
    int space, fifo;
    int res;

#if 0
    pERROR(sc, "sis1100_write data=%p addr=%08x count=%llu size=%d",
        data, addr, (unsigned long long)count, fd->vmespace_datasize);
#endif
    switch (fd->subdev) {
    case sis1100_subdev_ram:
        am=-1;
        datasize=4;
        space=6;
        fifo=0;
        break;
    case sis1100_subdev_remote:
        am=fd->vmespace_am;
        datasize=fd->vmespace_datasize;
        space=1;
        fifo=fd->fifo_mode;
        break;
    case sis1100_subdev_dsp:
        am=-1;
        datasize=4;
        space=6;
        fifo=0;
        break;
    case sis1100_subdev_ctrl:
        return sis1100_write_irq(sc, fd, count, count_written, data);
    default:
        return ENOTTY;
    }

    if (count%datasize)
        return EINVAL;

    res=sis1100_write_block(sc, fd,
        datasize, fifo, count/datasize, count_written, space, am,
        addr, data, &fd->last_prot_err);
    *count_written*=datasize;

    return res;
}
Exemple #5
0
		IFACEMETHODIMP Provider::GetFieldDescriptorCount(__out DWORD* pdwCount)
		{
			// # of fields depends on our usage scenario:
			switch(m_usageScenario)
			{
			case CPUS_LOGON:			
			case CPUS_CREDUI:
				*pdwCount = LUIFI_NUM_FIELDS;
				return S_OK;		
			case CPUS_UNLOCK_WORKSTATION:
				*pdwCount = LOIFI_NUM_FIELDS;
				return S_OK;
			default:
				pERROR(L"Provider::GetFieldDescriptorCount: No UI known for the usage scenario: 0x%08x", m_usageScenario);
				return S_FALSE;
			}

			// Should never reach this
			assert(0);
			return S_FALSE;
		}
Exemple #6
0
static void
_sis1100_irq_thread(struct sis1100_softc* sc, enum handlercomm command)
{
    u_int32_t new_irqs=0;
    int i;

    mutex_lock(&sc->sem_irqinfo);

    if (command&handlercomm_doorbell) {
        DECLARE_SPINLOCKFLAGS(flags)
        u_int32_t doorbell;

        SPIN_LOCK_IRQSAVE(sc->lock_doorbell, flags);
        doorbell=sc->doorbell;
        sc->doorbell=0;
        SPIN_UNLOCK_IRQRESTORE(sc->lock_doorbell, flags);

        switch (sc->remote_hw) {
        case sis1100_hw_vme:
            new_irqs|=sis3100rem_irq_handler(sc, doorbell);
            break;
        case sis1100_hw_camac:
            new_irqs|=sis5100rem_irq_handler(sc, doorbell);
            break;
        case sis1100_hw_pci:
            /* do nothing */
            break;
        case sis1100_hw_lvd:
            new_irqs|=zellvd_rem_irq_handler(sc, doorbell);
            break;
        case sis1100_hw_pandapixel:
            new_irqs|=pandapixel_rem_irq_handler(sc, doorbell);
            break;
        case sis1100_hw_psf4ad:
            /* do nothing */
        case sis1100_hw_invalid:
            /* do nothing */
            break;
        }
    }

    if (command&handlercomm_lemo) {
        new_irqs|=sis1100_lemo_handler(sc);
    }

    if (command&handlercomm_mbx0) {
        new_irqs|=sis1100_mbox0_handler(sc);
    }

    /* this is called from sis1100_link_up_handler for both
       'UP' and 'DOWN' of link one second after status change */
    if (command&handlercomm_up) {
        new_irqs|=sis1100_synch_handler(sc);
    }

    if (command&handlercomm_ddma) {
        new_irqs|=sis1100_ddma_handler(sc);
    }

    sc->pending_irqs|=new_irqs;

    mutex_unlock(&sc->sem_irqinfo);

    /* inform processes via signal if requested */
    mutex_lock(&sc->sem_fdata);
    for (i=0; i<sis1100_MINORUTMASK+1; i++) {
        if (sc->fdata[i]) {
            struct sis1100_fdata* fd=sc->fdata[i];
            if (fd->sig>0 && ((new_irqs & fd->owned_irqs)||
                              (fd->old_remote_hw!=sc->remote_hw))) {
                int res;
                /* XXXY muss raus */
                pERROR(sc, "irq_pending=%d pending_irqs=0x%x",
                        irq_pending(sc, fd, fd->owned_irqs),
                        sc->pending_irqs);
                pERROR(sc, "sig=%d new_irqs=0x%x owned_irqs=0x%x",
                        fd->sig, new_irqs, fd->owned_irqs);
                pERROR(sc, "old_remote_hw=%d remote_hw=%d",
                        fd->old_remote_hw, sc->remote_hw);
                /* XXXY muss raus */
                pERROR(sc, "send sig to %d", pid_nr(fd->pid));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
                res=kill_proc(fd->pid, fd->sig, 1);
#else
                res=kill_pid(fd->pid, fd->sig, 1);
#endif
                if (res)
                    pINFO(sc, "send sig %d to %u: res=%d",
                            fd->sig, pid_nr(fd->pid), res);
            }
        }
    }
    mutex_unlock(&sc->sem_fdata);

    /* wake up processes waiting in sis1100_irq_wait or doing select */
#ifdef __NetBSD__
    wakeup(&sc->remoteirq_wait);
    selwakeup(&sc->sel);
#elif __linux__
    wake_up_interruptible(&sc->remoteirq_wait);
#endif
}
Exemple #7
0
int
#else
void
#endif
sis1100_irq_thread(void* data)
{
    struct sis1100_softc* sc=(struct sis1100_softc*)data;
    enum handlercomm command;
    DECLARE_SPINLOCKFLAGS(flags);

#ifdef __linux__
#if LINUX_VERSION_CODE < 0x20600
    daemonize();
    snprintf(current->comm, sizeof(current->comm), "sis1100_%02d", sc->unit);
    SPIN_LOCK_IRQSAVE(current->sigmask_lock, flags);
    sigemptyset(&current->blocked);
    recalc_sigpending(current);
    SPIN_UNLOCK_IRQRESTORE(current->sigmask_lock, flags);
#endif
#endif /*__linux__*/

    while (1) {
#ifdef __NetBSD__
        tsleep(&sc->handler_wait, PCATCH, "thread_vmeirq", 0);
#elif __linux__
        /* prepare to sleep */
	__set_current_state(TASK_INTERRUPTIBLE);
        /* don't sleep if command!=0 */
        if (sc->handlercommand.command)
	    __set_current_state(TASK_RUNNING);
        else
            schedule();
#endif

        if (kthread_should_stop())
            return 0;

        SPIN_LOCK_IRQSAVE(sc->handlercommand.lock, flags);
        command=sc->handlercommand.command;
        sc->handlercommand.command=0;
        SPIN_UNLOCK_IRQRESTORE(sc->handlercommand.lock, flags);

#if 0
        pERROR(sc, "irq_thread: command=0x%x", command);
#endif

        _sis1100_irq_thread(sc, command);

#ifdef __linux__
	if (signal_pending (current)) {
	    SPIN_LOCK_IRQSAVE(current->SIGMASK_LOCK, flags);
	    flush_signals(current);
	    SPIN_UNLOCK_IRQRESTORE(current->SIGMASK_LOCK, flags);
	}
#endif /*__linux__*/

    }
#ifdef __linux__
    return 0;
#endif
}
Exemple #8
0
int
sis1100_read_loop(
    struct sis1100_softc* sc,
    struct sis1100_fdata* fd,
    u_int32_t addr,           /* VME or SDRAM address */
    int32_t am,               /* address modifier, not used if <0 */
    int size,                 /* datasize (bytes/word) */
    int space,                /* remote space (1,2: VME; 6: SDRAM) */
    int fifo_mode,
    size_t count,             /* words (of size 'size') to be transferred */
                              /* count==0 is illegal */
    size_t* count_read,       /* words transferred */
    u_int8_t* data,           /* destination (user virtual address) */
    int* prot_error
    )
{
    u_int32_t head;
    int idx, res=0;

#if 0
    pERROR(sc, "read_loop size=%d count=%llu addr=%08x",
        size, (unsigned long long)count, addr);
#endif

    *count_read=count;
    head=0x00000002|(space&0x3f)<<16;
    mutex_lock(&sc->sem_hw);
    if (am>=0) {
        head|=0x800;
        sis1100writereg(sc, t_am, am);
    }
    switch (size) {
    case 1:
        for (idx=0; idx<count; idx++, data++) {
            u_int32_t val;
            sis1100writereg(sc, t_hdr, head|(0x01000000<<(addr&3)));
            sis1100writereg(sc, t_adl, addr);
            do {
                *prot_error=sis1100readreg(sc, prot_error);
            } while (*prot_error==0x005);
            if (*prot_error) {
                *count_read=idx;
                break;
            }
            val=sis1100rawreadreg(sc, tc_dal);

#if defined(__LITTLE_ENDIAN)
            __put_user((val>>((addr&3)<<3))&0xff, (u_int8_t*)(data));
#else
            __put_user((val>>((3-(addr&3))<<3))&0xff, (u_int8_t*)(data));
#endif
            if (!fifo_mode)
                addr++;
        }
        break;
    case 2:
        for (idx=0; idx<count; idx++, data+=2) {
            u_int32_t val;
            sis1100writereg(sc, t_hdr, head|(0x03000000<<(addr&3)));
            sis1100writereg(sc, t_adl, addr);
            do {
                *prot_error=sis1100readreg(sc, prot_error);
            } while (*prot_error==0x005);
            if (*prot_error) {
                *count_read=idx;
                break;
            }
            val=sis1100rawreadreg(sc, tc_dal);

#if defined(__LITTLE_ENDIAN)
            __put_user((val>>((addr&2)<<3))&0xffff, (u_int16_t*)data);
#else
            __put_user((val>>((2-(addr&2))<<3))&0xffff, (u_int16_t*)data);
#endif
            if (!fifo_mode)
                addr+=2;
        }
        break;
    case 4:
        sis1100writereg(sc, t_hdr, head|0x0f000000);
        for (idx=0; idx<count; idx++, data+=4) {
            u_int32_t val;
            sis1100writereg(sc, t_adl, addr);
            do {
                *prot_error=sis1100readreg(sc, prot_error);
            } while (*prot_error==0x005);
            if (*prot_error) {
                *count_read=idx;
                break;
            }
            val=sis1100rawreadreg(sc, tc_dal);
            __put_user(val, (u_int32_t*)data);
            if (!fifo_mode)
                    addr+=4;
        }
        break;
    }
    mutex_unlock(&sc->sem_hw);
    return res;
}
Exemple #9
0
/* Initialize the fake registry.
 */
void InitializeFakeRegistry(void)
{
	/* There must be a better way of doing this:
	 */
	char row[10*1024], key[10*1024], value[10*1024];
	FILE *f_ptr;
	int i;

	/* Initialize fake registry linked list.
	 */
	reg_head_ptr = reg_tail_ptr = NULL;

	/* Load a previously saved fake registry (if this fails we assume one
	 * does not yet exist and leave creating one up to the save function).
	 */
	if ( GetUserConfigPath(reg_file, FR_FILENAME_LEN) == NULL)
		return;

	/* Append filename of registry to path.
	 */
	strcat(reg_file, REG_FILENAME);

	/* Test file, quit if does not exist (first time beebem ran so
	 * no entries).
	 */
	if ( (f_ptr=fopen(reg_file, "r")) == NULL)
		return;

	/* Load existing registry
	 */
	while (fgets( row, 256, f_ptr ) != NULL){
		i = strlen(row) -1;
		while(i>=0){
 			if (row[i]<32) row[i] = '\0';
				i--;
		}

		if (strlen(row)<=0)
			continue;

		if (row[0] == '#')
			continue;

		for(i=0; i< (int) strlen(row); i++)
			if (row[i] == '#'){
				row[i]='\0';
				break;
			}

		i = strlen(row) -1;
		while(i>=0){
			if (row[i] == '=') break;
			i--;
		}
		if (i<=0)
			continue;

		memcpy(key, row, i);
		key[i]='\0';

		value[0] = '\0';
		if(strlen(row)-i-1>0){
			memcpy(value, row+i+1, strlen(row)-i-1);
			value[strlen(row)-i-1] = '\0';
		}

		i = strlen(value) -1;
		while(value[i]<=32 && i>=0){
			value[i] = '\0';
			i--;
		}

		if (SetFakeRegistryItem(key, value) != TRUE)
                	pERROR(dL"Failed to add '%s' to the registry!\n", dR
			 , key);
	}
	fclose(f_ptr);
}
Exemple #10
0
		// SAS handling
		int  GinaChain::LoggedOutSAS(DWORD dwSasType, PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions, 
									 PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo, PVOID *pProfile)
		{
			// If configured to pass through to MS GINA, or auto-logon is enabled, we 
			// pass through, and let the MS GINA handle the logon.
			if(m_passthru || IsAutoLogonEnabled())
			{
				return m_wrappedGina->LoggedOutSAS(dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile);				
			}

			// We auth'd in another session - this session is the real one though, need to tell the service to add!
			if(dwSasType == WLX_SAS_TYPE_AUTHENTICATED)
			{
				// We could do this, but we don't get password (without additional wrapping of our own in WlxGetConsoleSwitchCredentials
				//  So instead we grab it post SAS processing via msgina.				
				WLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 credInfo;
				if(m_winlogon->WlxQueryConsoleSwitchCredentials(&credInfo))
				{
					pDEBUG(L"LoggedOutSAS: CredInfo=%p PrivateDataLen: 0x%08x PrivateData: %p", &credInfo, credInfo.PrivateDataLen, credInfo.PrivateData);
				}				
				
				int msresult = m_wrappedGina->LoggedOutSAS(dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile);
				//pGina::Transactions::LoginInfo::Add(pMprNotifyInfo->pszUserName, pMprNotifyInfo->pszDomain, pMprNotifyInfo->pszPassword);
				return msresult;
			}

			// Gather username/password from user.  If remote, we get it from rdp client if provided,
			//  otherwise show the logged out sas dialog to get it.
			std::wstring username;
			std::wstring password;
			std::wstring domain;
						
			bool showDialog = true;

			if(pGina::Helpers::UserIsRemote())
			{
				WLX_CLIENT_CREDENTIALS_INFO_V2_0 creds;
				creds.dwType = WLX_CREDENTIAL_TYPE_V2_0;				
				if(m_winlogon->WlxQueryTsLogonCredentials(&creds))
				{
					if(creds.pszUserName) username = creds.pszUserName;
					if(creds.pszPassword) password = creds.pszPassword;
					if(creds.pszDomain) domain = creds.pszDomain;
					if(!creds.fPromptForPassword) showDialog = false;

					pDEBUG(L"fPromptForPassword: %s", creds.fPromptForPassword ? L"TRUE" : L"FALSE");
					pDEBUG(L"fDisconnectOnLogonFailure: %s", creds.fDisconnectOnLogonFailure ? L"TRUE" : L"FALSE");
				}				
			}
			
			if(showDialog)
			{
				DialogLoggedOutSAS dialog(m_winlogon);						
				dialog.Username(username);
				dialog.Password(password);

				int dialogResult = dialog.ShowDialog();
				if(dialogResult == DialogLoggedOutSAS::SAS_ACTION_LOGON)
				{
					// Harvest u/p for passing along to msgina
					username = dialog.Username();
					password = dialog.Password();
				}
				else if(dialogResult >= DialogLoggedOutSAS::SAS_ACTION_MIN && dialogResult <= DialogLoggedOutSAS::SAS_ACTION_MAX)
				{
					// Just do as told
					return dialogResult;
				}
				else
				{
					// Unknown ret value, default to no action
					return DialogLoggedOutSAS::SAS_ACTION_NONE;
				}
			}

			// We now have the login info, let's give it a shot!
			pDEBUG(L"GinaChain::LoggedOutSAS: Processing login for %s", username.c_str());
			pGina::Transactions::User::LoginResult result = pGina::Transactions::User::ProcessLoginForUser(username.c_str(), NULL, password.c_str(), pGina::Protocol::LoginRequestMessage::Login);
			if(!result.Result())
			{
				std::wstring failureMsg = result.Message();
				pERROR(L"GinaChain::LoggedOutSAS: %s", failureMsg.c_str());
				m_winlogon->WlxMessageBox(NULL, const_cast<wchar_t *>(failureMsg.c_str()), L"Login Failure", MB_ICONEXCLAMATION | MB_OK);
				return WLX_SAS_ACTION_NONE;					
			}			

			pDEBUG(L"inaChain::LoggedOutSAS: Successful, resulting username: %s", result.Username().c_str());						

			// Invoke the msgina logged out sas dialog, intercept it, set username/password, and hit ok!
			HookedLoggedOutSAS::Enabled(true);
			HookedLoggedOutSAS::SetLoginInfo(result);
			int msresult = m_wrappedGina->LoggedOutSAS(dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile);
			HookedLoggedOutSAS::Enabled(false);				
			return msresult;			
		}
Exemple #11
0
int
sis1100_ddma_map(struct sis1100_softc *sc, struct sis1100_fdata* fd,
    struct sis1100_ddma_map* map)
{
    struct demand_dma* dma;
    int i;

    /* we are called from 'release' with map==0 */
    if ((map!=0) && (map->num!=0) && (map->size!=0)) {
        /*if (map->num<2)
            return EINVAL;*/

        if (map->size&(NBPG-1)) {
            pINFO(sc, "ddma_map: size not multiple of page size");
            return EINVAL;
        }

        if ((unsigned long)map->addr&(NBPG-1)) {
            pINFO(sc, "ddma_map: addr not at page boundary");
            return EINVAL;
        }
    }

    dma=&sc->demand_dma;
    mutex_lock(&dma->mux);

    /* is an other process using DMA? */
    if ((dma->status!=dma_invalid) && (dma->owner!=fd)){
        mutex_unlock(&dma->mux);
        return EPERM;
    }
    /* is DMA still active? */
    if (dma->status==dma_running) {
        mutex_unlock(&dma->mux);
        return EALREADY;
    }

    /* if DMA is initialized we will free all structures first */
    if (dma->status==dma_ready) {
        for (i=0; i<dma->numblocks; i++)
            sis1100_ddma_unmap_block(sc, dma->block+i);
        KFREE(dma->block);
        dma->block=0;
        dma->status=dma_invalid;
    }

    /* if the user did not request a new mapping we are done here */
    if ((map==0) || (map->num==0) || (map->size==0)) {
        mutex_unlock(&dma->mux);
        return 0;
    }

    pINFO(sc, "dma_map: size=%lld addr=%p num=%d",
        (unsigned long long)map->size, map->addr, map->num);

    dma->block=KMALLOC(map->num*sizeof(struct demand_dma_block));
    if (dma->block==0) {
        mutex_unlock(&dma->mux);
        return ENOMEM;
    }

    dma->owner=fd;
    dma->size=map->size;
    dma->numblocks=map->num;
    dma->uaddr=map->addr;
    for (i=0; i<dma->numblocks; i++)
        sis1100_ddma_zero(dma->block+i);

    for (i=0; i<dma->numblocks; i++) {
        struct demand_dma_block* block=dma->block+i;
        int res;

        block->uaddr=dma->uaddr+i*dma->size;
        block->size=dma->size;
#ifdef __NetBSD__
        block->p=fd->p;
#endif
        /*pINFO(sc, "dma_map: try block %d", i);*/
        res=sis1100_ddma_map_block(sc, block);
        if (res) {
            int j;
            pINFO(sc, "dma_map: block %d: res=%d", i, res);
            for (j=0; j<dma->numblocks; j++)
                sis1100_ddma_unmap_block(sc, dma->block+j);
            KFREE(dma->block);
            dma->block=0;
            mutex_unlock(&dma->mux);
            return res;
        }
    }
    for (i=0; i<dma->numblocks; i++) {
        pERROR(sc, "dmadpr0[%d]=%08x", i, dma->block[i].dmadpr0);
    }

    dma->status=dma_ready;
    mutex_unlock(&dma->mux);
    return 0;
}