⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deviceio.c

📁 日本著名的的嵌入式实时操作系统T-Kernel的源码及用户手册。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *---------------------------------------------------------------------- *    T-Kernel * *    Copyright (C) 2004 by Ken Sakamura. All rights reserved. *    T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * *    Version:   1.01.00 *    Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. * *---------------------------------------------------------------------- *//* *	deviceio.c (T-Kernel/SM) *	Device Management Function: Input/Output */#include "sysmgr.h"#include <sys/ssid.h>LOCAL	OpnCB	*OpnCBtbl;	/* Open management information table */LOCAL	QUEUE	FreeOpnCB;	/* Unused queue */LOCAL	INT	MaxOpnDev;	/* Maximum number of devices open */#define	DD(opncb)		( (opncb) - OpnCBtbl + 1 )#define	OPNCB(dd)		( OpnCBtbl + ((dd) - 1) )LOCAL	ReqCB	*ReqCBtbl;	/* Request management information table */LOCAL	QUEUE	FreeReqCB;	/* Unused queue */LOCAL	INT	MaxReqDev;	/* Maximum number of device requests */#define	REQID(reqcb)		( (reqcb) - ReqCBtbl + 1 )#define	REQCB(reqid)		( ReqCBtbl + ((reqid) - 1) )#define	DEVREQ_REQCB(devreq)	((ReqCB*)((B*)(devreq) - offsetof(ReqCB, req)))/* * Get resource management information */LOCAL ResCB* GetResCB( ID ssid, ID tskid ){	ResCB	*rescb;	rescb = GetResBlk(ssid, tskid);	if ( rescb == NULL ) return NULL;	LockDM();	/* If the startup function is not called, initialize at this point */	if ( rescb->openq.next == NULL ) {		/* Initialization of open device management queue */		QueInit(&rescb->openq);	}	UnlockDM();	return rescb;}/* * Verify validity of device descriptor */EXPORT ER check_devdesc( ID dd, UINT mode, OpnCB **p_opncb ){	OpnCB	*opncb;	if ( dd < 1 || dd > MaxOpnDev ) return E_ID;	opncb = OPNCB(dd);	if ( opncb->resid == 0 ) return E_ID;	if ( opncb->resid != tk_get_rid(TSK_SELF) ) return E_OACV;	if ( mode != 0 ) {		if ( (opncb->omode & mode) == 0 ) return E_OACV;	}	*p_opncb = opncb;	return E_OK;}/* * Verify validity of request ID */LOCAL ReqCB* check_reqid( ID reqid, OpnCB *opncb ){	ReqCB	*reqcb;	if ( reqid < 1 || reqid > MaxReqDev ) return NULL;	reqcb = REQCB(reqid);	if ( reqcb->opncb != opncb ) return NULL;	return reqcb;}/* * Get open management block */LOCAL OpnCB* newOpnCB( DevCB *devcb, INT unitno, UINT omode, ResCB *rescb ){	OpnCB	*opncb;	/* Get space in open management block */	opncb = (OpnCB*)QueRemoveNext(&FreeOpnCB);	if ( opncb == NULL ) return NULL; /* No space */	/* Register as open device */	QueInsert(&opncb->q, &devcb->openq);	QueInsert(&opncb->resq, &rescb->openq);	opncb->devcb  = devcb;	opncb->unitno = unitno;	opncb->omode  = omode;	QueInit(&opncb->requestq);	opncb->waitone = 0;	opncb->nwaireq = 0;	opncb->abort_tskid = 0;	opncb->resid  = 0; /* Indicate that open processing is not completed */	return opncb;}/* * Free open management block */LOCAL void delOpnCB( OpnCB *opncb, BOOL free ){	QueRemove(&opncb->q);	QueRemove(&opncb->resq);	if ( free ) {		QueInsert(&opncb->q, &FreeOpnCB);	}	opncb->resid = 0;}/* * Get request management block */LOCAL ReqCB* newReqCB( OpnCB *opncb ){	ReqCB	*reqcb;	/* Get space in request management block */	reqcb = (ReqCB*)QueRemoveNext(&FreeReqCB);	if ( reqcb == NULL ) return NULL; /* No space */	/* Register as requested open device */	QueInsert(&reqcb->q, &opncb->requestq);	reqcb->opncb = opncb;	return reqcb;}/* * Free request management block */LOCAL void delReqCB( ReqCB *reqcb ){	QueRemove(&reqcb->q);	QueInsert(&reqcb->q, &FreeReqCB);	reqcb->opncb = NULL;}/* ------------------------------------------------------------------------ *//* * Check open mode */LOCAL ER chkopenmode( DevCB *devcb, INT unitno, UINT omode ){	QUEUE	*q;	OpnCB	*opncb;	INT	read, write, rexcl, wexcl;	if ( (omode & TD_UPDATE) == 0 ) return E_PAR;	/* Check current open state */	read = write = rexcl = wexcl = 0;	for ( q = devcb->openq.next; q != &devcb->openq; q = q->next ) {		opncb = (OpnCB*)q;		if ( unitno == 0 || opncb->unitno == 0		  || opncb->unitno == unitno ) {			if ( (opncb->omode & TD_READ)  != 0 ) read++;			if ( (opncb->omode & TD_WRITE) != 0 ) write++;			if ( (opncb->omode & (TD_EXCL|TD_REXCL)) != 0) rexcl++;			if ( (opncb->omode & (TD_EXCL|TD_WEXCL)) != 0) wexcl++;		}	}	/* Is it able to open? */	if ( (omode & (TD_EXCL|TD_REXCL)) != 0 && read  > 0 ) return E_BUSY;	if ( (omode & (TD_EXCL|TD_WEXCL)) != 0 && write > 0 ) return E_BUSY;	if ( (omode & TD_READ)  != 0 && rexcl > 0 ) return E_BUSY;	if ( (omode & TD_WRITE) != 0 && wexcl > 0 ) return E_BUSY;	return E_OK;}/* * TRUE if specified device is open. */LOCAL BOOL chkopen( DevCB *devcb, INT unitno ){	QUEUE	*q;	for ( q = devcb->openq.next; q != &devcb->openq; q = q->next ) {		if ( ((OpnCB*)q)->unitno == unitno ) return TRUE;	}	return FALSE;}/* * Device open */EXPORT ID _tk_opn_dev( UB *devnm, UINT omode ){	ER	(*openfn)( ID devid, UINT omode, VP exinf );	VP	exinf;#if TA_GP	VP	gp;#endif	UB	pdevnm[L_DEVNM + 1];	INT	unitno;	ResCB	*rescb;	DevCB	*devcb;	OpnCB	*opncb;	ER	err;	err = ChkSpaceBstrR(devnm, 0);	if ( err < E_OK ) goto err_ret1;	unitno = phydevnm(pdevnm, devnm);	/* Get resource management information */	rescb = GetResCB(DEVICE_SVC, TSK_SELF);	if ( rescb == NULL ) { err = E_CTX; goto err_ret1; }	LockDM();	/* Search device to open */	devcb = searchDevCB(pdevnm);	if ( devcb == NULL || unitno > devcb->ddev.nsub )				{ err = E_NOEXS; goto err_ret2; }	/* Check open mode */	err = chkopenmode(devcb, unitno, omode);	if ( err < E_OK ) goto err_ret2;	openfn = (VP)devcb->ddev.openfn;	exinf = devcb->ddev.exinf;#if TA_GP	gp = devcb->ddev.gp;#endif	/* Is device driver call required? */	if ( chkopen(devcb, unitno)	  && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) openfn = NULL;	/* Get open management block */	opncb = newOpnCB(devcb, unitno, omode, rescb);	if ( opncb == NULL ) { err = E_LIMIT; goto err_ret2; }	UnlockDM();	if ( openfn != NULL ) {		/* Device driver call */#if TA_GP		err = CallDeviceDriver(DEVID(devcb, unitno), omode, exinf, 0,								openfn, gp);#else		err = (*openfn)(DEVID(devcb, unitno), omode, exinf);#endif		if ( err < E_OK ) goto err_ret3;	}	LockDM();	opncb->resid = tk_get_rid(TSK_SELF); /* Indicate that open processing is completed */	UnlockDM();	return DD(opncb);err_ret3:	LockDM();	delOpnCB(opncb, TRUE);err_ret2:	UnlockDM();err_ret1:	DEBUG_PRINT(("_tk_opn_dev err = %d\n", err));	return err;}/* * Abort all requests */LOCAL void abort_allrequest( OpnCB *opncb ){	ER	(*abortfn)( ID tskid, T_DEVREQ *devreq, INT nreq, VP exinf );	INT	(*waitfn)( T_DEVREQ *devreq, INT nreq, TMO tmout, VP exinf );	VP	exinf;#if TA_GP	VP	gp;#endif	DevCB	*devcb;	ReqCB	*reqcb;	QUEUE	*q;	/* If 'execfn' and 'waitfn' are called, execute abort request. */	LockDM();	devcb = opncb->devcb;	abortfn = (VP)devcb->ddev.abortfn;	waitfn  = (VP)devcb->ddev.waitfn;	exinf   = devcb->ddev.exinf;#if TA_GP	gp = devcb->ddev.gp;#endif	opncb->abort_tskid = tk_get_tid();	opncb->abort_cnt = 0;	if ( opncb->nwaireq > 0 ) {		/* Multiple requests wait */		reqcb = DEVREQ_REQCB(opncb->waireqlst);		/* Device driver call */#if TA_GP		CallDeviceDriver(reqcb->tskid, opncb->waireqlst,					opncb->nwaireq, exinf, abortfn, gp);#else		(*abortfn)(reqcb->tskid, opncb->waireqlst, opncb->nwaireq,								exinf);#endif		opncb->abort_cnt++;	} else {		/* Start request or single request wait */		for ( q = opncb->requestq.next; q != &opncb->requestq;							q = q->next ) {			reqcb = (ReqCB*)q;			if ( reqcb->tskid == 0 ) continue;			reqcb->req.abort = TRUE;			/* Device driver call */#if TA_GP			CallDeviceDriver(reqcb->tskid, &reqcb->req, 1, exinf,								abortfn, gp);#else			(*abortfn)(reqcb->tskid, &reqcb->req, 1, exinf);#endif			opncb->abort_cnt++;		}	}	UnlockDM();	if ( opncb->abort_cnt > 0 ) {		/* Wait for completion of abort request processing */		SyncWaitDM();	}	opncb->abort_tskid = 0;	/* Abort remaining requests and wait for completion */	LockDM();	while ( !isQueEmpty(&opncb->requestq) ) {		reqcb = (ReqCB*)opncb->requestq.next;		reqcb->req.abort = TRUE;		UnlockDM();		/* Device driver call */#if TA_GP		CallDeviceDriver(&reqcb->req, 1, TMO_FEVR, exinf, waitfn, gp);#else		(*waitfn)(&reqcb->req, 1, TMO_FEVR, exinf);#endif		LockDM();		/* Unregister completed request */		delReqCB(reqcb);	}	UnlockDM();}/* * Device close processing */LOCAL ER close_device( OpnCB *opncb, UINT option ){	ER	(*closefn)( ID devid, UINT option, VP exinf );	VP	exinf;#if TA_GP	VP	gp;#endif	ID	devid;	DevCB	*devcb;	INT	unitno;	ER	err, error = E_OK;	/* Abort all requests during processing */	abort_allrequest(opncb);	LockDM();	devcb  = opncb->devcb;	unitno = opncb->unitno;	closefn = (VP)devcb->ddev.closefn;	exinf = devcb->ddev.exinf;#if TA_GP	gp = devcb->ddev.gp;#endif	devid = DEVID(devcb, unitno);	/* Free open management block */	delOpnCB(opncb, FALSE);	/* Is device driver call required? */	if ( chkopen(devcb, unitno) ) {		option &= ~TD_EJECT;		if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) closefn = NULL;	}	UnlockDM();	if ( closefn != NULL ) {		/* Device driver call */#if TA_GP		err = CallDeviceDriver(devid, option, exinf, 0, closefn, gp);#else		err = (*closefn)(devid, option, exinf);#endif		if ( err < E_OK ) error = err;	}	LockDM();	/* Return open management block to FreeQue */	QueInsert(&opncb->q, &FreeOpnCB);	UnlockDM();#ifdef DEBUG	if ( error < E_OK ) DEBUG_PRINT(("close_device err = %d\n", error));#endif	return error;}/* * Device close */EXPORT ER _tk_cls_dev( ID dd, UINT option ){	OpnCB	*opncb;	ER	err, error = E_OK;	LockDM();	err = check_devdesc(dd, 0, &opncb);	if ( err < E_OK ) { error = err; UnlockDM(); goto err_ret; }	opncb->resid = 0; /* Indicate that it is during close processing */	UnlockDM();	/* Device close processing */	err = close_device(opncb, option);	if ( err < E_OK ) error = err;err_ret:#ifdef DEBUG	if ( error < E_OK ) DEBUG_PRINT(("_tk_cls_dev err = %d\n", error));#endif	return error;}/* ------------------------------------------------------------------------ *//* * Check break request */LOCAL ER check_break( void ){	T_RTEX	rtex;	ER	err;	err = tk_ref_tex(TSK_SELF, &rtex);	if ( err < E_OK ) goto err_ret;	return ( rtex.pendtex != 0 )? E_ABORT: E_OK;err_ret:	DEBUG_PRINT(("check_break err = %d\n", err));	return err;}/* * Request for starting input/output to device */LOCAL ID request( ID dd, INT start, VP buf, INT size, TMO tmout, INT cmd ){	ER	(*execfn)( T_DEVREQ *devreq, TMO tmout, VP exinf );	VP	exinf;#if TA_GP	VP	gp;#endif	OpnCB	*opncb;	DevCB	*devcb;	ReqCB	*reqcb;	UINT	m;	ER	err;	LockDM();	/* Check whether there is a break request */	err = check_break();	if ( err < E_OK ) goto err_ret1;	if ( start <= -0x00010000 && start >= -0x7fffffff ) {		m = 0; /* Ignore open mode */	} else {		m = ( cmd == TDC_READ )? TD_READ: TD_WRITE;	}	err = check_devdesc(dd, m, &opncb);	if ( err < E_OK ) goto err_ret1;	devcb = opncb->devcb;	execfn = (VP)devcb->ddev.execfn;	exinf = devcb->ddev.exinf;#if TA_GP	gp = devcb->ddev.gp;#endif	/* Get request management block */	reqcb = newReqCB(opncb);	if ( reqcb == NULL ) { err = E_LIMIT; goto err_ret1; }	/* Set request packet */	reqcb->req.next   = NULL;	reqcb->req.exinf  = NULL;	reqcb->req.devid  = DEVID(devcb, opncb->unitno);	reqcb->req.cmd    = cmd;	reqcb->req.abort  = FALSE;	reqcb->req.nolock = ( (opncb->omode & TD_NOLOCK) != 0 )? TRUE: FALSE;	reqcb->req.rsv    = 0;	reqcb->req.start  = start;	reqcb->req.size   = size;	reqcb->req.buf    = buf;	reqcb->req.asize  = 0;	reqcb->req.error  = 0;	err = tk_get_tsp(TSK_SELF, &reqcb->req.tskspc);	if ( err < E_OK ) goto err_ret2;	/* Indicate that it is during processing */	reqcb->tskid = tk_get_tid();	UnlockDM();	/* Device driver call */#if TA_GP	err = CallDeviceDriver(&reqcb->req, tmout, exinf, 0, execfn, gp);#else	err = (*execfn)(&reqcb->req, tmout, exinf);#endif	LockDM();	/* Indicate that it is not during processing */	reqcb->tskid = 0;	/* If there is an abort completion wait task,	   notify abort completion */	if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) {		SyncSignalDM(opncb->abort_tskid);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -